【STM32】HAL库——串口DMA通信(三)

本文详细介绍了STM32中DMA的工作原理、意义及其在串口通信中的应用。通过STM32CubeMX配置USART和DMA,实现串口的DMA发送与接收,并利用串口空闲中断判断接收完成,有效管理数据传输。同时,文章提供了具体的代码示例,展示了如何使用HAL库进行DMA串口操作。
摘要由CSDN通过智能技术生成

前期准备:

  1. STM32CubeMX
  2. STM32RCT6核心板
  3. IDE Keil(MDK-ARM)

关于DMA

1. 什么是DMA?

DMA(Direct Memory Access,直接存储器访问) 提供在外设与存储器存储器和存储器外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通,而不需要依赖于CPU,在这个时间中,CPU对于内存的工作来说就无法使用。

这里的外设指的是spi、usart、iic、adc等基于APB1 、APB2或AHB时钟的外设,而这里的存储器包括自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问地源或者目的。

2. DMA的意义

传感器A获取到了数据,我需要把获取到的数据交给传感器B使用,正常来说,需要CPU控制,把A获取到的数据赋给B。但如果使用DMA,我可以将A与B之间建立一个专门传输数据的通道,CPU无需介入,对于非常大的数据需要转移时,DMA无疑大大节省了CPU的资源

优点: 控制简单,它适用于数据传输率很高的设备进行成组传送。
缺点: 在DMA控制阶段,CPU无法访问内存,内存的效能没有充分发挥,相当一部分内存工作周期是空闲的。这是因为,外围设备传送两个数据之间的间隔一般总是大于内存存储周期,因此许多空闲的存储周期不能被CPU利用。
在这里插入图片描述

3. DMA的结构器

2个DMA控制器,DMA1有7个通道

在这里插入图片描述
DMA2有5个通道
在这里插入图片描述
1个通道同一时间只能进行一个,例如通道 1 的几个 DMA1 请求(ADC1、TIM2_CH3、TIM4_CH1),这几个是通过逻辑或到通道 1 的,这样我们在同一时间,就只能使用其中的一个。其他通道也是类似的

3. DMA的传输方式

  • DMA_Mode_Normal(正常模式)
    一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次
  • DMA_Mode_Circular(循环传输模式)
    当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输模式

4. DMA及通道的优先级

优先级管理采用软件+硬件:

  • 软件:每个通道的优先级可以在DMA_CCRx寄存器中设置,有4个等级
    最高级>高级>中级>低级

  • 硬件:如果2个请求,它们的软件优先级相同,则较低编号的通道比较高编号的通道有较高的优先权。比如:如果软件优先级相同,通道2优先于通道4

在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。

5. DMA中断

DMA的每个通道都有 3 个事件标志(DMA 半传输,DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求
可以通过设置寄存器的不同位来打开这些中断
在这里插入图片描述

6.指针递增模式

外设和存储器指针在每次传输后可以自动向后递增或保持常量。当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值


STM32CubeMX部分

1.配置时钟

选择STM32F103RCTx系列芯片,配置时钟的同时会自动配置IO口引脚
在这里插入图片描述
将HCLK设置为最大频率72MHz
在这里插入图片描述

2.配置USART和DMA

配置USART,【STM32】HAL库 CubeMX例程三—串口中断通信(2)(附工程源码)文章有讲解过,这里就不再赘述
在这里插入图片描述
DMA Settings ——> Add

在这里插入图片描述
然后选择USART1_RX,接着同样步骤再把USART1_TX添加进来

在这里插入图片描述

  • DMA Request(DMA请求): USART1_RX、USART1_TX
  • Channel(通道): 通道5、通道4
  • Dirction (DMA传输方向): Peripheral To Memory(外设到内存)、Memory To Peripheral(内存到外设 )
  • Priority(优先级): 低、低
  • Mode(模式): 正常、正常
  • Increment Address(地址指针递增): 1.这里因我们是一直往固定外设地址&USART1发送数据,所以地址不递增 2.这里我们的场景是将内存中连续存储单元的数据发送到串口,毫无疑问内存地址是需要递增的
  • Data Width(数据宽度): 字节、字节
    在这里插入图片描述
    USART1使能中断

在这里插入图片描述

3.工程生成

在这里插入图片描述
在这里插入图片描述
工程管理依旧是这几个选项,然后GENERATE CODE,STM32CubeMX部分完成

MDK 5部分

//DMA函数
· HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);串口DMA模式发送
· HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);串口DMA模式接收
· HAL_UART_DMAResume(&huart1); 恢复串口DMA
· HAL_UART_DMAPause(&huart1) 暂停串口DMA
· HAL_UART_DMAStop(&huart1); 结束串口DMA

1. DMA串口发送

在main.c中添加

 /* USER CODE BEGIN Init */
	uint8_t Senbuff[] = "Q大帅のUART DMA Test Success ! \r\n";   

  /* USER CODE END Init */

在while里写入

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Senbuff, sizeof(Senbuff));
		HAL_Delay(1000);		

  }

编译下载时需要选择相对应的下载器,勾选以下
在这里插入图片描述

效果如图

在这里插入图片描述

2. IDLE接收(串口空闲中断接收)

当DMA串口接收开始后,DMA通道会不断的将发送来的数据转移到内存,那该如何判断串口接收是否完成从而及时关闭DMA通道?如何知道接收到数据的长度?答案便是使用串口空闲中断
思路流程:

  1. 开启串口DMA接收
  2. 串口收到数据,DMA不断传输数据到内存
  3. 一帧数据发送完毕,串口暂时空闲,触发串口空闲中断
  4. 在中断服务函数中,可以计算刚才收到了多少个字节的数据
  5. 存储接收到的数据,清除标志位,开始下一帧接收

在原有代码上更改

//在main.c定义3个全局变量
/* USER CODE BEGIN Includes */
uint8_t rx_buffer[100];   //接收数据的数组
volatile uint8_t rx_len = 0; //接收数据的长度
volatile uint8_t recv_end_flag = 0; //接收结束标志位
/* USER CODE END Includes */
  /* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);  //开启空闲中断
HAL_UART_Receive_DMA(&huart1,rx_buffer,100);  //开启DMA接收中断
  /* USER CODE END 2 */

在stm32f1xx_it.c文件中

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  uint8_t tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE状态
  if((tmp_flag != RESET))//判断接收是否结束
    { 
      // recv_end_flag = 1; //接收结束
       __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清楚标志位
       HAL_UART_DMAStop(&huart1); 
       uint8_t temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);                 
       rx_len =100-temp; //计算数据长度
	     HAL_UART_Transmit_DMA(&huart1, rx_buffer,rx_len);//发送数据
       HAL_UART_Receive_DMA(&huart1,rx_buffer,100);//开启DMA
    }
  /* USER CODE END USART1_IRQn 1 */
}

效果如图

在这里插入图片描述

本期工程文档——>Gitee

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值