基于stm32的UART高效接收DMA+IDLE编程HAL库

基于stm32的UART高效接收DMA+IDLE编程HAL库

本文目标:基于stm32的UART高效接收DMA+IDLE编程HAL库

按照本文的描述,应该可以在对应的硬件上通实验并举一反三。

先决条件:拥有C语言基础,装有编译和集成的开发环境,比如:Keil uVision5

使用外设:USART2、GPIO

HAL库版本:STM32F1xx HAL Driver version number 1.8.5

STMCubeMX版本:6.10.0

Keil uVision5版本:V5.38.0.0

实验目的

新手学习UART实验,使用串口的DMA+IDLE空闲中断进行接收数据。

使用场景原理图

在我的应用场景中,设计一个实验进行自发的实验,其中我这里使用串口2进行实验

在这里插入图片描述

其中涉及使用的HAL库API如下:

//查询方式:
//发送:
HAL_UART_Transmit
//接收: 
HAL_UART_Receive
    
//中断方式:
//发送:
HAL_UART_Transmit_IT
HAL_UART_TxCpltCallback 
//接收: 
HAL_UART_Receive_IT
HAL_UART_RxCpltCallback
    
//DMA方式:
//发送:
HAL_UART_Transmit_DMA
HAL_UART_TxHalfCpltCallback
HAL_UART_TxCpltCallback
//接收: 
HAL_UART_Receive_DMA
HAL_UART_RxHalfCpltCallback
HAL_UART_RxCpltCallback
    
// 错误
HAL_UART_ErrorCallback
HAL_UART_ErrorCallback
  

IDLE

IDLE,空闲的定义是:总线上在一个字节的时间内没有再接收到数据。UART 的 IDLE 中断何时发生?RxD 引脚一开始就是空闲的啊,难道 IDLE 中断一直产生?不是的。当我们使能 IDLE 中断后,它并不会立刻产生,而是:至少收到 1 个数据后,发现在一个字节的时间里,都没有接收到新数据,才会产生 IDLE 中断。我们使用 DMA 接收数据时,确实可以提高 CPU 的效率,但是“无法预知要接收多少数据”,而我们想尽快处理接收到的数据。怎么办?比如我想读取 100 字节的数据,但是接收到 60 字节后对方就不再发送数据了,怎么办?我们怎么判断数据传输中止了?可以使用IDLE 中断。在这种情况下,DMA 传输结束的条件有 3:

① 接收完指定数量的数据了,比如收到了 100 字节的数据了,HAL_UART_RxCpltCallback被调用

② 总线空闲了:HAL_UARTEx_RxEventCallback 被调用

③ 发生了错误:HAL_UART_ErrorCallback 被调用

使用 IDLE 状态来接收的函数有:

//查询方式:
//接收: 
HAL_UARTEx_ReceiveToIdle
//回调函数:
//根据返回参数 RxLen 判断是否接收完毕,还是因为空闲而返回
    
//中断方式:
//接收: 
HAL_UARTEx_ReceiveToIdle_IT
//回调函数:
完毕:HAL_UART_RxCpltCallback
因为空闲而中止:
HAL_UARTEx_RxEventCallback

//DMA方式:
//接收: 
HAL_UARTEx_ReceiveToIdle_DMA
//回调函数:
传输一半:
HAL_UART_RxHalfCpltCallback
完毕:
HAL_UART_RxCpltCallback
因为空闲而中止:
HAL_UARTEx_RxEventCallback

// 错误
HAL_UART_ErrorCallback

程序设计

① 使用 DMA+IDLE 中断的方式接收数据,使用全局的数组来进行接收;

② main函数中将接收到的数据发回上位机。

串口配置

打开配置工具,进行串口配置

在这里插入图片描述

配置中断

在这里插入图片描述

配置DMA

在这里插入图片描述

代码片段

按照上述的配置进行底层配置之后,我们写点代码,进行接收数据,我们简单粗暴的写点函数,如下的代码片段

// 接收完成进入
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart2)
	{
		g_uart2_rx_complete = 1;
		Uart2ReciveDataSize = UART2_RECIVE_MAX;
		HAL_UART_Receive_DMA(&huart2,Uart2ReciveBuff,UART2_RECIVE_MAX);  // 重新启动接收
	}	
}
// 空闲中断进入
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if (huart == &huart2)
	{
		g_uart2_rx_complete = 1;
		Uart2ReciveDataSize = Size;
		/* re-start DMA+IDLE rx */
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, Uart2ReciveBuff, UART2_RECIVE_MAX);
	}	
}

接收错误进入

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart2)
	{
		/* re-start DMA+IDLE rx */
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, Uart2ReciveBuff, UART2_RECIVE_MAX);
	}
}

main函数中代码片段

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_DMA(&huart2,Uart2ReciveBuff,UART2_RECIVE_MAX);  // 开启接收
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	if(g_uart2_rx_complete == 1)
	{
		g_uart2_rx_complete = 0;
		HAL_UART_Transmit_DMA(&huart2,Uart2ReciveBuff,Uart2ReciveDataSize);  // 将接收的数据进行回显
	}
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

编译、烧写、运行,可以看到开发板的上的串口能成功接收数据,将接收到的数据进行回显,实验设计成功。

在这里插入图片描述

工程实验成功,后续将会继续记录项目中的实验,感谢关注。

本文中使用的测试工程

https://download.csdn.net/download/weixin_44317448/89208845

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用\[1\]中的代码是一个在STM32HAL库中使用DMA接收串口数据的例子。在这个例子中,通过设置空闲中断(IDLE)来判断串口接收是否完成,并使用DMA来传输数据。具体的实现步骤如下: 1. 首先,需要使能串口的空闲中断。在CUBEMX软件中,没有提供图形界面来开启空闲中断,所以需要手动编写代码来开启。 2. 接下来,开启DMA接收功能。通过调用HAL_UART_Receive_DMA函数来启动DMA接收,将接收到的数据存储到指定的缓冲区中。 3. 当串口接收到数据后,会触发空闲中断。在空闲中断处理函数中,首先需要清除中断标志,然后停止DMA接收。 4. 接着,通过调用__HAL_DMA_GET_COUNTER函数来获取DMA接收剩余的字节数,从而计算出实际接收到的字节数。 5. 然后,可以对接收到的数据进行处理,比如将数据发送到其他串口。 需要注意的是,根据实际接收到的字节数来定义DMA_RECEIVE的大小,确保其能够容纳接收到的数据。在引用\[1\]中,使用了uint16_t类型来定义DMA_RECEIVE。 总的来说,这个例子展示了如何使用STM32HAL库中的DMA接收串口数据,并通过空闲中断来判断接收是否完成。希望对正在学习的人有所帮助。 #### 引用[.reference_title] - *1* *3* [STM32 HAL库 串口DMA接收不定长数据](https://blog.csdn.net/weixin_41872408/article/details/118739340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [STM32HAL库开发系列 - 串口DMA接收](https://blog.csdn.net/sorcererr/article/details/128698094)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独处东汉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值