解决STM32使用DMA传输UART空闲中断接收数据时遇到的问题及解决方法
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;
}
}
存在的问题:
解决方法
取消DMA通道的中断
在串口页面查看中断,可以发现DMA通道的中断已经取消了
代码不需要修改
存在的问题:
再次开启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得到的值也是正确的