稳定的串口通信协议~物联网项目

借鉴了PPP协议的帧格式
当数据区出现7e的时候则需要进行对7e进行转义
7E—>7D 5E
数据帧的规定

开始字符AD数据区的长度IO数据区的长度AD数据区IO数据区校验位
1bit1bit1bit2bit1bit1bit整条数据的总长
7E020100 000007

各个区域的含义如下:

  • 开始字符:1个字节,代表一个数据包的开始。固定为0x7E
  • AD数据区的长度:1个字节,表示有多少个传感器数据,比如,1个传感器就1*2表示02因为AD数据区是有2bit
  • IO数据区的长度: 1个字节,表示有多少个IO口,比如,1个io就表示01,IO数据区就1bit
  • AD数据区:2个字节,一个传感器占用两个字节
  • IO数据区:1个字节,一个IO占用一个字节
  • 校验和:包括校验位在内整个数据包的总长度

这套数据规则是存在缺陷,但是在目前的业务中完全足够使用
在AD数据区的长度中大于100左右,就会存在校验位溢出的情况,哈哈哈哈
请添加图片描述

串口调试助手100ms循环发送几十分钟,未出现异常
image-20220509100322074

异常处理一:

  • 第一条数据包发送过去,数据包中间给予一些奇怪数据。
    image-20220509100512156

异常数据二:

  • image-20220509100731834

异常数据三:

  • image-20220509101027299

代码实现,基于CC2530实现

int  uart_count = 0;                //串口计数器
char uart_data_buff[128];           //串口接收缓冲区

#define UART_DATA_HEAD      0x7E    //判断指令帧头
char    UART_DATE_ADC_SUM = 0x00;   //传感器数量
char    UART_DATE_IO_SUM =  0x00;   //执行器、和数字量传感器的数量(他们的状态)
int     uart_data_sum =     0;      //接收指令总和
//串口发送一个字节
void uart_send_put(char byte)
{
  U0DBUF = byte;        //将要发送的1字节数据写入U0DBUF
  while(!UTX0IF);       //等待TX中断标志,即数据发送完成
  UTX0IF = 0;           //清除TX中断标志,准备下一次发送
}
//串口发送一个字节数组
void usrt_send_array(char *data, int index)
{
  int i = 0;
  for(i = 0;i<index;i++)
  {
    uart_send_put( data[i]); 
  }
}
//串口检验函数
void uart_data_check(char *data , int index);

//这个中断函数相当于,一个个接收的函数
#pragma vector = URX0_VECTOR
__interrupt void Scan_Byte()
{
  URX0IF=0;
  uart_data_buff[uart_count] = U0DBUF; //将数据存入缓冲区
  uart_count++;
  
  while(!U0DBUF);
  
  //-----这里是count、计算指令校验和都是 从123456789开始算的,所以取最后一位的时候记得-1

  if(uart_count == 3)//接收到前三个数据位的时候就已经可以知道整条数据的长度了
  {
    if(uart_data_buff[0] == UART_DATA_HEAD) //判断帧头
    {
      UART_DATE_ADC_SUM = uart_data_buff[1];//对传感器数量进行赋值
      UART_DATE_IO_SUM  = uart_data_buff[2];//对io状态的数量进行赋值
      //然后这里计算整条指令的总长度
      uart_data_sum = 1 + 1 + 1 + ((int)UART_DATE_ADC_SUM) + ((int)UART_DATE_IO_SUM) + 1;
    }
  }
  //当串口计数器大于3的时候,校验错误数据 
  if(uart_count >= 3)
  {

    //若数据任意一列出现了帧头,则都全部抛弃,重新拼接
    if(uart_data_buff[uart_count-1] == UART_DATA_HEAD)
    {
      //7E 04 02 12 7E 04 02 12 34 25 30 11 10 0A 这是一条错误数据
      //这里存在错误数据
      //程序运行到这里的时候uart_count = 4;uart_data_buff[4]里面是7E
      //所以将计数器赋值为1,uart_data_buff[0] 赋值帧头,从1开始继续接收数据
      uart_count = 1;
      uart_data_sum = 0;
      memset(uart_data_buff, 0, sizeof(uart_data_buff));
      UART_DATE_ADC_SUM = 0x00;
      UART_DATE_IO_SUM = 0x00;
      uart_data_buff[0] = UART_DATA_HEAD;//把帧头重新赋值到0
    }
    //最后一位是整条指令的校验和,把最后一位校验位取出来和计算出来的校验和判断
    if(uart_data_buff[uart_count-1] == uart_data_sum)
    {
      //接收成功
      uart_data_check(uart_data_buff,uart_count);
      uart_count = 0;
      uart_data_sum = 0;
      UART_DATE_ADC_SUM = 0x00;
      UART_DATE_IO_SUM = 0x00;
      D3 = ~D3;
    }
  }
  
}

//串口数据校验函数
void uart_data_check(char *data , int index)
{
  //index是从123456开始算的,记得-1
  //7E 04 01 12 34 25 30 11 09
  if(data[0] == UART_DATA_HEAD && ((int)data[index-1]) == index )
  {
        usrt_send_array(data,index);
  }
}

版权声明:本文为weixin_43539011原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。