搜索
bottom↓
回复: 31

51单片机串口接收不定长数据

[复制链接]

出0入0汤圆

发表于 2015-12-15 20:31:15 | 显示全部楼层 |阅读模式
请教大神,单片机串口如何接收不定长数据啊 ,比如 0x01+0x03+len+data0....datan CRC_H  CRC_L 写了一下午没啥成果

出0入0汤圆

发表于 2015-12-15 20:33:58 | 显示全部楼层
本帖最后由 xpstudio2011 于 2015-12-15 20:35 编辑

去看下DIY版的3D打印机固件里的串口通讯程序。相当好的。
Marlin  或者 较早的Sprinter 都是用一差不多的程序。
包括了CRC校验之类的操作。

出0入8汤圆

发表于 2015-12-15 20:38:23 | 显示全部楼层
下位机这边一字节一字节的接收,判断起始字节是不是0x01和0x03,是的话就接着判断,不是的话就把数据扔了重新判断

如果上一步判断接收到的事起始字节,那么第三字节就是数据长度n,然后接下来接收n字节的数据字节,之后接收的两字节是校验字节,如果校验没有问题则数据有效,如果校验有问题则数据丢掉

一堆if else 或者case

出0入10汤圆

发表于 2015-12-15 20:51:35 | 显示全部楼层
2种方法,1实时地进行if else 2 fifo缓冲区接收 main中进行测量,这种实时性稍微差些,但是用着也不错。

出0入0汤圆

发表于 2015-12-15 20:53:37 | 显示全部楼层
这不是modbus吗?用时间间隔来区分帧的

出0入0汤圆

 楼主| 发表于 2015-12-15 20:54:51 | 显示全部楼层
myin4 发表于 2015-12-15 20:53
这不是modbus吗?用时间间隔来区分帧的

第一次搞 能不能给源码分析一下?

出0入0汤圆

 楼主| 发表于 2015-12-15 20:56:44 | 显示全部楼层
prow 发表于 2015-12-15 20:38
下位机这边一字节一字节的接收,判断起始字节是不是0x01和0x03,是的话就接着判断,不是的话就把数据扔了重 ...

我就是用else if 写的  不好用

出0入0汤圆

发表于 2015-12-15 21:01:25 | 显示全部楼层
xpstudio2011 发表于 2015-12-15 20:33
去看下DIY版的3D打印机固件里的串口通讯程序。相当好的。
Marlin  或者 较早的Sprinter 都是用一差不多的程 ...

打印机的没有看到,有没有链接,嘿嘿

出0入0汤圆

发表于 2015-12-15 21:02:30 | 显示全部楼层
上网一搜modbus就出来了呀,
多用个定时器,串口接收中断里面开定时器,T35之后就是一帧了

出0入0汤圆

发表于 2015-12-15 21:14:43 | 显示全部楼层
随便帮写了段,仅供参考!!!

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2015-12-15 21:24:04 | 显示全部楼层
接收状态机变量step初始化为0

出0入0汤圆

 楼主| 发表于 2015-12-15 21:34:51 | 显示全部楼层
浮生莫若闲 发表于 2015-12-15 21:24
接收状态机变量step初始化为0

我字节写了一个  感觉串口反应缓慢  点串口调试助手的发送点好几下才能收到一帧数据   请问大神这事什么问题

出0入0汤圆

发表于 2015-12-15 21:48:19 | 显示全部楼层
1328616904 发表于 2015-12-15 21:34
我字节写了一个  感觉串口反应缓慢  点串口调试助手的发送点好几下才能收到一帧数据   请问大神这事什么 ...

我不是什么大神哦,想查问题,就上你的代码,不然我只能掐指头算。我要能掐指算的话,早就买彩票去咯

出60入0汤圆

发表于 2015-12-15 21:59:12 | 显示全部楼层
建立缓冲区接收数据, main中进行帧判断. 这样容易移植

出20入0汤圆

发表于 2015-12-15 22:36:26 | 显示全部楼层
   用缓冲区接受,超时从缓冲区取数据判断,这样做通用性很强。

出0入0汤圆

发表于 2015-12-15 22:40:14 | 显示全部楼层
talkingbeast 发表于 2015-12-15 22:36
用缓冲区接受,超时从缓冲区取数据判断,这样做通用性很强。


  超时从缓冲区取数据判断这个怎么理解? 还请指点

出0入0汤圆

 楼主| 发表于 2015-12-16 08:18:57 | 显示全部楼层
浮生莫若闲 发表于 2015-12-15 21:48
我不是什么大神哦,想查问题,就上你的代码,不然我只能掐指头算。我要能掐指算的话,早就买彩票去咯 ...
  1. void  UART2_IRQHandler (void)
  2. {
  3.     static unsigned char count;
  4.    UART_MemMapPtr uartPtr = UART2_BASE_PTR;                             /* ·¢ËÍÖжϴ¦Àí³ÌÐò             */
  5.    #if UART2_SEND_IRQ                                                   /* Óû§¶¨Òå                     */
  6.    #endif
  7.    
  8.    #if UART2_RECEIVE_IRQ
  9.   if (UART_S1_REG(uartPtr) & UART_S1_RDRF_MASK)
  10.    {                    /* Çå³ýÖжϱêÖ¾                 */
  11.       
  12.      // uart0SendChar ( UART_D_REG(uartPtr));  
  13.      tab[count] = UART_D_REG (uartPtr );
  14.      if(tab[count] == 0x01 && count == 0x00)
  15.      {
  16.         count = 1;
  17.      }
  18.      else if(tab[count] == 0x03 && count == 1)
  19.      {
  20.         count = 2;
  21.      }
  22.    
  23.      else if(count >= 2 && count < 8)
  24.      {
  25.         count ++;
  26.      }
  27.      else if(count == 8)
  28.      {
  29.         count = 0;
  30. //        for(i=0;i<8;i++)
  31. //         {
  32. //            uart0SendChar (tab[i]);
  33. //         }
  34.          //printf("size=%d\n",sizeof(tab));
  35.         //datalen = 0x00;   
  36.          uart0SendChar (crc16(tab,7)>>8);
  37.          uart0SendChar (crc16(tab,7)&0xff);
  38.          
  39.          
  40.      }
  41.      else
  42.      {
  43.          count = 0;
  44.          //datalen = 0;
  45.      }
  46.       
  47.    }   
  48.    #endif   
  49. }
