STM32——DMA

news2024/11/15 8:52:32

STM32——DMA

1.DMA介绍

什么是DMA?

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

DMA是一个数据搬运工

DMA的意义

代替 CPU 搬运数据,为 CPU 减负。

  1. 数据搬运的工作比较耗时间;

  2. 数据搬运工作时效要求高(有数据来就要搬走);

  3. 没啥技术含量(CPU 节约出来的时间可以处理更重要的事)。

搬运什么数据?

存储器、外设

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

三种搬运方式:

  • 存储器→存储器(例如:复制某特别大的数据buf)
  • 存储器→外设 (例如:将某数据buf写入串口TDR寄存器)
  • 外设→存储器 (例如:将串口RDR寄存器写入某数据buf)

存储器→存储器
在这里插入图片描述

存储器->外设
在这里插入图片描述

外设->存储器
在这里插入图片描述

2.实验一、内存到内存搬运

实验要求

使用DMA的方式将数组A的内容复制到数组B中,搬运完之后将数组B的内容打印到屏幕。

用到的库函数

  1. HAL_DMA_Start
HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress,
uint32_t DstAddress, uint32_t DataLength)

参数一:DMA_HandleTypeDef *hdma,DMA通道句柄

参数二:uint32_t SrcAddress,源内存地址

参数三:uint32_t DstAddress,目标内存地址

参数四:uint32_t DataLength,传输数据长度。注意:需要乘以sizeof(uint32_t)

返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

  1. __HAL_DMA_GET_FLAG
#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__) (DMA1->ISR & (__FLAG__))

参数一:HANDLE,DMA通道句柄

参数二:FLAG,数据传输标志。DMA_FLAG_TCx表示数据传输完成标志

返回值:FLAG的值(SET/RESET)

代码实现

  1. 开启数据传输

  2. 等待数据传输完成

  3. 打印数组内容

#define BUF_SIZE 16
// 源数组
uint32_t srcBuf[BUF_SIZE] = {
    0x00000000,0x11111111,0x22222222,0x33333333,
    0x44444444,0x55555555,0x66666666,0x77777777,
    0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,
    0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF
};
// 目标数组
uint32_t desBuf[BUF_SIZE];
int fputc(int ch, FILE *f)
{
    unsigned char temp[1]={ch};
    HAL_UART_Transmit(&huart1,temp,1,0xffff);
    return ch;
}
main函数里:
    // 开启数据传输
    HAL_DMA_Start(&hdma_memtomem_dma1_channel1,
                  (uint32_t)srcBuf, (uint32_t)desBuf, sizeof(uint32_t) * BUF_SIZE);
// 等待数据传输完成
while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1) == RESET);
// 打印数组内容
for (i = 0; i < BUF_SIZE; i++)
    printf("Buf[%d] = %X\r\n", i, desBuf[i]);

3.实验二、内存到外设搬运

实验要求

使用DMA的方式将内存数据搬运到串口1发送寄存器,同时闪烁LED1。

用到的库函数

HAL_UART_Transmit_DMA

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData,
uint16_t Size)

参数一:UART_HandleTypeDef *huart,串口句柄

参数二:uint8_t *pData,待发送数据首地址

参数三:uint16_t Size,待发送数据长度

返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

代码实现

  1. 准备数据

  2. 将数据通过串口DMA发送

#define BUF_SIZE 1000
// 待发送的数据
unsigned char sendBuf[BUF_SIZE];
main函数里
    // 准备数据
    for (i = 0; i < BUF_SIZE; i++)
        sendBuf[i] = 'A';
// 将数据通过串口DMA发送
HAL_UART_Transmit_DMA(&huart1, sendBuf, BUF_SIZE);
while (1)
{
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
    HAL_Delay(100);
}

3.外设到内存搬运

实验要求

使用DMA的方式将串口接收缓存寄存器的值搬运到内存中,同时闪烁LED1。

用到的库函数

  1. __HAL_UART_ENABLE
#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((((__INTERRUPT__) >> 28U)
== UART_CR1_REG_INDEX)? ((__HANDLE__)->Instance->CR1 |= ((__INTERRUPT__) &
                                                         UART_IT_MASK)): \
    (((__INTERRUPT__) >> 28U)
     == UART_CR2_REG_INDEX)? ((__HANDLE__)->Instance->CR2 |= ((__INTERRUPT__) &
                                                              UART_IT_MASK)): \
    ((__HANDLE__)->Instance-
     >CR3 |= ((__INTERRUPT__) & UART_IT_MASK)))

参数一:HANDLE,串口句柄

参数二:INTERRUPT,需要使能的中断

返回值:无

  1. HAL_UART_Receive_DMA
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData,uint16_t Size)

参数一:UART_HandleTypeDef *huart,串口句柄

参数二:uint8_t *pData,接收缓存首地址

参数三:uint16_t Size,接收缓存长度

返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

  1. __HAL_UART_GET_FLAG
#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR &
(__FLAG__)) == (__FLAG__))

参数一:HANDLE,串口句柄

参数二:FLAG,需要查看的FLAG

返回值:FLAG的值

  1. __HAL_UART_CLEAR_IDLEFLAG
#define__HAL_UART_CLEAR_IDLEFLAG(__HANDLE__)__HAL_UART_CLEAR_PEFLAG(__HANDLE__)

参数一:HANDLE,串口句柄

返回值:无

  1. HAL_UART_DMAStop
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)

参数一:UART_HandleTypeDef *huart,串口句柄

返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

  1. __HAL_DMA_GET_COUNTER
#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->CNDTR)

参数一:HANDLE,串口句柄

返回值:未传输数据大小

代码实现

main.c

uint8_t rcvBuf[BUF_SIZE]; // 接收数据缓存数组
uint8_t rcvLen = 0; // 接收一帧数据的长度
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 使能IDLE空闲中断
HAL_UART_Receive_DMA(&huart1,rcvBuf,100); // 使能DMA接收中断
while (1)
{
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
    HAL_Delay(300);
}

main.h

#define BUF_SIZE 100

stm32f1xx_it.c

extern uint8_t rcvBuf[BUF_SIZE];
extern uint8_t rcvLen;
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 */
    if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) == SET)) // 判断IDLE标志位是否被置位
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);// 清除标志位
        HAL_UART_DMAStop(&huart1); // 停止DMA传输,防止干扰
        uint8_t temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
        rcvLen = BUF_SIZE - temp; //计算数据长度
        HAL_UART_Transmit_DMA(&huart1, rcvBuf, rcvLen);//发送数据
        HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE);//开启DMA
    }
    /* USER CODE END USART1_IRQn 1 */
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1423024.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言应用实例——贪吃蛇

&#xff08;图片由AI生成&#xff09; 0.贪吃蛇游戏背景 贪吃蛇游戏&#xff0c;最早可以追溯到1976年的“Blockade”游戏&#xff0c;是电子游戏历史上的一个经典。在这款游戏中&#xff0c;玩家操作一个不断增长的蛇&#xff0c;目标是吃掉出现在屏幕上的食物&#xff0c…

shell - 免交互

一.Here Document 免交互 1. 交互的概念 交互&#xff1a;当计算机播放某多媒体程序的时候&#xff0c;编程人员可以发出指令控制该程序的运行&#xff0c;而不是程序单方面执行下去&#xff0c;程序在接受到编程人员相应的指令后而相应地做出反应。 对于Linux操作系统中&…

【RT-DETR有效改进】Bi-FPN高效的双向特征金字塔网络(附yaml文件+完整代码)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的改进机制是BiFPN双向特征金字塔网络,其是一种特征融合层的结构,也就是我们本文改进RT-DETR模型中的Neck部分,它的主要思想是通过多层级的特征金字塔和双向信息传递来提高精度。本文给大家带…

零基础爬什么值得买的榜单——爬虫练习题目一(答一)

完蛋 蚌埠住了 引言日常吐槽言归正传 步骤一分析网页分析网络加载详细说说网络面板实际操作 测试代码测试结果知识点JS和Fetch/XHR是什么&#xff1f;有什么关联&#xff1f;网页数据的中文为什么是16进制数&#xff0c;以及如何判断&#xff1f; 结尾 引言 日常吐槽 今天剪辑…

力扣题目训练(5)

2024年1月29日力扣题目训练 2024年1月29日力扣题目训练345. 反转字符串中的元音字母349. 两个数组的交集350. 两个数组的交集 II96. 不同的二叉搜索树97. 交错字符串44. 通配符匹配 2024年1月29日力扣题目训练 2024年1月29日第五天编程训练&#xff0c;今天主要是进行一些题训…

回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于OOA-LSSVM鱼鹰算法优化最小…

Windows断开映射磁盘提示“此网络连接不存在”,并且该磁盘直在资源管理器中

1、打开注册表编辑器 快捷键winR 打开“运行”&#xff0c; 输入 regedit 2、 删除下列注册表中和无法移除的磁盘相关的选项 \HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\ 3、打开“任务管理器”&#xff0c;重新启动“Windows资源…

C++指针比较

内存中各个数据的存放方式。 数组str1、str2、str3、str4都是在栈中分配的&#xff0c;内存中的内容都为“abc”加一个“\0”&#xff0c;但是他们的位置是不同的&#xff0c;因此代码第15行和第16行输出的都是0. 指针str5、str6、str7、str8也是在栈中分配的&#xff0c;他们…

Shell中的awk

一、awk 1.1.awk工作原理 逐行读取文本&#xff0c;默认以空格或tab键为分隔符进行分隔&#xff0c;将分隔所得的各个字段保存到内建变量中&#xff0c;并按模式或者条件执行编辑命令。 awk倾向于将一行分成多个"字段"然后再进行处理。 awk信息的读入也是逐行读取…

Apple Vision Pro 评测:这款顶尖头显仅是对未来的初步探索

原文&#xff1a;Apple Vision Pro Review: The Best Headset Yet Is Just a Glimpse of the Future 作者&#xff1a;Joanna Stern 戴上 Apple Vision Pro 混合现实头显整整近 24 小时后&#xff0c;有几件事让我颇感意外&#xff1a; 我居然没感到恶心。我竟然高效完成了大…

springboot---四大核心

四大核心 Starter简介总结 Autoconfigure简介示例原理自定义starter打包实践 总结 CLIActuator Starter 简介 springboot项目中几乎项目依赖中基本上全是各种各样的starter, 那么到底什么是starter? starter是一组方便的依赖描述符&#xff0c;当我们使用它时&#xff0c;可…

推荐系统|排序_多目标模型

文章目录 四大特征用户特征物品特征统计特征场景特征 训练过程中会遇到的问题 四大特征 ID相当于是人拥有的身份证&#xff0c;能够唯一确定出一个人 用户特征 主要指的是用户ID和用户画像 物品特征 主要是指物品ID和物品画像以及物品持有人。 统计特征 统计特征既包括对…

Java并发基础:CompletionService全面解析!

内容概要 CompletionService的优点在于能够解耦任务提交与结果获取&#xff0c;有效的整合线程池与阻塞队列&#xff0c;实现任务完成顺序的处理&#xff0c;提升系统吞吐量&#xff0c;它简化了多线程编程的复杂性&#xff0c;使开发者能够更专注于业务逻辑&#xff0c;而不必…

【昕宝爸爸小模块】深入浅出详解之常见的语法糖

深入浅出详解之常见的语法糖 一、&#x1f7e2;关于语法糖的典型解析二、&#x1f7e2;如何解语法糖&#xff1f;2.1&#x1f7e2;糖块一、switch 支持 String 与枚举2.2&#x1f4d9;糖块二、泛型2.3&#x1f4dd;糖块三、自动装箱与拆箱2.4&#x1f341;糖块四、方法变长参数…

TOP100 矩阵

1.73. 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 提示&#xff1a; m matrix.lengthn matrix[0].length1 < m, n < 200-2^31 < matrix[i][j] < 2^31 - 1 思路&#xf…

宏景eHR FrCodeAddTreeServlet SQL注入漏洞复现

前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 一、产…

【排序算法】C语言实现随机快排,巨详细讲解

文章目录 &#x1f680;前言&#x1f680;快排的核心过程partition&#xff08;划分过程&#xff09;&#x1f680;快排1.0&#x1f680;随机快速排序&#x1f680;稳定性 &#x1f680;前言 铁子们好啊&#xff01;继续我们排序算法今天要讲的是快排&#xff0c;通常大家所说…

❤搭建一个Springboot项目(ltbjava)

❤从0实现一个项目 搭建好我们的java环境和运行的IDEA软件以后&#xff0c;接下来我们就应该实现一个自己的项目了 0 项目描述 基于jdk17 的学习&#xff0c;因为据说最新的spring框架的最低要求是jdk17Maven 3.8.7PS&#xff1a;springboot3.0版本以上必须用jdk171、 项目创…

STM32F407移植OpenHarmony笔记6

继上一篇笔记&#xff0c;编译好STM32的裸机程序&#xff0c;能点亮LED灯了。 下一步就是启动liteos_m内核了。 不过为了更好的调试代码&#xff0c;需要先把printf重定向到串口&#xff0c;基于gcc的printf重定向和Keil不一样。 直接新建printf.c&#xff0c;在里面重写printf…

摄像头监控系统/视频监控云平台EasyCVR接入单兵设备后如何配置移动规矩

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体控可实现视频监控直播、视频轮播、视频录像…