搜索
bottom↓
回复: 30

关于普通IO实现单线单工通信的编程思路

[复制链接]

出0入0汤圆

发表于 2014-5-28 13:53:02 | 显示全部楼层 |阅读模式
本帖最后由 lmt50211 于 2014-5-28 13:56 编辑

这个是匠人手记里的一节,因为对发送部分没有编程思路,现发贴希望各位提出一些各自的见解,还望各位赐教。。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2014-5-28 14:26:18 | 显示全部楼层
可以参考温度传感器18B20的方式哦

出0入0汤圆

发表于 2014-5-28 14:33:52 | 显示全部楼层
参考红外的波形图,然后用定时器做。主机定时发送,从机不停扫描IO口。

出0入0汤圆

发表于 2014-5-28 20:45:35 | 显示全部楼层
将数据转换成PWM

出0入0汤圆

发表于 2014-5-28 20:55:47 | 显示全部楼层
原来用海尔的单片机搞了一个,但因为使用内部晶振,温度变化就有影响,但有看到做倒车雷达的,用风枪把锡吹熔了接收也正常,目前还没有找到办法。

出0入0汤圆

发表于 2014-5-28 23:14:36 | 显示全部楼层
使用曼彻斯特编码可以解决同步问题

出0入0汤圆

发表于 2014-5-28 23:24:05 | 显示全部楼层
LS的方案很好呀!

出0入0汤圆

 楼主| 发表于 2014-5-29 08:51:33 | 显示全部楼层
kingway00 发表于 2014-5-28 14:26
可以参考温度传感器18B20的方式哦

也考虑过用这种方式,但看很多人的程序都是使用延时函数来做的,这样的话通用性就会比较差。

出0入0汤圆

 楼主| 发表于 2014-5-29 08:51:55 | 显示全部楼层
skyxjh 发表于 2014-5-28 23:14
使用曼彻斯特编码可以解决同步问题

可以详细说说吗?

出0入0汤圆

 楼主| 发表于 2014-5-29 08:52:48 | 显示全部楼层
rf_smart 发表于 2014-5-28 20:55
原来用海尔的单片机搞了一个,但因为使用内部晶振,温度变化就有影响,但有看到做倒车雷达的,用风枪把锡吹 ...

这个可以贴出来吗,大家可以讨论讨论。。。

出0入0汤圆

 楼主| 发表于 2014-5-29 08:54:23 | 显示全部楼层
jinbangzhou 发表于 2014-5-28 14:33
参考红外的波形图,然后用定时器做。主机定时发送,从机不停扫描IO口。 ...


目前主要是如何发出波形的发送程序没有编写思路,接收部分问题倒不大。以前有写过类似的

出0入0汤圆

发表于 2014-5-29 09:00:56 | 显示全部楼层
lmt50211 发表于 2014-5-29 08:54
目前主要是如何发出波形的发送程序没有编写思路,接收部分问题倒不大。以前有写过类似的
...

程序就不贴了写得比较乱,其实难的还是在接收,发送用延时,定时器什么的发就是了。
原来想过一种方法可以避免晶振误差的影响,即发送一个较长的脉冲做为同步,接收方用定时器
数这个脉宽,传输数据的脉宽为长脉宽的1/n,这样可能会解决一些温度的影响,但这样的
通信速率可能就慢了。如果IO有上下沿中断那就好办了,不过想用定时器+任意IO实现,
还是不简单。

出0入0汤圆

