首页 > 社交 > 科普中国

串口接收不定长数据的几种方法

常驻编辑 科普中国 2022-09-20 串口   定长   数据   主程序   定时器   字节   函数   长度   标志   定义   方式

同样,在主程序中判断一帧数据的接收完成并处理。JC2拜客生活常识网

2.特点协议判断帧头帧尾及长度JC2拜客生活常识网

有时候我们需要自己定义协议传输数据,这时候就可以在通讯协议里添加特点的帧头帧尾以及数据长度字节,通过判断这些字节来判断数据的开始和结束。假设定义一个简单的传输协议如下:JC2拜客生活常识网

帧头JC2拜客生活常识网

数据长度,1字节JC2拜客生活常识网

数据,N字节JC2拜客生活常识网

0x5A,0xA5JC2拜客生活常识网

数据部分的字节数JC2拜客生活常识网

有效数据JC2拜客生活常识网

可以使用中断方式接收数据:JC2拜客生活常识网

HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口中断接收数据

接收中断函数如下:JC2拜客生活常识网

//串口接收中断回调函数
uint8_t RevByte;
uint16_t RevTick = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  static uint16_t Rx_len;

  if(huart->Instance==USART1)
  {
    Uart1.RxBuf[Uart1.RxCnt]=RevByte;
    switch(Uart1.RxCnt)
    {
      case 0:
        if(Uart1.RxBuf[Uart1.RxCnt] == 0x5A)//帧头1正确
          Uart1.RxCnt++;
        else
          Uart1.RxCnt = 0;
        break;
      case 1:
        if(Uart1.RxBuf[Uart1.RxCnt] == 0xA5)//帧头2正确
          Uart1.RxCnt++;
        else
          Uart1.RxCnt = 0;
        break;
      case 2:
        Rx_len = Uart1.RxBuf[Uart1.RxCnt];
        Uart1.RxCnt++;
        break;
      default:
        Uart1.RxCnt++;
        if((Rx_len+3) == Uart1.RxCnt)//数据接收完成
        {
          Uart1.RxFlag = 1;
          Uart1.RxLen = Uart1.RxCnt;
          Uart1.RxCnt = 0;
        }
        break;
    }
    HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口中断接收数据
	}
}

同样,在主程序中判断一帧数据的接收完成并处理,运行测试结果如下:JC2拜客生活常识网

JC2拜客生活常识网

3.超时判断JC2拜客生活常识网

超时判断其实与空闲中断的原理类似,只不过是通过定时器来取代空闲中断来判断一帧数据的结束,一般采样接收中断+超时判断的方式。之前的文章Freemodbus移植就是采样这种方式。JC2拜客生活常识网

超时判断的时间跟波特率有关,假设串口起始位和结束位各1位,那么接收一个字节就需要8+2=10位,在9600波特率下,一秒钟就能接收9600/10=960字节。也就是一个字节需要1.04ms,那么超时时间最小可以设置为1.5倍的单字节接收时间,或者更长。JC2拜客生活常识网

超时判断可以使用硬件定时器或软件定时器来实现。硬件定时器的方式可以参考之前的Freemodbus移植部分的程序。软件定时器定义一个计时变量,该变量在systick中断中+1实现计时,可以节省硬件资源,但计时最小分辨率跟systick中断有关。JC2拜客生活常识网

编写中断接收函数:JC2拜客生活常识网

//串口接收中断回调函数
uint8_t RevByte;
uint16_t RevTick = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance==USART1)
  {
    Uart1.RxBuf[Uart1.RxCnt]=RevByte;
    Uart1.RxCnt++;
    Uart1.RxStart = 1;//开始接收标志
    RevTick = 0;//计时清零
    if(Uart1.RxCnt==RX_MAXLEN)
    {
      Uart1.RxCnt = RX_MAXLEN-1;
    }
    HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口中断接收数据
  }
}

编写超时判断函数,在Systick中断中调用:JC2拜客生活常识网

//串口接收超时判断,该函数在Systick中断(1ms中断一次)中调用
void UartTimeOut()
{
  if(Uart1.RxStart == 1)
  {
    RevTick++;
    if(RevTick > 2)
    {
      Uart1.RxLen = Uart1.RxCnt;
      Uart1.RxCnt = 0;
      Uart1.RxStart = 0;
      Uart1.RxFlag = 1;
    }
  }
}

使用时只要打开接收中断即可,不再需要空闲中断。JC2拜客生活常识网

HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口中断接收数据

同样,在主程序中判断一帧数据的接收完成并处理。测试结果就不贴了。

相关阅读:

  • 什么是DTU?DTU的作用是什么?
  • 温州速维:触摸一体机的常见问题和解决方案
  • 520祝福语都是你要说的
  • 光环大数据培训怎么样(大数据对培训与开发)
  • 手机恢复出厂设置会怎么样(手机如何永久删除数据)
  • 数据分析的方法有哪些(数据分析通常包括哪两种方法)
  • 哪些是大数据(大数据具有哪些基本特征)
  • 分析软件有哪些(数据分析软件排名)
  • 哪里找数据(综艺节目数据在哪找)
  • 合并单元格在哪里(数据合并表格在哪)
    • 网站地图 |
    • 声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不做权威认证,如若验证其真实性,请咨询相关权威专业人士。