关于串口接收问题

[复制链接]
3689|15
 楼主| dai_22 发表于 2010-5-12 11:50 | 显示全部楼层 |阅读模式
本帖最后由 dai_22 于 2010-5-12 12:05 编辑

当上位机以下面格式发送数据给下位机,下位机接收程序该怎样写才不会出现死循环?


报头

长度

逻辑地址

命令

参数内容

校验

结束符

1Byte

1Byte

1Byte

1Byte

nByte

1Byte

1Byte

固定0x40

逻辑地址开始到结束符的字节总数。

硬件4Bit拨码开关设置或由通讯设置。

参考命令列表

参考命令列表的详细数据内容

从报头开始到校验前的所有字节异或。

固定

0x0D



  1. 这是我的程序,使用了串口中断接收。
  2. //***************************
  3. //串行中断,接收上位机数据
  4. //***************************
  5. seri_int () interrupt 4 using 1
  6. {
  7.    unsigned char i, j;
  8.    unsigned char rece_data = SBUF;//接收串口数据
  9.    unsigned char verify = 0;//保存校验码
  10.    if (RI)
  11.    {   
  12.        RI = 0;
  13.        if (g_bReceBe)
  14.       {
  15.           i = g_cReceNum++;
  16.          g_cReceBuf[i] = rece_data;
  17.      }
  18.      else
  19.      {   
  20.         if((g_cReceNum==0) && (rece_data==0x40))//接收协议头
  21.         {
  22.              g_bReceBe = 1;
  23.              i = g_cReceNum++;
  24.              g_cReceBuf[i] = rece_data;
  25.         }
  26.     }
  27.     if ((g_cReceNum == g_cReceBuf[1] + 2) && ( g_cReceBuf[1]!= 0 )) //判断数据是否接收完
  28.        {   
  29.             for (j=0; j<g_cReceNum-1; j++)//校验验证码
  30.             {   verify ^= g_cReceBuf[j];    }
  31.             if (!verify)
  32.            {   
  33.                 g_bReceOk  = 1;
  34.                 g_cCommand = g_cReceBuf[3];
  35.                 ES = 0;
  36.             }
  37.             g_bReceBe  = 0;
  38.             g_cReceNum = 0;
  39.         }
  40.         if (g_cReceNum >= 24)//最长一条协议为23字节
  41.         {
  42.             g_cReceNum = 0;  
  43.             g_bReceBe  = 0;
  44.         }
  45.     }
  46.     else if(TI)
  47.     { TI = 0;   }




ejack 发表于 2010-5-12 12:31 | 显示全部楼层
围绕着g_cReceNum的错误不少,LZ还需要慢慢修改。
另外LZ还需要考虑健壮性问题,比如说一帧中间丢了1个字节怎么处理……等等
 楼主| dai_22 发表于 2010-5-12 12:56 | 显示全部楼层
本帖最后由 dai_22 于 2010-5-12 12:57 编辑

LS
谢谢前辈指点,晚辈悟性低,不知g_cReceNum中的错误在哪里?
mohanwei 发表于 2010-5-12 14:31 | 显示全部楼层
报头0x40和包尾0x0d在报文中会出现么?是否有转义?有转义的话,检测到包尾0x0d即可认为接收结束,再加上缓冲区溢出检测,可以认为是非常健壮的了。

如果没有转义,那就只能用状态机来接收了,需要很多的容错处理,做起来很麻烦。
 楼主| dai_22 发表于 2010-5-12 14:38 | 显示全部楼层
4# mohanwei
0x40和0x0d都会出现,但是没有转义。
teddeng 发表于 2010-5-12 15:46 | 显示全部楼层
不是复杂应用,原来没成功弄过多机通讯建议参考MODBUS,两种方式都简单实用。
ejack 发表于 2010-5-12 18:54 | 显示全部楼层
LZ的协议是变长的,若以目前程序无时序辅助的机制,一旦丢失字节将会影响后续帧。最恶劣情况下连续破坏4帧的接收。
ejack 发表于 2010-5-12 18:58 | 显示全部楼层
校验是否包括该字节本身?
928315 发表于 2010-5-12 21:20 | 显示全部楼层
楼主,一个字节的包头,感觉有点少。推荐一种状态机的写法
#pragma vector=USART0RX_VECTOR
__interrupt void Uart0_Rx (void)
{  
    INT8U i;
    i = RXBUF0;
       
        switch(uart0_rx_state)
        {
        case 0:
                if(i == 0xff)
                        uart0_rx_state++;
                else
                        uart0_rx_state = 0;
                break;
        case 1:
                if(i == 0x00)
                        uart0_rx_state++;
                else
                        uart0_rx_state = 0;
                break;
        case 2:
                if(i == 0x66)
                        uart0_rx_state++;
                else
                        uart0_rx_state = 0;
                break;
        case 3:
                if(i == 0x55)
                        uart0_rx_state++;
                else
                        uart0_rx_state = 0;
                break;
        case 4://SN
                uart0_rx_state++;
                break;
        case 5://SN
                uart0_rx_state++;
                break;
        case 6://SN
                uart0_rx_state++;
                break;
        case 7://SN
                uart0_rx_state++;
                break;
        case 8://CRC
                uart0_rx_state++;
                recDataNum = 0;//初始化计数
                break;
        case 9://数据
                Proc_Data(i);
                break;
        default:
                uart0_rx_state = 0;
                if(i == 0xff)
                        uart0_rx_state++;
                break;
        }
}
928315 发表于 2010-5-12 21:21 | 显示全部楼层
感觉你的IF ELSE 让我头都昏了。。。
928315 发表于 2010-5-12 21:29 | 显示全部楼层
大家还有什么写法,都探讨下啊。这种通讯协议解析很常用的啦。。。
 楼主| dai_22 发表于 2010-5-13 08:56 | 显示全部楼层
8# ejack
顶7楼,从报头开始到校验前一个字节的所有字节异或,不包括校验本身。
 楼主| dai_22 发表于 2010-5-13 09:03 | 显示全部楼层
9# 928315
谢谢你的建议,小弟悟性低,不知道这样写有什么优势,我的协议是变长的,也能这样写吗?
 楼主| dai_22 发表于 2010-5-13 09:07 | 显示全部楼层
弱弱的问一下:是不是所给的分数会影响回帖率?
yuyetufu 发表于 2010-5-15 16:02 | 显示全部楼层
弱弱的问一下:是不是所给的分数会影响回帖率?
dai_22 发表于 2010-5-13 09:07
不会,大伙儿都是无私的,不会看分数
dengm 发表于 2010-5-15 16:16 | 显示全部楼层
最好 1. 转义  2.  校验用2bytes----CRC8 + SUM8
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

20

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部