STM32CubeMX学习笔记(7)——DMA接口使用

发布者:CrystalSparkle最新更新时间:2025-02-21 来源: jianshu关键字:STM32CubeMX  DMA接口 手机看文章 扫描二维码
随时随地手机看文章

一、DMA简介

DMA(Direct Memory Access) 直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH。DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。 要注意的是 DMA2 只存在于大容量的单片机中。


二、DMA请求映像


DMA1 各个通道的请求映像


DMA2 各个通道的请求映像


其中 ADC3、SDIO 和 TIM8 的 DMA 请求只在大容量产品中存在,这个在具体项目时 要注意。


三、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”


2. 选择 MCU 和封装


3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)


选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置


4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire


四、DMA1

4.1 配置串口

在 Connectivity 中选择 USART1 设置,并选择 Asynchronous 异步通信


波特率为 115200 Bits/s。传输数据长度为 8 Bit。奇偶检验 None,停止位 1 ,接收和发送都使能。


使能串口接收中断


4.2 配置DMA



点击 DMA Settings 添加 USART1 TX 和 USART1 RX 分别对应DMA1 的通道4和通道5。


  • Priority:
    当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通 道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,DMA1 控制器拥有高于 DMA2 控制器的优先级。

  • Mode:
    Normal 表示单次传输,传输一次后终止传输。
    Circular 表示循环传输,传输完成后又重新开始继续传输,不断循环永不停止。

  • Increment Address:
    Peripheral 表示外设地址自增。
    Memory 表示内存地址自增。
    串口发送数据是将数据不断存进串口的发送数据寄存器(USARTx_TDR)。所以外接的地址是不递增。而内存储器存储的是要发送的数据,所以地址指针要递增才能将所以的数据发送出去。

  • Data Width:
    Byte 一个字节。
    Half Word 半个字,等于两字节。
    Word 一个字,等于四字节。
    串口数据发送寄存器只能存储8bit,每次发送一个字节,所以数据长度选择Byte。

4.3 生成代码

输入项目名和项目路径


选择应用的 IDE 开发环境 MDK-ARM V5


每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。


点击 GENERATE CODE 生成代码

4.4 USART+DMA数据发送

新建一个变量

uint8_t sendBuff[] = 'USART test by DMArn';


在 man.c 中的主循环添加以下代码:

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */

    HAL_UART_Transmit_DMA(&huart1, (uint8_t *)sendBuff, sizeof(sendBuff));

    HAL_Delay(1000);

    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


通过串口助手可以看到在接收区有数据不断的打印输出

注意:如果不开启串口中断,则程序只能发送一次数据,程序不能判断DMA传输是否完成,USART一直处于busy状态。


4.5 USART+DMA数据接收

在 main.c 头部添加全局变量 Buffer

/* Private variables ---------------------------------------------------------*/

UART_HandleTypeDef huart1;


/* USER CODE BEGIN PV */

uint8_t Buffer[1];

/* USER CODE END PV */


在 stm32f1xx_it.c 头部声明全局变量 Buffer

/* External variables --------------------------------------------------------*/

extern UART_HandleTypeDef huart1;


/* USER CODE BEGIN EV */

extern uint8_t Buffer[1];

/* USER CODE END EV */


在 main.c 中,while 循环前,串口初始化后,添加接收中断开启函数,这样在第一次接收到数据的时候才会触发中断。

/**

  * @brief  The application entry point.

  * @retval int

  */

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_DMA_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  HAL_UART_Receive_DMA(&huart1, (uint8_t *)Buffer, 1);

  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


在 stm32f1xx_it.c 这个文件的最下面添加 HAL_UART_RxCpltCallback()

/* USER CODE BEGIN 1 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

    if(huart->Instance == USART1)

    {

        HAL_UART_Receive_DMA(&huart1, (uint8_t *)Buffer, 1);

        HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Buffer, 1);

    }

}

/* USER CODE END 1 */


通过串口助手发送 OK,可以看到接收到 O,这是因为设置的接收数据是一个字符,如果要接收更多字符,请加大 Buffer。


4.6 串口IDLE空闲中断+DMA数据接收

特点:

  • 可以实现任意字符串接收并输出。

  • 在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到数据,即产生IDLE中断。
    在 main.c 中添加以下变量:

uint8_t recvBuff[BUFFER_SIZE];  //接收数据缓存数组

volatile uint8_t recvLength = 0;  //接收一帧数据的长度

