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半满接收中断 至此,可以正常接收数据,并且中断回调函数中的Size得到的值也是正确的
精彩链接
发表评论