查看: 2631|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
沙发
发表于 2015-9-24 08:59:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
设计目标:
1. 单片机时钟10MHz,串口波特率115200
2. 由于波特率较高,串口必须采用中断方式接收
3. 串口接受完数据必须对数据进行解帧,即判断出帧头和帧尾,这部分放while循环里面处理

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


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

//变量定义
//串口缓冲区 建立一个环形缓冲区,收发
unsigned char xdata UART_Receive_Size=0;//串口缓冲区接收字节数
unsigned char xdata UART_Receive_First=0;//串口缓冲区接收字节开始位置
unsigned char xdata UART_Read_First=0;
unsigned char xdata UART_Buffer[BUFFER_SIEZ];//串口缓冲区
unsigned char xdata UART_Send_Byte_Ok=0;//发送一字节成功
//中断处理
//串口初始化根据自己的单片机写就行
void UART0_Interrupt (void) interrupt 4  
{
   if(RI0)                         //如果是发中断,返回
   {   
     RI0=0;  //清除中断标志
     if(UART_Receive_Size<=BUFFER_SIEZ)//缓冲区未满,装载数据
     {
       UART_Buffer[UART_Receive_First++]=SBUF0;
       UART_Receive_Size++;//串口缓冲区接收字节数
       if(UART_Receive_First>=BUFFER_SIEZ)//循环装入缓冲区
         UART_Receive_First = 0;
     }
   }
  if(TI0)
  {         
    TI0=0;
   UART_Send_Byte_Ok=1;
  }
}

//在缓冲区中读取一帧数据
void Do_Commend()
{
  unsigned char Buf[8]={0,0,0,0,0,0,0,0};//帧数据缓冲区
  unsigned char i=0;
  unsigned char data_packge_flag=0;

  if(UART_Receive_Size>=8)//缓冲区字节数大于等于一个包字节数
  {
    while(UART_Receive_Size!=0)//寻找帧数据头
    {
         if(UART_Buffer[UART_Read_First]==0xaa)
         {
           if(UART_Read_First+7<BUFFER_SIEZ)
           {
              if(UART_Buffer[UART_Read_First+7]==0x55)
              {
               data_packge_flag=1;
               break;
              }
           }
           else
           {
              if(UART_Buffer[7-(BUFFER_SIEZ-UART_Read_First)]==0x55)
              data_packge_flag=1;
              break;
           }
         }
         UART_Read_First++;
         if(UART_Read_First>=BUFFER_SIEZ)//环形 缓冲区折行
         UART_Read_First=0;
         UART_Receive_Size--;
    }
    if(data_packge_flag==1)//寻找到枕头
    {
       for(i=0;i<8;i++)//读取帧数据
       {
          Buf=UART_Buffer[UART_Read_First];
          UART_Receive_Size--;
          UART_Read_First++;
          if(UART_Read_First>=BUFFER_SIEZ)//环形 缓冲区折行
            UART_Read_First=0;
       }
       data_packge_flag=0;
    }
    if(Buf[7]==0x55&&Buf[0]==0xaa)  //接收到一个正确的数据包
    {
          switch(Buf[1])
          {
            ...
          }
        }
  }
}
复制代码转载

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入中科因仑

本版积分规则

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