STM32使用DMA传输UART空闲中断中接收的数据遇到的问题以及解决方法
CubeMX配置
-
串口配置:使用默认配置(传输数据长度为8 Bit,奇偶检验无,停止位为1 Bit, 接收和发送都使能),因为我的是LIN项目所以使用的时串口的LIN模式,一般就是异步通信
-
打开DMA传输
-
打开串口接收中断
-
生成工程
-
在mian.c中添加如下代码
//添加方法定义 void Util_Receive_IT(UART_HandleTypeDef *huart); //USER CODE BEGIN 4之间实现Util_Receive_IT方法 /** * 重写接收中断函数 */ void Util_Receive_IT(UART_HandleTypeDef *huart) { if(huart == &huart2) { //开启DMA传输UART空闲中断中接收的数据,并在接收到UART空闲中断后停止传输 //判断DMA接收是否正常启动 if(HAL_UARTEx_ReceiveToIdle_DMA(huart, pLINRxBuff, LIN_RX_MAXSIZE) != HAL_OK) { //如果有错误的话,清空缓冲,置位一些标志 HAL_UART_AbortReceive(huart); //重启DMA接收,pLINRxBuff是接收缓冲数组,接收的字节数,我这里LIN_RX_MAXSIZE是12 HAL_UARTEx_ReceiveToIdle_DMA(huart, pLINRxBuff, LIN_RX_MAXSIZE); } } } //USER CODE BEGIN 2中添加如下代码 //开启中断接收 Util_Receive_IT(&huart2); //USER CODE BEGIN 4之间增加中断回调函数和错误回调函数的实现 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { //LIN协议 if (huart == &huart2) { //具体的数据处理函数 } //重启DMA接收 Util_Receive_IT(huart); } /** * 重写UART错误中断处理程序,重新开启中断 * * @brief UART error callback. * @param huart UART handle. * @retval None */ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ //解决串口溢出,导致不断进入串口中断函数,使MCU过载的问题 if(HAL_UART_GetError(huart) & HAL_UART_ERROR_ORE) { //清除ORE标志位 __HAL_UART_FLUSH_DRREGISTER(huart); Util_Receive_IT(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; } }
-
存在的问题:
- LIN_RX_MAXSIZE是12,所以程序最多可以接收12个字节的数据,但是因为HAL_UARTEx_RxEventCallback回调函数会处理半满中断,全满中断和串口空闲中断,所以接收6个字节(包括6个字节)的数据中断回调函数中Size参数得到的值是正确的,并且保存到接收缓冲数组中的数据也是正确的。当接收超过6个字节的数据,中断回调函数中Size参数得到的值是LIN_RX_MAXSIZE一半,也就是6,只要字节数在7-12之间,参数Size的值永远是6,数据是可以正常接收的。
- 原因可能开启了DMA通道的中断,然后HAL_UARTEx_RxEventCallback中断回调函数会处理半满中断、全满中断和串口空闲中断这三种情况,半满中断先执行导致Size会变成接收字节数的一半。
解决方法
-
取消DMA通道的中断
-
在串口页面查看中断,可以发现DMA通道的中断已经取消了
-
代码不需要修改
-
存在的问题:
- 接收1-11个字节的数据是没有问题的,只要接收12个字节的数据,在串口调试过程中,点击串口的发送按钮,需要发送两次12个字节的数据,才会进入到中断回调函数的断点中,并且中断回调函数的Size参数得到的值是不正确的,接收缓存中保存的数据也是不正确的
- 还有一个问题,当进入中断回调函数的断点中,再次用串口调式助手发送一次数据,当前的中断回调函数执行完后,再次使用串口调试助手发送12字节的数据,中断回调函数只会接收到一个字节的数据
- 目前没有找到原因
再次开启DMA通道中断
-
开启DMA通道中断,虽然Size会有错误,但是接收的数据是正确的,只要全满中断和串口空闲中断就可以了,不需要半满中断
-
通过网上查阅资料,可以使用
__HAL_DMA_DISABLE_IT()
宏来禁用半满中断 -
stm32g0xx_hal_dma.h定义了全满中断、半满中断和错误中断
-
修改代码
//开启中断接收 Util_Receive_IT(&huart2); //禁用DMA半满接收中断 __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT); /** * 重写接收中断函数 */ void Util_Receive_IT(UART_HandleTypeDef *huart) { if(huart == &huart2) { //开启DMA传输UART空闲中断中接收的数据,并在接收到UART空闲中断后停止传输 //判断DMA接收是否正常启动 if(HAL_UARTEx_ReceiveToIdle_DMA(huart, pLINRxBuff, LIN_RX_MAXSIZE) != HAL_OK) { //如果有错误的话,清空缓冲,置位一些标志 HAL_UART_AbortReceive(huart); //重启DMA接收 HAL_UARTEx_ReceiveToIdle_DMA(huart, pLINRxBuff, LIN_RX_MAXSIZE); } //禁用DMA半满接收中断 __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT); } }
-
每次开启DMA接收时,都要禁用DMA半满接收中断文章来源:https://www.toymoban.com/news/detail-752008.html
-
至此,可以正常接收数据,并且中断回调函数中的Size得到的值也是正确的文章来源地址https://www.toymoban.com/news/detail-752008.html
到了这里,关于STM32使用DMA传输UART空闲中断中接收的数据遇到的问题以及解决方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!