复制代码

出20入0汤圆

发表于 2015-12-16 09:35:46 | 显示全部楼层
vjcmain 发表于 2015-12-15 22:40
超时从缓冲区取数据判断这个怎么理解? 还请指点

  1.接收数据存放在缓冲区中;当接收字节超时发生时,调用数据处理函数;
  2.数据处理:从缓冲区中获取接收到的数据流,判断是否符合modbus协议或者自定义协议格式,然后判断;
这样的架构可以处理多种协议格式,比如没有包头包尾结构的modbus协议;或者有包头包尾的协议;接收数据长度固定和可变都可以处理,通用性很好。

出0入0汤圆

发表于 2015-12-21 09:14:36 | 显示全部楼层
就是判断相邻两个数据之间的间隔。比如超过10ms就判定接收完成一帧数据。

出0入0汤圆

 楼主| 发表于 2015-12-22 14:03:29 | 显示全部楼层
miaoguoqiang 发表于 2015-12-21 09:14
就是判断相邻两个数据之间的间隔。比如超过10ms就判定接收完成一帧数据。

谢谢,我解决了  我延时20毫秒  

出0入0汤圆

发表于 2015-12-22 14:14:51 | 显示全部楼层
遵循 学习 下  标准 modbus 就会明白了

出0入0汤圆

发表于 2015-12-22 14:20:49 | 显示全部楼层
1328616904 发表于 2015-12-22 14:03
谢谢,我解决了  我延时20毫秒

楼主是怎么解决的,20毫秒是在哪里调的啊?

出0入0汤圆

发表于 2015-12-23 08:30:28 | 显示全部楼层
modbus的程序网上有很多,下载一个看看就懂了

出0入0汤圆

 楼主| 发表于 2015-12-23 10:17:14 | 显示全部楼层
河图洛书 发表于 2015-12-22 14:20
楼主是怎么解决的,20毫秒是在哪里调的啊?

在发送度寄存器命令之后就开始延时,20ms足够从机返回数据了,20ms内读到就读到了 读不到也执行下面的程序,这样也能防止死机,不知道这样是否妥当

出0入84汤圆

发表于 2015-12-23 12:03:34 | 显示全部楼层
间隔20ms那是超时处理,这个显然是modbus协议,只要在读取字长字节时改变整个命令的长度就可以了,光处理超时显然不行

出0入0汤圆

 楼主| 发表于 2015-12-23 13:41:21 | 显示全部楼层
czzhouyun 发表于 2015-12-23 12:03
间隔20ms那是超时处理,这个显然是modbus协议,只要在读取字长字节时改变整个命令的长度就可以了,光处理超 ...

对,我根据需要接受命令的长度,控制串口的接收计数器和延时处理,这样既能保证数据的准确性又可以方式死机

出0入0汤圆

发表于 2015-12-23 13:57:30 | 显示全部楼层
设置定时器,串口接收中断重置定时器,定时器溢出中断设置标志位,判断标志位,处理

出5入10汤圆

发表于 2015-12-23 14:05:58 | 显示全部楼层
楼主可以把这个程序发上来学习下吗?

出0入0汤圆

 楼主| 发表于 2015-12-23 17:17:40 | 显示全部楼层
mailyyg@163.com 发表于 2015-12-23 13:57
设置定时器,串口接收中断重置定时器,定时器溢出中断设置标志位,判断标志位,处理 ...

差不多吧

出0入0汤圆

发表于 2018-1-22 17:54:28 | 显示全部楼层
最近也在写串口不定长接收,学习了。谢谢楼主

出0入0汤圆

发表于 2018-3-9 14:48:42 | 显示全部楼层
void ComInINT(void) interrupt 4 //using 1  //串口接收-中断函数
{   
        uchar xdata comm_dat[65];  //串口接收
        uchar dat,i;
       
    if(RI)
    {
        RI=0;
        dat=SBUF;
                                switch (step)
                                {
                                        case 1:
                                        {
                                                Count=0;
                                                if(dat=='/')step=2;
                                                else step=1;
                                        }
                                        break;

                                        case 2:
                                        {
                                                comm_dat[Count]=dat;
                                                if(comm_dat[Count]==0x0d)step=3;
                                                else step=2; Count++;                                         
                                                if(Count>64){Count=0;step=2;}
                                        }
                                        break;
                                        case 3:
                                        {                                                                               
                                                    for(i=0;i<Count;i++)chs[i]=comm_dat[i];
                                                    for(i=0;i<64;i++)comm_dat[i]=0;
                                                read_flag=1; step=0; dat=0;
                                        }
                                        break;
                                       
                                        default:{}break;
                                }                                                               
    }
    if(TI)
                        {TI = 0;busy = 0;}
}

出0入0汤圆

发表于 2018-8-6 15:36:05 | 显示全部楼层
hongguan 发表于 2018-3-9 14:48
void ComInINT(void) interrupt 4 //using 1  //串口接收-中断函数
{   
        uchar xdata comm_dat[65];  //串 ...

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

本版积分规则

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

GMT+8, 2024-4-19 14:57

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

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