STM32使用HAL库UART接收不定长数据-1

使用STM32的HAL库实现UART串口不定长数据的接收

使用STM32的UART接收数据的时候,经常会遇到接收长度不固定的数据,比如一帧数据可能是10个字节,也可能是12个字节。这种数据称为不定长数据。

现有的很多通信协议是不定长的,比如modbus-rtu,其不同指令的长度是不同的,还比如与ESP8266通信使用的AT指令,其数据长度也不是固定的。

对于上面所说的不定长数据,可以使用状态机的方式判断一帧数据的结束,即在UART接收中断中按照通信协议的格式进行判断,确定哪个字节为帧的结尾。但是这种方式编程比较复杂。

有一个更简单的方法,就是判断一帧数据的时间间隔。默认两帧数据之间是有一定时间间隔的,比如10ms,那么当收到一个字节的数据后,5ms内没有收到新的字节,就认为一帧数据的结束。这种方法能够大大简化UART接收中断的处理函数。只需要在主流程里判断这一帧数据是否合法即可,能够很好的减低编程难度,也提高了MCU的处理效率。

那么如何实现这种编程方式呢?这里介绍一种通过HAL库实现的方式。

不定长数据接收方式

在STM32中最通用的方式就是借助UART的IDLE中断来实现,即结合UART的接收DMA和IDLE中断来实现。这种方式适用于STM32的所有芯片。

UART的IDLE中断是:当一个空闲帧被检测到时产生的中断。空闲帧如下图所示,为持续一个字节数据的高电平,就是空闲帧。也就是持续1个字节总线上没有数据就是一个空闲帧。

通过设置UART使用DMA进行接收,使得UART能够自动接收数据,并放入缓冲区中。当STM32检测到IDLE中断后,通过回调函数对接收到的数据进行处理。这样不用每接收到一个字节就处理,提高了MCU的运行效率。

HAL库函数

在STM32的HAL库中提供了现成的函数
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

这个函数使用DMA接收数据,当接收到Size个数据或者遇到IDLE中断时完成接收,然后调用下面的回调函数。

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

库函数使用注意实现

因此对一帧数据的处理函数要放到 HAL_UARTEx_RxEventCallback() 函数中。注意这个函数是在中断程序中,因此其处理函数要尽量的短。而且其参数Size 在DMA为循环模式时,指的是在接收缓冲区中下一个字节的写入索引位置,这个要注意。

在使用HAL_UARTEx_RxEventCallback() 回调函数的时候也要注意,这个函数在DMA的"半传输"中断和"传输完成"中断的时候也会进入此回调函数。比如说使用HAL_UARTEx_ReceiveToIdle_DMA() 函数接收20个字节,那么在接收到10个字节的时候会触发DMA"半传输中断",接收到20个字节的时候会触发DMA的"传输完成"中断。DMA的"传输完成"中断不会产生影响,因为此时接收也已经完成了。但是"半传输"中断会影响处理,比如接收到不定长数据为12个字节,那么在收到10个字节的时候会进入HAL_UARTEx_RxEventCallback() 回调函数,在接受到12个字节的时候还会进入HAL_UARTEx_RxEventCallback() 回调函数。

防止DMA中断影响的方法

最简单的处理方法是关闭DMA的这2个中断,可以在调用HAL_UARTEx_ReceiveToIdle_DMA() 函数后,关闭这2个中断,参考如下代码:

  HAL_UARTEx_ReceiveToIdle_DMA(&huart1,recvbuf,20);
  __HAL_DMA_DISABLE_IT(huart1.hdmarx,DMA_IT_HT); //关闭半传输中断
  __HAL_DMA_DISABLE_IT(huart1.hdmarx,DMA_IT_TC); //关闭传输完成中断

这种方法既适用于将UART的DMA接收设置为循环接收,也适用于将DMA设置为单次接收模式。

如果不想关闭中断,而且DMA接收模式时单次模式,那么也可以在回调函数中进行判断,判断方法如下:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if(huart->RxState == HAL_UART_STATE_READY){
    // 接收完成
  }else{
    // 半传输中断
  }
}

在"半传输"中断进入时,接收没有完成,因此huart->RxState 的值是HAL_UART_STATE_BUSY_RX ,因此可以通过判断huart->RxState 的值是否等于HAL_UART_STATE_READY ,得知是因哪种事件进入的回调函数。

以上就是STM32使用HAL库实现UART不定长数据接收的一种方法,使用起来很简便。但是使用IDLE中断判断1帧数据结束还有有一定问题的,比如说在终端发送数据的时候,一帧数据中字节与字节之间的时间间隔比1个字节长了,就会造成误判。所以在使用的时候还是要注意区分的。在新出的STM32处理器中,针对这一点提供也新的解决方案,就是包含一个时间间隔可以设置的功能,这个将在下一次进行分享。

相关推荐
海的预约1 小时前
51单片机-按键
单片机·嵌入式硬件·51单片机
【云轩】5 小时前
基于STM32与IFX007T的电机驱动全解析(无人机/机器人实战)
stm32·机器人·无人机
qq_75568224012 小时前
STM32使用NRF2401进行数据传送
stm32·单片机·嵌入式硬件
FreakStudio18 小时前
开源一款串口舵机驱动扩展板-FreakStudio多米诺系列
单片机·嵌入式·大学生·电子diy
艾格北峰19 小时前
STM32 物联网智能家居 (六) OLED显示设备
arm开发·stm32·单片机·嵌入式硬件·物联网·智能家居
weixin_5358542221 小时前
oppo,汤臣倍健,康冠科技,高途教育25届春招内推
c语言·前端·嵌入式硬件·硬件工程·求职招聘
热爱嵌入式的小许1 天前
STM32 HAL库&标准库+ESP8266+机智云
stm32·单片机·嵌入式硬件·stm32移植机智云·stm32连接机智云·hal库移植机智云·标准库移植机智云
无际单片机编程1 天前
面对STM32的庞大体系,如何避免迷失在细节中?
java·stm32·单片机·嵌入式硬件·嵌入式开发
【云轩】1 天前
【零基础实战】用STM32玩转DRV8313电机驱动:从原理到无人机/机器人控制
stm32·机器人·无人机
2301_764602231 天前
stm32hal库寻迹+蓝牙智能车(STM32F103C8T6)
stm32·单片机·嵌入式硬件