volatile uint8_t recvDndFlag = 0; //一帧数据接收完成标志


在 main.h 中添加以下宏定义与变量:

#define BUFFER_SIZE 256

extern uint8_t recvBuff[BUFFER_SIZE];  //接收数据缓存

extern volatile uint8_t recvLength;  //接收一帧数据的长度

extern volatile uint8_t recvDndFlag; //一帧数据接收完成标志


在 main.c 中,while 循环前,串口初始化后,添加空闲中断和DMA接收开启函数,这样在第一次接收到数据的时候才会触发中断。

/**

  * @brief  The application entry point.

  * @retval int

  */

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_DMA_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断

  HAL_UART_Receive_DMA(&huart1, recvBuff, BUFFER_SIZE);

  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


在 stm32f1xx_it.c 这个文件的最下面修改 USART1_IRQHandler()

void USART1_IRQHandler(void)

{

  /* USER CODE BEGIN USART1_IRQn 0 */

    uint32_t tmpFlag = 0;

    uint32_t temp;

    tmpFlag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位

    if((tmpFlag != RESET))//idle标志被置位

    { 

        __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位

        

        HAL_UART_DMAStop(&huart1); //

        temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   

        recvLength  =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数

        recvDndFlag  = 1;   // 接受完成标志位置1    

        HAL_UART_Transmit_DMA(&huart1, recvBuff, recvLength);

        recvLength = 0;//清除计数

        recvDndFlag = 0;//清除接收结束标志位


        memset(recvBuff,0,recvLength);

        HAL_UART_Receive_DMA(&huart1, recvBuff, BUFFER_SIZE);//重新打开DMA接收,不然只能接收一次数据

     }

  /* USER CODE END USART1_IRQn 0 */

  HAL_UART_IRQHandler(&huart1);

  /* USER CODE BEGIN USART1_IRQn 1 */


  /* USER CODE END USART1_IRQn 1 */

}


通过串口助手发送不定长数据


五、注意事项


用户代码要加在 USER CODE BEGIN N 和 USER CODE END N 之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。

关键字:STM32CubeMX  DMA接口 引用地址:STM32CubeMX学习笔记(7)——DMA接口使用

上一篇:STM32CubeMX学习笔记(8)——ADC接口使用
下一篇:STM32CubeMX学习笔记(6)——USART串口使用

推荐阅读最新更新时间:2026-03-25 12:44