发表于 2014-5-29 10:54:57 | 显示全部楼层
SIGNAL(TIMER0_OVF_vect)
{
   

   
       
        if (single_wire.transmit_status == SINGLE_WIRE_MODULE_RECEIVE)
        {          
       TCNT0  = 0xD1; //set count
      
           single_wire.pin_value = SINGLE_WIRE_PIN_READ();
          
           if (!single_wire.pin_value)
           {
              // 计算脉冲宽度低电平时间
                  single_wire.pluse_coun ++;       
                  
           }
           else
           {             
                  switch (single_wire.code_status)
              {
              case SINGLE_WIRE_CODE_IDLE_PULSE:
                             // 接收起始码
                                                  
                       if ((single_wire.pluse_coun >= 20)&&(single_wire.pluse_coun < 40))
                             {                                                   
                              single_wire.bit_coun = 0;
                      single_wire.byte_coun = 0;                                                                                       
                                  // 转为接收数据状态
                                  single_wire.code_status = SINGLE_WIRE_CODE_DATA;
                                  
                       }
                                           
                   break;
                                                                               
              case SINGLE_WIRE_CODE_DATA    :
                             // 接收数据          
                   // 根据数据来确定数据长度
                           // 计算低电平时间算数据为 1 还是 0
                                                     
                           if ((single_wire.pluse_coun >= 6)&&(single_wire.pluse_coun < 12))
                           {
                              single_wire.buff[single_wire.byte_coun] |= pgm_read_byte(&bit_code[single_wire.bit_coun]);                                                                              
                              single_wire.bit_coun++;
                           }                                                                                 
                           else if ((single_wire.pluse_coun >= 3)&&(single_wire.pluse_coun < 6))
                           {
                              single_wire.buff[single_wire.byte_coun] &= ~pgm_read_byte(&bit_code[single_wire.bit_coun]);                  
                                  single_wire.bit_coun++;
                           }                                                                                 
                             // 接收满 8 比特,接收下一个字节
                           if (single_wire.bit_coun >= 8)            
                   {
                          single_wire.bit_coun = 0;
                                  // 字节数自动累加
                              single_wire.byte_coun ++;
                               
                              if (single_wire.byte_coun >= SINGLE_RECEIVE_MAX)
                              {                               
                                     single_wire.byte_coun = 0;       
                                         single_wire.bit_coun = 0;
                                         
                                         single_wire.transmit_status = SINGLE_WIRE_MODULE_RECEIVE_OK;

                                         
                              }
                       }
                       break;       
                                                                                                                                                                                                                                                                                     
              }
                  
                  single_wire.pluse_coun = 0;
           }
          
        }
       
        else if (single_wire.transmit_status == SINGLE_WIRE_MODULE_SEND)
        {          

       TCNT0  = 0xCE; //set count
           // 发送脉冲时间计数
           single_wire.pluse_coun++;
          
           switch (single_wire.code_status)
           {
          
           case SINGLE_WIRE_CODE_IDLE_PULSE: // 发送起始码
                if (single_wire.pluse_coun <= 20)
                    {
                       SINGLE_WIRE_SEND_LOW();// 发送高
                    }
                    else if (single_wire.pluse_coun <= 40)
                    {                     
                           SINGLE_WIRE_SEND_HIGH(); // 发送低
                        }
                        else
                        {
                           single_wire.pluse_coun = 0;
                           single_wire.code_status = SINGLE_WIRE_CODE_DATA;                                                                       
                    }
                break;
           case SINGLE_WIRE_CODE_DATA: // 发送数据
          
                // 根据数据来确定数据长度
                    
                    if (single_wire.buff[single_wire.byte_coun]
                                &pgm_read_byte(&bit_code[single_wire.bit_coun]))                  
                {                   
                   single_wire.data_width = 12;
                }
                else
                {
                   single_wire.data_width = 6;
                }
                                                         
                // 脉冲一半时间发低电平
                if (single_wire.pluse_coun <= single_wire.data_width/2)
                {
                   SINGLE_WIRE_SEND_LOW();//
                }
                    // 脉冲一半时间发高电平
                else if (single_wire.pluse_coun <= single_wire.data_width)
                {                
                           SINGLE_WIRE_SEND_HIGH(); //                                                
                        }
                        else
                        {
                           // 脉冲计数时间与设定时间相等时
                           // 发送下一位数据
                           single_wire.pluse_coun = 0;                  
                           single_wire.bit_coun++;
                           // 发送满 8 比特则发送下一个字节
               if (single_wire.bit_coun >= 8)
                   {
                      single_wire.bit_coun = 0;
                      single_wire.byte_coun++;
                      // 发送总字节数
                      if (single_wire.byte_coun >= SINGLE_TRANSMIT_MAX)
                      {                                                                                                                                     
                     //single_wire.transmit_status = SINGLE_WIRE_MODULE_SEND_OK;                
                     TCCR0A = 0x00; //; //start Timer
                     single_wire_init(SINGLE_WIRE_CODE_IDLE_PULSE,SINGLE_WIRE_MODULE_RECEIVE);
                     TCCR0A = 0x02; //; //start Timer
                      }
                           }                                                   
                        }   
                break;           
                                                                                                                                                                                                                                         
           }          
        }
       
       
}

出0入0汤圆

发表于 2014-5-29 10:55:51 | 显示全部楼层
这个我已经做的挺稳定的了

出0入0汤圆

 楼主| 发表于 2014-5-29 11:05:52 | 显示全部楼层
