单片机串口环形缓冲区进行数据帧接收和处理的问题

2020-01-19 19:38发布

设计目标:
1. 单片机时钟10MHz,串口波特率115200
2. 由于波特率较高,串口必须采用中断方式接收
3. 串口接受完数据必须对数据进行解帧,即判断出帧头和帧尾,这部分放while循环里面处理

搜索了下,发现下面的代码比较符合要求
但是根据信息有几个问题
1. UART_Receive_Size在中断函数和一般函数都出现,会产生其真实值被中断后覆盖掉的问题,导致值出错(最终结果是有可能丢帧)
2. 可不可以不用UART_Receive_Size,而是定义两个指针,分别指向接收位置和处理位置,则缓冲区的满(full)
    不用UART_Receive_Size进行判断,而是利用这两个指针的关系进行判断。这样子可以避免问题1?()
3. 求测试过的健壮性好的代码,谢谢


  1. //系统可修改参数宏定义
  2. #define BUFFER_SIEZ 64
  3. //控制命令定义
  4. #define COMMUNCIATE 0
  5. #define SET_SYSTEM_CAL_FULL 1
  6. #define SET_SYSTEM_CAL_MV_V 2
  7. #define SET_SYSTEM_OL 3
  8. #define SET_POWER_OFF_TIME 4 //设定系统关机时间
  9. #define READ_SYSTEM_DATA 5

  10. //变量定义
  11. //串口缓冲区 建立一个环形缓冲区,收发
  12. unsigned char xdata UART_Receive_Size=0;//串口缓冲区接收字节数
  13. unsigned char xdata UART_Receive_First=0;//串口缓冲区接收字节开始位置
  14. unsigned char xdata UART_Read_First=0;
  15. unsigned char xdata UART_Buffer[BUFFER_SIEZ];//串口缓冲区
  16. unsigned char xdata UART_Send_Byte_Ok=0;//发送一字节成功
  17. //中断处理
  18. //串口初始化根据自己的单片机写就行
  19. void UART0_Interrupt (void) interrupt 4  
  20. {
  21.    if(RI0)                         //如果是发中断,返回
  22.    {   
  23.      RI0=0;  //清除中断标志
  24.      if(UART_Receive_Size<=BUFFER_SIEZ)//缓冲区未满,装载数据
  25.      {
  26.        UART_Buffer[UART_Receive_First++]=SBUF0;
  27.        UART_Receive_Size++;//串口缓冲区接收字节数
  28.        if(UART_Receive_First>=BUFFER_SIEZ)//循环装入缓冲区
  29.          UART_Receive_First = 0;
  30.      }
  31.    }
  32.   if(TI0)
  33.   {         
  34.     TI0=0;
  35.    UART_Send_Byte_Ok=1;
  36.   }
  37. }

  38. //在缓冲区中读取一帧数据
  39. void Do_Commend()
  40. {
  41.   unsigned char Buf[8]={0,0,0,0,0,0,0,0};//帧数据缓冲区
  42.   unsigned char i=0;
  43.   unsigned char data_packge_flag=0;
  44.   
  45.   if(UART_Receive_Size>=8)//缓冲区字节数大于等于一个包字节数
  46.   {
  47.     while(UART_Receive_Size!=0)//寻找帧数据头
  48.     {
  49.          if(UART_Buffer[UART_Read_First]==0xaa)
  50.          {
  51.            if(UART_Read_First+7<BUFFER_SIEZ)
  52.            {
  53.               if(UART_Buffer[UART_Read_First+7]==0x55)
  54.               {
  55.                data_packge_flag=1;
  56.                break;
  57.               }
  58.            }
  59.            else
  60.            {
  61.               if(UART_Buffer[7-(BUFFER_SIEZ-UART_Read_First)]==0x55)
  62.               data_packge_flag=1;
  63.               break;
  64.            }
  65.          }
  66.          UART_Read_First++;
  67.          if(UART_Read_First>=BUFFER_SIEZ)//环形 缓冲区折行
  68.          UART_Read_First=0;
  69.          UART_Receive_Size--;
  70.     }
  71.     if(data_packge_flag==1)//寻找到枕头
  72.     {
  73.        for(i=0;i<8;i++)//读取帧数据
  74.        {
  75.           Buf=UART_Buffer[UART_Read_First];
  76.           UART_Receive_Size--;
  77.           UART_Read_First++;
  78.           if(UART_Read_First>=BUFFER_SIEZ)//环形 缓冲区折行
  79.             UART_Read_First=0;
  80.        }
  81.        data_packge_flag=0;
  82.     }
  83.     if(Buf[7]==0x55&&Buf[0]==0xaa)  //接收到一个正确的数据包
  84.     {
  85.           switch(Buf[1])
  86.           {
  87.             ...
  88.           }
  89.         }
  90.   }
  91. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
18条回答
Ray______
1楼-- · 2020-01-21 17:23
ziruo2002ab 发表于 2015-9-26 21:45
原理当然不复杂
复杂的是 当找到了帧头继续找帧尾时,到了数据缓冲区最后一个接收字节还没找到时,该怎么 ...

首先纠正一点,是判断帧尾,不是寻找帧尾。你一帧数据格式难道没规律?判断正确有何难,错误就扔掉
Ray______
2楼-- · 2020-01-21 22:59
kinsno 发表于 2015-9-26 22:03
2倍够干啥的,分分钟灭趴下;我一般会计算整个程序运行的最大时间,然后根据这个时间和一帧字节去反推缓 ...

你怎么不说8位机算啥,64位机直接秒杀…客观点看
Ray______
3楼-- · 2020-01-22 02:19
因为只有手机,就简单表达下自己的思想吧
uint8_t *dat;
if(ReceiveComplete)
{
  while(!cheakHead)
{
     dat++;
  }
if(checkEnd)
  {
    //u can check data here or return ok
  }
else
{
   //find next or return error
}
}
kinsno
4楼-- · 2020-01-22 03:07
本帖最后由 kinsno 于 2015-9-27 10:00 编辑
chenchaoting 发表于 2015-9-26 22:52
你这个漏不漏帧,一帧数据没发全怎么处理?


一帧没发全:因为你是有方法可以判断帧尾的,不管是定长的还是不定长的帧,你就一直找帧尾,如果找不着,就直接return掉(但不是移动帧头哦),当然还要考虑溢出的情况,比如你一帧最长也就是100个字节,结果你从帧头找了100个字节还没有找到帧尾,这明显就得移动帧头了,对吧;
kinsno
5楼-- · 2020-01-22 05:54
 精彩回答 2  元偷偷看……
Ray______
6楼-- · 2020-01-22 09:01
kinsno 发表于 2015-9-27 09:59
呵呵,我们所说根本不在一条线上;

既然你知道不在一条线上你还妄加评论?关键字眼麻烦看好

一周热门 更多>