基于CubeMX的STM32开启DMA空闲中断进行串口不定长收发

在嵌入式系统中,串口通信常用于设备间数据传输。传统固定长度收发效率低,而不定长数据收发能灵活处理可变长度帧(如传感器数据或命令)。通过DMA(直接内存访问)空闲中断(IDLE Interrupt) 结合,STM32可高效实现此功能:DMA自动搬运数据到内存,减少CPU负担;空闲中断在串口线空闲时触发,标志一帧数据接收完成。本文基于CubeMX配置和HAL库,逐步讲解实现方法。


1. 准备工作
  • 硬件:STM32开发板(主包用的是STM32F103C8T6)、USB转串口模块、PC。
  • 软件:STM32CubeMX、Keil MDK或STM32CubeIDE。
  • 基础知识:熟悉USART通信、DMA原理和中断机制。

2. CubeMX配置步骤

CubeMX自动生成初始化代码,确保配置正确:

  1. 创建新工程

    • 打开CubeMX,选择目标MCU。
    • 设置时钟源(HSE 8MHz),配置时钟树至系统频率72MHz(F1系列)。
      在这里插入图片描述
  2. 配置串口(USART)

    • 启用USART(如USART1),模式为Asynchronous

    • 参数设置:波特率115200、数据位8、停止位1、无校验。

    • 引脚分配:PA9(TX)、PA10(RX),自动路由。

  3. 启用DMA传输

    • 在USART DMA Settings中,添加DMA通道:
      • Direction: Peripheral To Memory(接收方向)。
      • Mode: Circular(循环模式,持续接收)。
      • Increment Address: Memory(内存地址自增)。
      • Data Width: Byte(字节宽度)。
        在这里插入图片描述
  4. 启用空闲中断

    • 在NVIC Settings中:
      • 勾选USART全局中断(USART1 global interrupt)。
      • 启用USART IDLE Interrupt(空闲中断)。
    • 设置中断优先级(如Preemption priority 0)。
      在这里插入图片描述
  5. 生成代码

    • Project Manager中设置IDE(如MDK-ARM),生成代码。
    • 点击GENERATE CODE,导出Keil工程。

3. 代码实现

在生成的Keil工程中添加以下代码。关键点:

  • DMA接收初始化:启动DMA接收不定长数据。
  • 空闲中断处理:在中断回调中处理完整帧。
  • 数据帧提取:通过计算接收长度获取有效数据。
3.1 全局变量定义

main.c开头添加变量:

uint8_t buf_ctl[256];    // 接收数据缓冲区,大小按需求自定义即可
3.2 初始化DMA接收

main()函数中,启动DMA接收:

// main函数内
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);	//开启串口空闲中断
	HAL_UART_Receive_DMA(&huart1,buf_ctl,256);	//接收DMA使能
3.3 空闲中断处理

stm32f4xx_it.c中,修改USART中断处理函数:

// USART1全局中断处理
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))	   						  // 获得串口空闲中断标志
	{                              	
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);															// 清除空闲中断标志												 
		HAL_UART_DMAStop(&huart1);	        														// 停止DMA传输,防止数据覆盖
 
		len = 256 - (uint8_t)__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);     // 计算实际接收的数据长度
		buf_ctl[len]='\n';                              									// 在接收数据的末尾添加字符串结束符(适用于ASCII数据)
		HAL_UART_Transmit(&huart1,buf_ctl,len+1,500);   

		memset(buf_ctl,0,sizeof(buf_ctl));              								// 清空接收缓冲区
		HAL_UART_Receive_DMA(&huart1, buf_ctl, 256);       								// 重新开启DMA,准备接收下一帧数据。
								     
	}
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
4. 测试与验证
  1. 硬件连接
    • PC串口助手(如PuTTY)通过USB转串口连接STM32的USART1。
    • 开发板供电。
  2. 测试步骤
    • 编译下载代码到STM32。
    • PC发送不定长数据(如"Hello"、“STM32 DMA”)。
    • 观察回传数据:应与发送数据一致,证明收发成功。
  3. 常见问题
    • 数据丢失:确保DMA缓冲区足够大(如256字节)。
    • 中断不触发:检查CubeMX中空闲中断是否启用,并清除标志位。
    • 性能优化:减少主循环延时,使用DMA发送进一步提高效率。
      在这里插入图片描述

5. 总结

通过CubeMX配置DMA和空闲中断,STM32实现了高效串口不定长收发:

  • 优势:CPU占用率低(DMA搬运数据),实时性强(中断响应帧结束)。
  • 应用场景:适用于物联网设备、工业控制等需处理可变长度数据的系统。
  • 扩展建议:添加帧头/帧尾校验提升鲁棒性,或结合RTOS实现多任务处理。

其他:
在这里插入图片描述
在这里插入图片描述
感谢XTao EmbedLogs大大,参考文章链接:https://blog.csdn.net/a1547998353/article/details/139193387

Logo

分享最新、最前沿的AI大模型技术,吸纳国内前几批AI大模型开发者

更多推荐