jinbangzhou 发表于 2014-5-29 10:54
SIGNAL(TIMER0_OVF_vect)
{
   

非常感谢。。。。

出0入0汤圆

发表于 2014-5-29 11:26:46 来自手机 | 显示全部楼层
重载putchar,用io实现串口发送

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-29 13:03:23 | 显示全部楼层
lmt50211 发表于 2014-5-29 08:51
可以详细说说吗?

你搜一下“曼彻斯特编码”就有了,曼码每一位中间都有一个跳变沿,作为同步时钟,也作为数据,上长沿表示“0”,下降沿表示“1”,这样一来两个相邻的跳变之间的时间间隔就只能是0.5T或1T(T表示一位码长时间),可以用1.5T以上的间隔时间作为字同步。可以参考4100RF卡的编码方式。

出0入0汤圆

发表于 2014-5-29 13:08:53 | 显示全部楼层
围观学习中。。。

出0入0汤圆

发表于 2014-5-29 13:50:30 来自手机 | 显示全部楼层
顺便问这种方式硬件如何做到几千米的距离?

出0入0汤圆

 楼主| 发表于 2014-5-29 14:55:07 | 显示全部楼层
zyw19987 发表于 2014-5-29 13:50
顺便问这种方式硬件如何做到几千米的距离?

这个暂时就不知道了,我这个应用在只有几米的产品上。

出0入0汤圆

 楼主| 发表于 2014-5-29 15:25:47 | 显示全部楼层
本帖最后由 lmt50211 于 2014-5-29 15:30 编辑

根据“jinbangzhou” 提供的代码,调整后可以实现通信,但通信的质量还需要进一步测试。
现附上相应代码,请各位提点。。

1)  发送部分  MCU   HT   BS84B08-3    内部16M   定时器: 250us中断一次(2K无源蜂鸣器)
#define p_data_out           _pa1    //通信口
#define temp_send_byte   4         //4字节数据,后2字节为前2字节的反码
bit b_send_ok;      //发送数据完成标志位
unsigned char r_send_cnt; //发送时基
unsigned char r_send_cnts;//Bit0,Bit1计数
unsigned char r_send_mode;//发送数据状态
unsigned char r_send_data[temp_send_byte];//发送数据缓存器
unsigned char r_send_num; //发送数据位数
unsigned char r_send_byte;//发送数据字节数
//====================================================================
//===          测试函数              ===//
void test_process(void)
{
        bit b_send_ok = 0;   //清发送完成标志位
        r_send_data[0] = 0x04;
        r_send_data[1] = 0xf0;
        r_send_data[2] = 0xfb;
        r_send_data[3] = 0x0f;
}
//====================================================================
//===          中断服务函数          ===//
#pragma vector  Interrupt_Extemal        @ 0x0c
void Interrupt_Extemal()
{
//======================================//       
        r_t2500us ++;
        if(r_t2500us >= 10)
        {
                r_t2500us = 0;
                b_t2500us = 1;
                r_t100ms ++;       
                if(r_t100ms >= 40)
                {
                        r_t100ms = 0;
                        b_t100ms = 1;
                }
                r_t500ms ++;
                if(r_t500ms >= 200)
                {
                        r_t500ms = 0;
                        b_t500ms = 1;       
                }
        }
//======================================//
        if(b_send_ok == 0)//发送请求
        {
                r_send_cnt++;
            switch(r_send_mode)
            {
                case 0:
                    if(r_send_cnt <= 80)
                    {
                        p_data_out = 1;   
                    }   
                    else if(r_send_cnt <= 160)//发送起始码
                    {
                        p_data_out = 0;   
                    }
                    else
                    {
                        r_send_cnt = 0;
                        r_send_mode = 1;//进入发送数据码
                    }
                    break;
                case 1:
                    if(r_send_data[r_send_byte] & (1 << r_send_num))
                    {
                        r_send_cnts = 20;      
                    }
                    else
                    {
                        r_send_cnts = 10;   
                    }
                    if(r_send_cnt <= (r_send_cnts / 2))// 脉冲一半时间发低电平
                    {
                        p_data_out = 0;   
                    }
                    else if(r_send_cnt <= r_send_cnts)// 脉冲一半时间发高电平
                    {
                        p_data_out = 1;
                    }
                    else
                    {
                        r_send_cnt = 0;
                        r_send_num ++;
                        if(r_send_num >= 8)//发送完8位
                        {
                            r_send_num = 0;
                            r_send_byte++;
                            if(r_send_byte >= temp_send_byte)//发送多字节
                            {
                                r_send_byte = 0;
                                r_send_mode = 2;//进入结束码
                            }   
                        }   
                    }
                    break;
                case 2://结束码
                    if(r_send_cnt <= 20)
                    {
                        p_data_out = 0;   
                    }
                    else if(r_send_cnt <= 40)
                    {
                        p_data_out = 1;
                    }
                    else
                    {
                        p_data_out = 0;
                        r_send_cnt = 0;
                        b_send_ok = 1;//发送完成  
                        r_send_mode = 0;//恢复到头码状态  
                    }
                    break;
                default:
                    break;
            }
        }
}
波形图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-5-29 15:36:32 | 显示全部楼层
2)接收部分   MCU:SONIX   SN8P2511  16M内部RC   定时器:125us中断一次
#define p_data_in             FP00      //数据接口
#define temp_read_byte   4           //接收数据字节数
unsigned char r_flag0;
sbit b_read_ok       = r_flag0:6;//接收完成标志位
unsigned char r_read_cnt; //接收时基
unsigned char r_read_mode;//接收状态
unsigned char r_read_data[temp_read_byte];//接收数据缓存器
unsigned char r_read_num; //接收数据位数
unsigned char r_read_byte;//接收数据字节数
//====================================================================
//===          测试函数              ===//
void test_process(void)
{
        if(b_read_ok == 1)
        {
                b_read_ok = 0;
                if(r_read_data[0] == (0xff - r_read_data[2]))
                {
                        r_buzz_cnt = r_read_data[0];
                        r_read_data[0] = 0;
                }
                        if(r_read_data[1] == (0xff - r_read_data[3]))
                {
                        r_read_data[1] = 0;
                }
        }
}
//====================================================================
//===          中断服务函数          ===//
void __interrupt[0x08] t0_overview (void) //T0->125us
{
        if(FT0IRQ)
        {
                FT0IRQ = 0;

                T0C = 131;//T0计数寄存器

                r_t1000us++;
                if(r_t1000us >= 8)
                {
                        r_t1000us = 0;
                        b_t1000us = 1;
                        r_t100ms++;
                        if(r_t100ms >= 100)
                        {
                                r_t100ms = 0;
                                b_t100ms = 1;
                                r_t500ms++;
                                if(r_t500ms >= 5 * 4)
                                {
                                        r_t500ms = 0;
                                        b_t500ms = 1;
                                }
                        }
                }
//======================================//
                if(p_data_in == 1)   //计算高电平时间
            {
                    r_read_cnt ++;             
            }
            else
            {       
                        switch(r_read_mode)
                {
                    case 0://头码
                        if((r_read_cnt >= 80) && (r_read_cnt <= 160))
                        {
                                                r_read_num = 0;
                            r_read_byte = 0;
                            r_read_mode = 1;//
                        }
                        break;
                    case 1://数据码
                                        if((r_read_cnt >= 15) && (r_read_cnt <= 40))
                        {
                            r_read_data[r_read_byte] >>= 1;
                                                r_read_data[r_read_byte] |= 0x80;
                            r_read_num++;
                        }
                        else if((r_read_cnt >= 3) && (r_read_cnt < 15))
                        {
                            r_read_data[r_read_byte] >>= 1;
                                                r_read_data[r_read_byte] &= 0x7f;  
                                                r_read_num++;
                        }
                        if(r_read_num >= 8)
                        {
                            r_read_num = 0;
                            r_read_byte++;
                            if(r_read_byte >= temp_read_byte)
                            {
                                r_read_byte = 0;
                                r_read_num = 0;
                                r_read_mode = 2;
                            }   
                        }
                        break;
                    case 2://结束码
                        if((r_read_cnt >= 20) && (r_read_cnt <= 80))
                        {
                            b_read_ok = 1;
                            r_read_mode = 0;
                        }
                        break;
                    default:
                        break;
                }
                        r_read_cnt = 0;      
            }       
        }       
}

出0入0汤圆

发表于 2015-10-1 15:56:43 | 显示全部楼层
mark一下,普通IO实现单线单工通信

出0入0汤圆

发表于 2015-10-21 00:09:49 | 显示全部楼层
早三年见到这个就好了.

出0入0汤圆

 楼主| 发表于 2015-10-21 08:01:05 | 显示全部楼层
ZJetWay 发表于 2015-10-21 00:09
早三年见到这个就好了.

现在知道也不会太迟,可以总结一下

出0入0汤圆

发表于 2015-10-21 08:29:14 | 显示全部楼层
主要是板间通过一线制通信会受电机,大电流的影响,这个怎么解决呢?

出0入0汤圆

发表于 2015-10-21 08:47:11 | 显示全部楼层
很多按摩器手控器都是一线通信的

出20入62汤圆

发表于 2015-10-21 08:58:53 | 显示全部楼层
类似的有sony dv机的lanc协议,你搜下

出0入8汤圆

发表于 2015-10-21 09:24:54 | 显示全部楼层
用过的18b20和am2301都是单线通讯

出0入0汤圆

发表于 2015-10-21 09:31:46 | 显示全部楼层
红外接收头信号也是单总线吧
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-5 19:32

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表