[STM32]HAL库实现DMA+串口idle接收
说来惭愧,玩了一年多的单片机,但是却一直没有一个非常好的串口接收策略,之前同学推荐了idle闲时中断接收,当时也是因为时间原因没有自己去尝试,寒假准备完善自己的基础代码库的时候才想起这回事。其实发的这篇文章并没有什么技术含量,只是因为我的实现方案相较于网上的都比较简单,和HAL库结合比较紧密。同时也感叹一下HAL库和CUBEMX的组合实在是方便。
介绍一下串口的Idle中断,参考手册是这么说的:
When an idle frame is detected, there is the same procedure as a data received character plus an interrupt if the IDLEIE bit is set.
意思是,如果IDLEIE被设置后,那么当接收数据后的空闲帧被检测到之后才会触发一个中断
关于网上也有不少配置DMA+串口idle的教程,我看了不少,感觉都挺麻烦,要自己配置不少东西。不过出于习惯,我经常直接去HAL库的.h文件里翻函数写,于是我发现了下面这套函数:
这不就是HAL库封装的关于闲时中断的三个接收函数吗,而且还把阻塞中断DMA三种接收方式都封装了。
这三个函数网上找了找几乎就没找到资料,不过好在HAL库的注释够全,光看注释也看的通。
那么我们核心的函数就是这个了:
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
下面是它的注释
/**
* @brief Receive an amount of data in DMA mode till either the expected number of data is received or an IDLE event occurs.
* @note Reception is initiated by this function call. Further progress of reception is achieved thanks
* to DMA services, transferring automatically received data elements in user reception buffer and
* calling registered callbacks at half/end of reception. UART IDLE events are also used to consider
* reception phase as ended. In all cases, callback execution will indicate number of received data elements.
* @note When the UART parity is enabled (PCE = 1), the received data contain
* the parity bit (MSB position).
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M = 01),
* the received data is handled as a set of uint16_t. In this case, Size must indicate the number
* of uint16_t available through pData.
* @param huart UART handle.
* @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
* @param Size Amount of data elements (uint8_t or uint16_t) to be received.
* @retval HAL status
*/
从注释也是可以看出来他会通过DMA接收数据,超出我们指定的长度或者发生了串口闲时中断,可以说是一步到位了。
我们要做的只是调用这个函数,然后写个接收事件回调函数即可。
这个事件回调函数也是HAL库预先帮我们做好的weak函数,要用的时候自己找个地方定义即可。
下面是函数调用栈,可以看到HAL库写的还是很复杂的
配置
挺简单的,自己捣鼓去,我不想详细写。
主要就几点:
- CUBEMX里面配置好串口和DMA,然后记得开启串口的中断
- 调用函数
HAL_UARTEx_ReceiveToIdle_DMA
- 在回调函数
HAL_UARTEx_RxEventCallback
中记录下此次接收到的数据长度 - 要想再接收数据就必须再次调用接收函数