stm32单片机个人学习笔记12(DMA直接存储器存取)

前言

本篇文章属于stm32单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。

STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili

一、DMA

存储器和存储器之间使用软件触发,外设和存储器之间使用硬件触发--比如AD通道的转换,转换完成后再转运 

 存储器映像

 DMA总线来访问外设存储器,内部多个通道实现数据的独立转运,仲裁器用于调度各个通道的转运,AHB从设备用来配置DMA的参数,DMA请求是DMA的触发源

基本结构图 

二、实例一(DMA数据转运) 

MyDMA.c

将DMA使用结构体将所有参数初始化好

调用一次Transfer就转运一次

#include "stm32f10x.h"                  // Device headeruint16_t MyDMA_Size;void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);MyDMA_Size=Size;DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_MemoryInc	= DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = Size;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, DISABLE);
}void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1, DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);DMA_Cmd(DMA1_Channel1, ENABLE);while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);}

main.c 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyDMA.h"uint8_t DataA[]={0x01,0x02,0x03,0x04};
uint8_t DataB[]={0,0,0,0};int main(void)
{OLED_Init();MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);OLED_ShowString(1,1,"DataA");OLED_ShowString(3,1,"DataB");OLED_ShowHexNum(1,8,(uint32_t)DataA,8);OLED_ShowHexNum(3,8,(uint32_t)DataB,8);OLED_ShowHexNum(2,1,DataA[0],2);OLED_ShowHexNum(2,4,DataA[1],2);OLED_ShowHexNum(2,7,DataA[2],2);OLED_ShowHexNum(2,10,DataA[3],2);OLED_ShowHexNum(4,1,DataB[0],2);OLED_ShowHexNum(4,4,DataB[1],2);OLED_ShowHexNum(4,7,DataB[2],2);OLED_ShowHexNum(4,10,DataB[3],2);Delay_ms(1000);while (1){MyDMA_Transfer();DataA[0]++;DataA[1]++;DataA[2]++;DataA[3]++;OLED_ShowHexNum(2,1,DataA[0],2);OLED_ShowHexNum(2,4,DataA[1],2);OLED_ShowHexNum(2,7,DataA[2],2);OLED_ShowHexNum(2,10,DataA[3],2);OLED_ShowHexNum(4,1,DataB[0],2);OLED_ShowHexNum(4,4,DataB[1],2);OLED_ShowHexNum(4,7,DataB[2],2);OLED_ShowHexNum(4,10,DataB[3],2);Delay_ms(1000);}
}

二、实例二(AD多通道+DMA转运)

AD单次转换,扫描模式且DMA单次转运

 AD.c