基于MPC8260和FPGA的DMA接口设计
引言   在基于软件无线电的某无线通信信号侦收平台的设计中,天线接收到的信号经过变频器处理和A/D变换之后,经过高速通道把采集的信号送入主控板进行数据分发处理。系统的结构框图如图1所示。 图1 主控板的系统结构框图   主控板的硬件核心是嵌入式微处理器MPC8260,负责系统软件的加载、数据的分发以及与外界命令控制的交互。软件上,采用高性能的VxWorks嵌入式实时操作系统。从天线接收到的射频信号经过变频和A/D变换之后作为数据源连接到FPGA,FPGA对接收到的数据进行中频变换和信道估计等预处理后,在CPU的控制下将数据传输到本地内存,最后CPU对数据打包后进行快速分发。因此,将40~50 Mbps的高速数据流从FPGA传给CP
[单片机]
基于MPC8260和FPGA的<font color='red'>DMA</font><font color='red'>接口</font>设计
视频采集中DMA控制的流横式接口设计
引 言    随着计算机技术、多媒体技术以及通信技术的发展,数字视频技术得到了越来越广泛的应用。在数字视频技术的研究中,视频数据传输是一个技术关键。本文针对视频数据流数据量大、实时性要求高的特点,采用流模式传输,将视频采集数据通过DMA从存储资源紧张的片内缓存区搬运至片外sDRAM帧缓冲区,实现图像的高速传输。 利用SoPC(System FPGA上,实现视频图像的采集、存储、传输和显示。采用自定制组件的办法,将多口sDRAM控制器封装成符合流模式规范的一个外设挂在Avalon总线上,非常方便DMAC进行数据的搬运,并大大提高了系统的性能。 1 流模式传输规范    流模式传输是Altera 计数器的基金项目:深圳
[嵌入式]
PSoC3应用于多通讯接口时的DMA设计
        随着上层应用软件的日趋多样化,现在的便携式电子产品对嵌入式芯片的功能需求越来越高,单一或仅可以局部定制的传统芯片已经不能满足需要。因此数字系统和模拟系统都可以根据需要灵活定制成为芯片设计、开发的发展方向。Cypress为满足业界需要继PSoC1之后开发了PSoC3和PSoC5全新可编程模拟和数字嵌入式芯片。其中PSoC3使用基于单循环流水线的高性能8051内核(67MHz/33MIPS),PSoC5则是基于32位ARM Cortex-M3的内核(80MHz/100MIPS);两者都内置闪存、SRAM,支持片外存储器访问,在8、16和32bit应用中同时实现了高集成度和高灵活性。本文重点讲述了PSoC3在多通讯接口设
[手机便携]
Keil5安装+STM32CubeMX安装+VSCode辅助开发教程
本文介绍STM32相关开发工具的安装,包括: Keil5安装 STM32CubeMX安装 VSCode辅助开发 所有需要使用到的安装包下载链接:通过百度网盘分享的文件:embedded-packge.rar 链接:https://pan.baidu.com/s/1XW72C96-WjeZ6hGhTgJ56A?pwd=4jfh 提取码:4jfh 注意:如果你想用VSCode来辅助Keil5开发,网上有很多教程叫你把原来的软件卸载掉,其实没有必要!!!我们只是把VSCode当作代码编辑器,调试和编译交仍然给keil来完成! 视频教程链接: Keil5安装教程_哔哩哔哩_bilibilihttps://www.bilibil
[单片机]
STM32CubeMx 串口通信(下)串口接收
工作环境: STM32CubeMXv6 Keil5 串口调试助手 串口接收相对串口发送而言比较复杂,HAL_UART_Receive是阻塞式的发送,但是我们不可能让一块单片机一直进行监听,通常而言我们都会采用终端的方法完成串口接收。 Cube的基本配置和串口发送是一致的,但最后要添加终端的勾选。 首先打开左侧的下拉框Connectivity,点击USART1选项; 在打开的选单中点击Mode的下拉框,选中Asynchronous; 在下方的配置框中选中Parameter Settings进行配置: Baud Rate:波特率 Word Length:字长 Parity: 奇偶校验 S
[单片机]
基于STM32CUBEMX驱动TMOS模块STHS34PF80(2)----驱动STHS34PF80进行人体检测
概述 STHS34PF80 是一款非冷却、工厂校准的红外运动和存在检测传感器,工作波长在 5 µm 至 20 µm 之间。STHS34PF80 传感器设计用于测量视野内物体发出的红外辐射量。该信息由 ASIC 进行数字处理,可以对其进行编程以监控运动、存在或过热状况。 本章主要驱动STHS34PF80,进行人体检测。 最近在弄ST和瑞萨RA的课程,需要样片的可以加群申请:6_15061293 。 样品申请 https://www.wjx.top/vm/OhcKxJk.aspx# 视频教程 https://www.bilibili.com/video/BV18z4y1g7BA/ 完整代码下载 https://downlo
[单片机]
STM32CUBEMX生成freeRTOS代码的时候出现警告
概述 最近做新项目使用了FREERTOS.1,执行生成代码时提示: WARNINGS: - When FreeRTOS is used, it is strongly recommanded to use HAL timebase source other than the Systick. HAL函数如果是阻塞型呼叫,內部会用到HAL_Delay(),FreeRTOS应该还是使用SystTick。如果使用的时基操作來源一样,怕有不可预期问题出现,故选择其他定时器。 此时在生成代码报错就会消失。
[单片机]
STM32核心知识入门指南:标准库、HAL库与STM32CubeMX零基础详解
初识STM32,那肯定要先了解它是什么,长话短说进入正文! STM32是什么,是一款来自意法半导体公司生产的32位微控制器系列产片,这里小楽就不多介绍了。 那刚接触嵌入式或其他同学就该疑惑了,为什么叫STM32?32位是什么?微控制器(MCU)又是什么?那小楽将一一解答。 各位,各位集中注意力! 一.STM32的介绍 一.微控制器(MCU)是什么 咱来先解决微控制器! 微控制器呢!是一种集成了多种功能模块的 嵌入式专用计算机芯片,广泛应用于各类电子设备的控制场景中。它将很多部件(这里的部件暂时先不急着介绍,容量有点大)集成在单个芯片上,具备完整的最小系统能力,可独立实现特定控制任务。 二.为什么叫STM32与32位是什么
[单片机]
STM32核心知识入门指南:标准库、HAL库与<font color='red'>STM32CubeMX</font>零基础详解
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved