找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1190|回复: 6
收起左侧

解析串口4接收的数据包中的一帧数据

[复制链接]
回帖奖励 10 黑币 回复本帖可获得 1 黑币奖励! 每人限 1 次
ID:590050 发表于 2025-1-17 20:43 | 显示全部楼层 |阅读模式
      程序大部分是借鉴的网上或STC的例程,想实现从串口接收的数据包中,解析出一帧完整的命令。请教各位大神帮看一下程序,我用的STC单片机,串口4接收数据,接收的数据存在ucRX4_Buffer【】中,最大存UART4_BUF_LENGTH个数据。中断部分程序如下:
unsigned char ucRX4_index=0;
void Uart4_isr() interrupt 18         //UART4 中断服务程序
{
        UART4_INT_DISABLE();        //禁止串口4中断        
        
        if(RI4)                                        //串口4接收到数据         
    {
                CLR_RI4();          //清除中断4的接收标志  

                ucRX4_Buffer[ucRX4_index] = S4BUF;         //将串口4接收到的数据放入ucRX4_Buffer[]
                ucRX4_index++;
                if(ucRX4_index>UART4_BUF_LENGTH)        ucRX4_index=0;                        
    }

    if (TI4)
    {
        CLR_TI4();         //清除中断4的发送标志

                bTX4_Busy = 0;           //设置串口4发送为空闲
    }
        UART4_INT_ENABLE();                  //允许串口4中断
}

数据接收后,从接收的数据包中查找以FD,FD,FD开头的数据帧,不同的命令对应不同的数据长度,将查找出的数据存在ucRX4_CMD_Data_Buffer【】中,程序如下:
void  Uart4_Read_Cmd_Data(void)                //读串口4接收的不同命令的数据
{
        unsigned char i;
        ucRX4_Read_Cnt = 0;        
        switch(ucRX4_Read_State)
        {
                case 0:                //判断头文件
                {
//从接收缓存中查找帧头
                        if(ucRX4_Buffer[ucRX4_Read_Cnt] == 0xFD)         //帧头0xFD 0xFD 0xFD
                        {
                                 ucRX4_Read_Cnt++;                 //读下一个数
                                if(++ucRX4_Head_Cnt >= 3)        //头0xFD 0xFD 0xFD
                                {
                                        ucRX4_Read_State=1;
                                }
                        }
                        else
                        {
                                ucRX4_Read_Cnt++;                 //读下一个数
                                ucRX4_Head_Cnt = 0;
                                ucRX4_Read_State = 0;
                        }        
                }        
                break;

                case 1:        //判断命令长度,不同命令长度不同;
                {                        
                        if(ucRX4_Buffer[ucRX4_Read_Cnt] == 0x06)                //06命令,06后4个字节,加上命令,共计5个字节
                                ucRX4_Recv_Data_Length=5;                                         
                        else if(ucRX4_Buffer[ucRX4_Read_Cnt] == 0x07)        //07命令
                                ucRX4_Recv_Data_Length=15;
                        else if(ucRX4_Buffer[ucRX4_Read_Cnt] == 0x08)        //08命令
                                ucRX4_Recv_Data_Length=10;
                        else if(ucRX4_Buffer[ucRX4_Read_Cnt] == 0x09)        //09命令
                                ucRX4_Recv_Data_Length=11;
                        else  ucRX4_Recv_Data_Length=0;

                        ucRX4_Read_State=2;                                                               
                }                                 
                break;

                case 2:                //接收数据
                {                                 
                        for(i=0;i<ucRX4_Recv_Data_Length;i++)
                        {
                                ucRX4_CMD_Data_Buffer[ i]=ucRX4_Buffer[ucRX4_Read_Cnt];
                                ucRX4_Read_Cnt++;        
                        }

                        bRX4_Flag=1;         //一帧数据接收完成
                        ucRX4_Read_State=0;
                        ucRX4_Head_Cnt = 0;

                }break;

                default:break;
        }
}

在其它程序中,需要读数据时,就调用        void  Uart4_Read_Cmd_Data(void)函数。

以上程序,现在的问题是,总是查找出的数据总是不对,用串口助手验证,比如发的数据包中包含了一帧数据,FD FD FD 06 01 02 03 06,但解析出的数据却不是这个,求大神帮看一下是哪里的问题,先谢。
回复

使用道具 举报

ID:338503 发表于 2025-1-18 08:07 | 显示全部楼层
你上述程序调用void  Uart4_Read_Cmd_Data(void)函数1次只能读取1个字节数据,按你上述程序,要根据命令(0x06,0x07,0x08,0x09)的不同调用相应次数才可以。
回复

使用道具 举报

ID:338503 发表于 2025-1-18 08:16 | 显示全部楼层
上述读命令程序调用1次只能读取一个字节数据,只有根据命令(0x06,0x07,0x08,0x09)的不同调用相应次数才可以。
回复

使用道具 举报

ID:1143113 发表于 2025-1-19 11:04 | 显示全部楼层
有一个问题要注意,你是什么时候开始解析,建议要在解析前先判断接收字节数够不够。只有字节数够了才调用判断。这个非常重要的。
回复

使用道具 举报

ID:161164 发表于 2025-1-19 23:27 | 显示全部楼层
ucRX4_Read_Cnt 是全局变量吗?
为什么要在Uart4_Read_Cmd_Data函数开头清零?
回复

使用道具 举报

ID:1133081 发表于 2025-1-20 08:51 | 显示全部楼层
首先要充分了解该自定义通讯协议,通常通讯协议的每一个字节都有其特定含义。例如:数据头,数据长度,有效数据,验证码,数据尾等。假设这串数据的前3个FD为数据头,那么当串口连续收到3个FD即判断为有真实信号到来,即持续对后续数据保存。否则清除缓存。如果数据长度固定很好办,收完若干字节即给出结束标志。数据长度不固定,但有字节长度信息也好办,根据长度信息确定结束接收并给出结束标志。如不含根据长度信息通常启动定时器,若干时间收不到数据表示传输结束即给出结束标志。解析函数在得到结束标志后才开始解析并清除结束标志和缓存,为下次接收做准备。假设FD FD FD 06 01 02 03 06是固定长度,串口中断示例:

  1. void UARTInterrupt() interrupt 4
  2. {
  3.         static uchar num=0;                //静态计数变量
  4.         uchar i;
  5.         RI=0;                                        //接收中断请求标志位清0
  6.         rec_buf[num]=SBUF;                //接收到的数据串保存在缓存数组
  7.         if(rec_buf[0]==0xFD)        //验证数据头(起始位)
  8.         {
  9.                 num++;
  10.                 if(num==3)
  11.                 {
  12.                         if((rec_buf[0]&rec_buf[1]&rec_buf[2])!=0xFD)
  13.                         {
  14.                                 for(i=0;i>7;i++)
  15.                                         rec_buf[i]=0x00;//清除缓存
  16.                         }
  17.                 }
  18.                 if(num>=8)
  19.                 {
  20.                         flag=1;                        //接收完成标志置1
  21.                         num=0;                        //计数变量清0
  22.                 }
  23.         }
  24. }
复制代码



回复

使用道具 举报

ID:1143357 发表于 2025-1-24 12:50 | 显示全部楼层
你调用这个函数时switch结构只进去了一次就出来了,而且用于计数的参数又是局部变量,再次调用计数参数又会归零,这里可以改一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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