#include "stm32f10x.h"                  // Device headeruint16_t AD_Value[4];/*** @brief  AD初始化* @param  无* @retval 无*/
void AD_Init(void)
{//开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//ADC预分频RCC_ADCCLKConfig(RCC_PCLK2_Div6);//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//ADC通道选择ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);//ADC初始化ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_NbrOfChannel = 4;ADC_Init(ADC1, &ADC_InitStructure);//DMA初始化DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_MemoryInc	= DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 4;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);//开启ADC到DMA的输出ADC_DMACmd(ADC1, ENABLE);//开启ADC电源ADC_Cmd(ADC1, ENABLE);//ADC校准ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));}/*** @brief  AD获取转换值且DMA开始转运* @param  无* @retval 转换得到的值*/
void AD_Getvalue(void)
{DMA_Cmd(DMA1_Channel1, DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1, 4);DMA_Cmd(DMA1_Channel1, ENABLE);ADC_SoftwareStartConvCmd(ADC1, ENABLE);while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}

 main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"int main(void)
{OLED_Init();AD_Init();OLED_ShowString(1,1,"AD0:");OLED_ShowString(2,1,"AD1:");OLED_ShowString(3,1,"AD2:");OLED_ShowString(4,1,"AD3:");while (1){AD_GetValue();OLED_ShowNum(1,5,AD_Value[0],4);OLED_ShowNum(2,5,AD_Value[1],4);OLED_ShowNum(3,5,AD_Value[2],4);OLED_ShowNum(4,5,AD_Value[3],4);Delay_ms(100);}
}

 

AD多次转换,扫描模式且DMA连续转运  

AD.c 

#include "stm32f10x.h"                  // Device headeruint16_t AD_Value[4];/*** @brief  AD初始化* @param  无* @retval 无*/
void AD_Init(void)
{//开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//ADC预分频RCC_ADCCLKConfig(RCC_PCLK2_Div6);//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//ADC通道选择ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);//ADC初始化ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;ADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_NbrOfChannel = 4;ADC_Init(ADC1, &ADC_InitStructure);//DMA初始化DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_MemoryInc	= DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 4;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);//开启ADC到DMA的输出ADC_DMACmd(ADC1, ENABLE);//开启ADC电源ADC_Cmd(ADC1, ENABLE);//ADC校准ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

 main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"int main(void)
{OLED_Init();AD_Init();OLED_ShowString(1,1,"AD0:");OLED_ShowString(2,1,"AD1:");OLED_ShowString(3,1,"AD2:");OLED_ShowString(4,1,"AD3:");while (1){OLED_ShowNum(1,5,AD_Value[0],4);OLED_ShowNum(2,5,AD_Value[1],4);OLED_ShowNum(3,5,AD_Value[2],4);OLED_ShowNum(4,5,AD_Value[3],4);Delay_ms(100);}
}

 

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

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

相关文章

Java最全面试题->数据库/中间件->RocketMQ面试题

文章目录 RocketMQ多个MQ如何选型?RocketMQ组成部分有哪些?RocketMQ消费模式有几种?消息重复消费如何解决?RocketMQ如何保证消息的顺序消费?RocketMQ如何保证消息不丢失?RocketMQ如何实现分布式事务?RocketMQ的消息堆积如何处理?RocketMQ 下边是我自己整理的面试题,基…

FreeRTOS的事件组

实时嵌入式系统必须对事件做出响应。FreeRTOS允许将事件传递给任务。此类功能的示例包括信号量和队列,两者都具有以下属性: 它们允许任务在“阻塞”状态下等待单个事件发生。  当事件发生时,它们会取消阻塞单个任务——取消阻塞的任务是等待…

【论文阅读】Tabbed Out: Subverting the Android Custom Tab Security Model

论文链接:Tabbed Out: Subverting the Android Custom Tab Security Model | IEEE Conference Publication | IEEE Xplore 总览 “Tabbed Out: Subverting the Android Custom Tab Security Model” 由 Philipp Beer 等人撰写,发表于 2024 年 IEEE Symp…

Pulsar mq 设置延迟消息模式 pulsar mq 发送延迟消息 pulsar如何发送消费延时消息

1. 本文使用spring 提供的pulsarTemplate. 内部对于pulsar client 封装了一层 2.生产者为: String fingerprint UUID.randomUUID().toString();# 可修改TimeUnit 改为小时,天。 pulsarTemplate.newMessage(fingerprint).withTopic("dddd")…

闯关leetcode——222. Count Complete Tree Nodes

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/count-complete-tree-nodes/description/ 内容 Given the root of a complete binary tree, return the number of the nodes in the tree. According to Wikipedia, every level, except possibl…

设计模式基础概念(行为模式):责任链模式(Chain Of Responsibility)

概述 责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。 该模式建议你将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于…

小小猫棒onu替换家用光猫,薅运营商带宽羊毛,突破1000M

小小猫棒onu 一、总体步骤 1 记录原来光猫信息 主要包括SN,ploam密码,loid、loid密码、 mac、上网的vlan id等 一般gpon采用SN、ploam密码、SNploam密码三种中的一种认证方式 一般Epon采用loid(逻辑id)、mac、loid mac三种中…

【Unity 实用工具篇】 | UGUI 循环列表 SuperScrollView,快速上手使用

前言 【Unity 实用工具篇】 | UGUI 循环列表 SuperScrollView,快速上手使用一、UGUI ScrollRect拓展插件:SuperScrollView1.1 介绍1.2 效果展示1.3 使用说明及下载 二、SuperScrollView 快速上手使用2.1 LoopListView22.2 LoopGridView2.3 LoopStaggered…

【Java并发编程】信号量Semaphore详解

一、简介 Semaphore(信号量):是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。 Semaphore 一般用于流量的控制,特别是公共资源有限的应用场景。例如数据库的连接&am…

Spring Boot框架下租房管理系统的设计与实现

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…

9.Linux按键驱动-工作队列

1.思路 1.1在gpio结构体中定义工作队列 1.2 在probe函数中初始化工作队列 1.3.在中断服务程序中调度工作队列 1.4工作队列处理函数&#xff1a; 2.编程 程序&#xff1a; #include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #…

基于微信小程序实现信阳毛尖茶叶商城系统设计与实现

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

xtu 哈希

样例输入# 2 2 1 2 4 1 3 5 7 样例输出# 2 3解题思路&#xff1a;欧拉筛素数 满足题意的素数值一定是从n/2开始的。原因&#xff1a;因为每个哈希函数值最多冲突一次&#xff0c;也就是一个哈希值最多出现2次&#xff0c;最坏的情况&#xff0c;数组中所有哈希值都出现2次&…

【判断推理】逻辑论证之一般质疑

不明确选项&#xff1a;表述不够明确&#xff0c;属于既不能加强、也不能削弱的选项 5.1 无论据有结论的一般质疑 无论据有结论&#xff1a;题干往往由“背景、分析、结论”&#xff0c;用提出反向论据的方式反驳论点。 这类题挺简单的&#xff0c;注意话题一致、主题正确&am…

手机拍证件照,换正装有领衣服及底色的方法

证件照在我们的职业生涯的关键节点是经常会用到的&#xff0c;比如毕业入职、人事档案建立、升迁履历、执业资格考试和领证等&#xff0c;这些重要的证件照往往要求使用正装照&#xff0c;有时候手头没有合适的衣服&#xff0c;或者原先的证件照背景色不符合要求&#xff0c;就…

【Fargo】18:camera获取及预览

QCameraViewfinder.ui Build started at 0:10... 1>------ Build started: Project: Fargo, Configuration: Debug Win32 ------

acaconda基础指令(实用不罗嗦,持续更新)

查看conda版本 conda --version 更新acaconda conda update Anaconda 查看有哪些虚拟环境&#xff08;三条均可&#xff09; conda env listconda info -econda info --envs 创建虚拟环境 conda create -n env_name python3.8 激活虚拟环境 conda activate env_name …

Python图像处理——基于ResNet152的人脸识别签到系统(Pytorch框架)

&#xff08;1&#xff09;数据集制作 本次使用明星做为数据集&#xff0c;首先编写爬虫函数&#xff0c;根据关键字爬取对应的明星&#xff0c;爬取结果保存至data文件夹&#xff0c;并以标签名作为文件名。具体爬取的明星如下&#xff1a; 注&#xff1a;实际应用中&#xf…

【thinkphp8】00005 thinkphp8 Db::table和Db::name的区别

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【th…

FreeRTOS 6:任务创建函数xTaskCreate分析

动态创建任务xTaskCreate xTaskCreate 1、申请堆栈内存&#xff08;返回首地址&#xff09; 2、申请任务控制块内存&#xff08;返回首地址&#xff09; 3、把前面申请的堆栈地址&#xff0c;赋值给控制块的堆栈成员 4、调用prvlnitialiseNewTask初始化任务控制块中的成员 …