文章目录
一、DMA基本概念
DMA(Direct Memory Access,直接存储器访问)是一种允许外设直接与存储器进行数据传输的技术,这样 CPU 不需要参与整个搬运过程,只需在开始和结束时配置和管理,大大提高了系统效率。
整个工作流程大体分为:
1.初始化配置阶段(CPU 参与)
- CPU 告诉 DMA 控制器:
- 数据从哪里来(源地址)
- 要放到哪里去(目标地址)
- 要搬多少数据(传输大小)
- 传输方式(单次/循环/突发等)- 然后启动 DMA
2.传输阶段(CPU 不参与)
- DMA 控制器接管总线的使用权,自动完成源地址 → 目标地址的数据传输。
- CPU 可以同时执行其他任务(并行处理),不用被数据搬运“绑死”。
3.结束阶段(中断通知)
- DMA 传输完成后,触发中断,通知 CPU:“数据搬运完成了,可以处理下一步了。”
二、DMA 的传输模式
- 存储器到存储器(如大块内存拷贝)
- 外设到存储器(如 ADC 采样结果写入内存)
- 存储器到外设(如把内存中的数据送到串口发送寄存器)
- 外设到外设(少见)
三、DMA 工作流程图
1.这个流程图展示了STM32中DMA最经典的工作方式:当一个外设需要交换数据时,它向DMA发出请求,DMA就像一位高效的搬运工,自动在总线上完成数据搬运,整个过程无需CPU核心参与。它涵盖了‘外设到存储器’、‘存储器到外设’和‘外设到外设’这三种模式。
四、什么是 USART?
USART (Universal Synchronous/Asynchronous Receiver/Transmitter) 是一种串行通信接口,常用于微控制器与外部设备(如电脑、传感器、其他MCU等)之间的数据交换。
- 异步模式 (UART): 最常用,不需要时钟线,依靠预先约定好的波特率进行通信。例如:RS-232, TTL串口。
- 同步模式: 需要一条时钟线(SCLK)来同步数据。
- 工作原理: 数据一位一位地顺序传输。发送时,CPU将数据写入发送数据寄存器(TDR),硬件会自动将数据移位发出。接收时,硬件将接收到的位流组合成字节,存入接收数据寄存器(RDR),并产生中断告知CPU。
五、为什么需要 USART + DMA?
将USART和DMA结合,主要是为了解决传统查询和纯中断方式的弊端:
1.查询方式:
CPU不断轮询USART的状态标志位(如TXE, RXNE),效率极低,CPU完全被阻塞,无法执行其他任务。
2.中断方式:
发送: 每发送完一个字节,产生一个中断,CPU需要响应中断并写入下一个字节。对于大量数据发送,中断频率非常高,CPU频繁进出中断上下文,开销很大。
接收: 每接收到一个字节,产生一个中断,CPU需要立刻读取数据寄存器,否则下一个数据可能会覆盖当前数据(Overrun Error)。如果CPU正在处理高优先级任务,可能导致数据丢失。
3.DMA方式 (USART + DMA):
发送: CPU只需一次性将要发送的数据数组地址、长度等信息配置给DMA,DMA就会自动地将内存中的数据逐个搬运到USART的发送数据寄存器中,直到发送完成才通知CPU。整个过程CPU几乎可以完全不管。
接收: CPU只需提前开辟一个接收缓冲区(数组),并将其地址和长度配置给DMA。此后,USART收到的每一个字节都会由DMA自动搬运到指定的内存数组中。只有当整个缓冲区接收满(或一半时,利用半传输中断)时,DMA才通知CPU来处理数据。极大降低了中断频率, 避免了数据丢失。
4.优点:
高效: 极大减少了CPU开销,让CPU可以专注于数据处理、算法等核心任务。
低功耗: CPU在数据传输期间可以进入睡眠模式,降低系统功耗。
高可靠性: 尤其对于高速数据流,DMA方式能更可靠地处理数据,避免因中断延迟导致的数据丢失。
五、STM32CubeMX DMA+USART配置
1.新建工程
1.双击打开桌面下载好的STM32CubeMX,点击File–>New Project,或直接点击ACCEE TO MCU SELECTOR

2.在左边搜索栏里输入使用的芯片型号,右边选中并开始创建

2.设置RCC时钟源
设置高/低速时钟源都由外部晶振产生。

3.设置串口参数
1.串口2参数设置

2.根据实际硬件电路修改GPIO口

3.使能串口2接收中断

3.设置DMA
1.添加DMA接口

2.选择要配置的接口可以选择只配置RX或者TX或两个都配置,根据自己需求来

3.下面DMA框中保持默认即可

到此USART+DMA参数配置结束,主要就是在串口功能的基础上添加DMA功能。
4.时钟配置
1.时钟源设置
默认时钟源是由内部RC振荡器产生,可通过图中按钮进行修改,外部晶振数值取决于实际电路板上的晶振大小.

提示:
- 这里用到的芯片的最大时钟频率是100MHz,有的芯片最大只有72MHz,实际最大频率可通过查看芯片数据手册确定。
2.时钟频率设置

①PLLM—PLL输入时钟分频系数,根据自己需要的系统时钟频率来进行修改
②PLLN—主PLL倍频系数(自动计算)
③PLLP—主PLL分频系数(自动计算)
④SYSCLK—系统时钟
⑤HCLK—AHB总线时钟,由系统时钟SYSCLK 分频得到,一般不分频,等于系统时钟
⑥APB1/APB2 Prescaler—APB1/APB2总线的预分频系数,可根据需要修改
5.工程文件设置
1.工程设置
注:工程路径中不能有中文,否则会输出错误。
库文件要提前下载好,具体方法在 “【STM32CubeMX学习教程】——1.软件安装” 这一篇文章中有提到。

2.代码生成设置

3.点击右上角按钮生成代码,之后会出现下面的窗口,再点击打开工程即可在用keil查看工程代码。

4.编译成功

六、HAL库中常用的USART + DMA相关代码
1.启动DMA传输
uint8_t txBuffer[] = "Hello, World!\r\n";
HAL_UART_Transmit_DMA(&huart2, txBuffer, sizeof(txBuffer) - 1);//-1 排除空值终端
2.发送中断回调函数
//在传输完成回调函数中处理后续工作(可选)
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART2) {
// 发送完成,可以点亮LED或者准备下一包数据
}
}
3.启动DMA接收
// 1. 定义接收缓冲区
#define RX_BUFFER_SIZE 100
uint8_t rxBuffer[RX_BUFFER_SIZE];
HAL_UART_Receive_DMA(&huart2, rxBuffer, RX_BUFFER_SIZE);
4.接收中断回调函数
//处理接收完成中断(可选)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART2) {
// 整个缓冲区接收满了
// 处理数据,然后重新启动接收(因为DMA只触发一次)
processData(rxBuffer, RX_BUFFER_SIZE);
HAL_UART_Receive_DMA(&huart2, rxBuffer, RX_BUFFER_SIZE);
}
}
以上就是本章的全部内容,如果对你有帮助,欢迎点赞支持,谢谢!
7231

被折叠的 条评论
为什么被折叠?



