写在前面
在学习这一节知识点的时候,真的是感觉太抽象了,没有一个合适的视频讲的我有那种豁然开朗的感觉,直到我看到了这篇文章,大家可以去看看,里面的描述特别形象。
链接:https://blog.csdn.net/gdjason/article/details/51019219
是什么
DMA —- Directional Memory Access,直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
其中最重要的就是节省了CPU资源。
串口直接收发和DMA结合串口收发比较
串口直接收发数据过程:
接受:
数据通过串口发送到CPU,CPU然后把数据存储到数组里面
发送:
数据存储到数组里面, CPU把数组里面的数据发送到串口
CPU在这一串操作的过程中是会被占用的,不能进行别的操作
DMA和串口结合起来收发数据过程:
发送:
内存中的数据,通过DMA发送到外设,发送完毕,DMA的发送完毕标志清除。
接受:
串口发送数据,DMA把数据取走,然后把数据存储到数组
在这一串操作的过程中,CPU都是空闲的,可以去干别的事情,可以不用管串口的收发
并且不需要担心串口的收发,串口接收DMA在初始化的时候就处于开启状态,然后需要配置一个空闲中断一直等待数据的到来,也就是只要串口接收数据完毕,就会有一个电平变化,然后就可以进入中断,然后我们不需要在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。 也就是只要你打开了DMA通道,探测到电平变化,进入空闲中断,就可以自动进行收发
没听懂用一种更清晰的方法来描述
(来自前方声明的链接博客的描述)
对于DMA,打个比方就很好理解:
角色预设: 淘宝店主 —- STM32 MCU
快递员 —- 外设(如UART,SPI)
发货室 —- DMA
1、首先你是一个淘宝店主,如果每次发货收货都要跟快递沟通交涉会很浪费时间和精力。
2、然后你就自己建了一个发货室,发货室里有好多个货柜箱子,每个箱子上都写着快递名字(如果申通快递,顺丰快递等)。
3、每次发什么快递,你就找到对应的货柜箱子,把货物放进去即可,然后跟快递通知一声。
4、快递取走快件。
5、如果是收货,快递直接把快件放到对应的柜子,然后通知你一下。
6、你过来提取货物。
通过上面的方式,你可以不需要直接跟快递打交道,就可以轻松发货成功,DMA处理方式跟上面例子是一样的。
如果下图:
串口利用DMA配置过程
实战代码
这是本周学习STM32任务之一,任务中少了Send_data[4]和Send_data[5],是接收方的ID

/*------------------------------------------------------下面的就是实现串口和DMA结合的程序包含了利用DMA实现串口的收发-------------------------------------------------------*/#include "sys.h"#include "usart.h" #include "led.h"#include "string.h"#include #include "crc.h"// //如果使用ucos,则包括下面的头文件即可.#if SYSTEM_SUPPORT_OS#include "includes.h" //ucos 使用 #endif //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1#pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; }; FILE __stdout; //定义_sys_exit()以避免使用半主机模式 _sys_exit(int x) { x = x; } //重定义fputc函数 int fputc(int ch, FILE *f){ while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;}#endif /*------------------------------------------------------下面的就是实现串口和DMA结合的程序包含了利用DMA实现串口的收发-------------------------------------------------------*//*--------------------数据包类型-----------------------*/enum//枚举{ WAITING_FF1, //等待1(包头) WAITING_FF2, //等待2(包头) RECEIVE_ID, //接收方id RECEIVE_ExtraID, //接收方扩展ID RECEIVE_LEN, //数据长度 RECEIVE_PACKAGE, //数据包 RECEIVE_CHECK //接收校验位}receive_state_;u8 DMA_Rece_Buf[DMA_Rec_Len]; //DMA接收串口数据缓冲区u16 Usart1_Rec_Cnt=0; //本帧数据长度 u8 DMA_Tx_Buf[DMA_Tx_Len]; //DMA接收串口数据缓冲区u16 Usart1_Tx_Cnt=0; //本帧数据长度 u8 DataBag[3],PWMValue; u8 CRCCODE,CRCCODEdaima; //自己计算的CRC校验码const CRC_8 crc_8_MAXIM = {0x31,0x00,0x00,TRUE,TRUE};//UART1的GPIO初始化void UART1_GPIO_Init(void){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟 //USART1_TX PA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9 //USART1_RX PA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA, &GPIO_
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!