这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » NUCLEO-U083RC学习历程34-优化一下DMA与串口空闲中断的代码

共2条 1/1 1 跳转至

NUCLEO-U083RC学习历程34-优化一下DMA与串口空闲中断的代码

高工
2025-05-16 21:19:18     打赏

使用DMA和空闲中断实现了串口接收不定长的数据功能,使用HAL库函数实现一下上述功能。

串口的空闲中断:顾名思义,就是当串口在一定的时间内没有接收到数据时,触发控制状态,从而产生空闲中断;一般来说,STM32在数据交互时,传输字节之间的间隔很短,然后再一个字节的通讯时间内,没有收到数据时,意味着程序进入了空闲中断,所以在程序的初始化后,我们只需要开启空闲中断后,然后在串口的回调函数中,进行数据迁移就可以,这里为了方便验证,将数据做回传处理。

一:cube MX配置和之前的帖子写的相同,这里就不做过多的介绍:

大家可以看下之前的帖子

NUCLEO-U083RC学习历程19-学习串口DMA发送和DMA的不定长接收-电子产品世界论坛

https://forum.eepw.com.cn/thread/389467/1

二:HAL库中有关串口接收的处理函数

在HAL库中使用串口中断或者时空闲中断,区别在于接收每个字节进入中断还是在未接收到一个字节时间内,进入中断,后者就是为了当全部数据接收时,使用HAL库自动处理数据是否完整的,从而进入库里面的回调函数。

2.1  启动接收DMA接收空闲中断

HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

当在主函数里面调用上述函数,就会自动启用串口的以DMA接收数据时,产生空闲中断,当数据接收完成后,进入回调函数进行处理。我们在回调函数中处理串口接收到数据即可。

注意:这里进入空闲中断存在两种方式:

a:接收数据时,发生一个字节时间内没有接收到数据时

b:当串口接收到数据,与定义接收的长度一致时,进入空闲中断。所以这就要求我们设置需要将接收的数组设置大一些,以保证我们可以正常接收到完整的数据,防止数据的丢失。

2.2 手动关闭DMA的中断

#define __HAL_DMA_DISABLE_IT(__HANDLE__, __INTERRUPT__)  ((__HANDLE__)->Instance->CCR &= ~(__INTERRUPT__))

HAL库中对DMA有传输错误、半传输完成和全部传输完成中断,三种不同的方式,如果说不把上述中断关闭的话,当串口接收一组数据时候,存在接收一半数据,进入接收一半的回调函数,接收完成后的回调函数,意味着串口会进入两次中断,从而多进入一次中断,往往半传输中断的回调函数意义不大,而且占用了中断资源。

2.3  接收完成回调函数

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);

这里的接收完成中断函数,主要是接收完成后,在回调中需要再次开启中断,否则不能再次进入中断处理。

2.4 传输错误中断处理

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);

写这个错误中断处理函数,主要是为了HAL在接收数据时出错,可能时外部干扰源引起的,在接收错误的回调函数中,同样需要处理空闲中断的接收,否则程序也无法再次开启空闲中断。

三:程序如下所示:

3.1  接收完成处理,做数据回传处理

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart == &huart2)
	{
//		__HAL_DMA_DISABLE(&hdma_usart2_rx);
//		HAL_UARTEx_ReceiveToIdle_DMA(&huart2,RecBuffer2,256);
//		__HAL_DMA_ENABLE(&hdma_usart2_rx);
			HAL_UARTEx_ReceiveToIdle_DMA(&huart2, RecBuffer2, 256); // 接收完毕后重启
			HAL_UART_Transmit(&huart2, RecBuffer2, Size, 100);         // 将接收到的数据再发出
			__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);		   // 手动关闭DMA_IT_HT中断
			memset(RecBuffer2, 0, 32);							   // 清除接收缓存
//		mcudRxLength = Size;
//		LocalSlaveProcess(mcudRxLength,GetLocalAddr());
	}
}

3.2 接收错误处理函数

void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart)
{
    if(huart->Instance == USART2)
    {
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, RecBuffer2, 256); // 接收发生错误后重启
		__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);		   // 手动关闭DMA_IT_HT中断
		memset(RecBuffer2, 0, 32);							   // 清除接收缓存      
    }
}

3.3 主程序下添加如下代码:

 HAL_UARTEx_ReceiveToIdle_DMA(&huart2, RecBuffer2, 256);
  __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);	

四:实测图片如下:

0517-1.png

可以看到以5ms的时间间隔进行测试,发送和接收的数据容错率很低。

实测较之前的处理方式,自己手动编写空闲中断处理函数,在串口中断调用的方式,本次使用HAL库的函数进行处理,增加了接收错误的处理部分;从而保证数据输出时候的稳定性。

测试代码如下所示:

TEST015_DMA+USART - 副本.zip




关键词: STM32U083     优化串口处理    

院士
2025-05-16 23:47:41     打赏
2楼

hal库可以完成这个优化吗?

期待一下楼主的作品


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]