您的位置:首页 > 教育 > 锐评 > 地方农村电商平台网站设计思路_云南文山邮编_爱站网 关键词挖掘工具站_新闻头条今日要闻最新

地方农村电商平台网站设计思路_云南文山邮编_爱站网 关键词挖掘工具站_新闻头条今日要闻最新

2025/4/16 17:17:13 来源:https://blog.csdn.net/qq_44764442/article/details/147051414  浏览:    关键词:地方农村电商平台网站设计思路_云南文山邮编_爱站网 关键词挖掘工具站_新闻头条今日要闻最新
地方农村电商平台网站设计思路_云南文山邮编_爱站网 关键词挖掘工具站_新闻头条今日要闻最新

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!

本文写于:2025.04.07

STM32开发板学习——第24节: [8-2]DMA数据转运&DMA+AD多通道

  • 前言
  • 开发板说明
  • 引用
  • 解答和科普
  • 一、DMA转运数据
    • 1.1结构体访问地址
    • 1.2DMA配置
  • 二、DMA+AD多通道
  • 问题
  • 总结

前言

   本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
   欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
   在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
   另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!

开发板说明

   本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
   原理图如下
1、开发板原理图
在这里插入图片描述
2、STM32F103C6和51对比
在这里插入图片描述
3、STM32F103C6核心板
在这里插入图片描述

视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。

下图是实物图
在这里插入图片描述

引用

【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
在这里插入图片描述
数据手册
在这里插入图片描述

解答和科普

一、DMA转运数据

1.1结构体访问地址

在这里插入图片描述

uint8_t aa=0x66;
int main(void)
{OLED_Init();OLED_ShowString(1,2,"Hello STM32 MCU");OLED_ShowHexNum(2,1,aa,2);OLED_ShowHexNum(3,1,(uint32_t)&aa,8);	

在这里插入图片描述
可以看到数据被才能到了SRAM区,它的地址是20开头的。由编译器决定。

const uint8_t aa=0x66;

存储在Flash中的,当然不能说是变量了,而应该说是"常量",因为它是不能变的。
在这里插入图片描述
在这里插入图片描述
出现不需要改变的东西,可以存放在Flash中。
在这里插入图片描述
在这里插入图片描述
所以ADC_>DR的地址就是0x4001244C;
在这里插入图片描述

可以看到ADC1的DR寄存器,它的地址是4001 244C,40开头可知它确实是外设寄存器的区域, 这个具体地址4001 244C是固定的哈, 在手册里也可以查到, 首先打开第二章, 看一下这个存储器映像,可以看到ADC1的起始地址是4001 2400, 接着再打开ADC的章节, 看一下最后面这个寄存器总表, 可以看到ADC DR寄存器的地址偏移是4C, 之前ADC1的起始地址是4001 2400, DR是偏移量4C,所以ADC1的DR地址就是4001 244C和我们这里OLED显示的是一样的, 所以如果你想算某个寄存器的地址, 就可以查手册计算一下, 首先查一下这个计算器所在外设的起始地址, 然后再在外设的寄存器总表里查一下偏移, 起始地址加偏移就是这个计算器的实际地址。
我们再来研究一下这个ADC1->DR,是如何知道ADC1 DR寄存器的地址的呢, 这种结构体的方式又是如何访问到寄存器的呢?
在这里插入图片描述
可以看到ADC1就是这个东西, 左边是一个强制类型转换,把ADC1_BASE 转换为了ADC_TypeDef类型的指针, 右边ADC1_BASE就是ADC1的基地值, 基地址就是起始地址的意思, 也就是我们刚才查表看到的4001 2400.
在这里插入图片描述

转到定义看一下ADC1基地址就是APB2外设基地址+0x2400, 再转到定义APB2外设基地址就是外设基地址+0x10000
在这里插入图片描述
在这里插入图片描述
再转到定义外设基地址就是0x40000000, 可以看到上面还有SRAM基地址。
再回过来, 现在基地址有了, 但是基地址加偏移才是计算器的实际地址, 在这里啊, 它使用了一个非常巧妙的方法来实现这个偏移, 就是使用结构体来实现我们跳转到结构体的定义, 可以看到这里是依次定义的各种计算器这个结构体成员的顺序哈, 看一下手册和这个寄存器实际存放的顺序是一一对应的, 如果我们定义一个ADC结构体的指针, 并且指针的地址就是这个外设的起始地址, 那这个结构体的每个成员就会正好映射实际的每个寄存器,
就是在内存的40012400开始的位置, 存放的ADC1的寄存器, 存放顺序是SR、CR1、CR2 等等, 我们定义ADC-TypeDeft这样一个结构体, 那它在内存的存储情况啊,也是SR、CR1、CR2, 如果我指定这个结构体的起始地址就是ADC1外设寄存器的起始地址, 那么这个结构体的内存和外设计算器的内存就会完美重合。我再访问结构体的某个成员。就相当于是访问这个外设的某个寄存器了,这就是STM32,使用结构体来访问寄存器的流程。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

ADC1是结构体指针,指向的是ADC1外设的起始地址,访问结构体成员,就相当于是加一个地址偏移,起始地址加偏移,就是指定的寄存器。
在这里插入图片描述

1.2DMA配置

在这里插入图片描述
初始化第一步,RCC开启DMA的时钟
第二步, 就可以直接调用DMA1_Init初始化这里的各个参数; 那这所有的参数通过一个结构体就可以配置;
好了之后就可以进行开关控制;DMA_Cmd给指定的通道使能就可以完成了。那在这里如果你选择的是硬件触发,不要忘了在对应外设调用一下XXX_DMACmd,开启一下触发信号的输出, 如果你需要DMA的中断,那就调用DMA_ITConfig,开启中断输出, 再在NVIC里配置相应的中断通道,然后写中断函数就行了,中断的配置啊,各个外设都一样,这里结构图我暂时没有画中段的部分啊,最后在运行的过程中,如果转运完成传输计数器清零了,这时再想给传输计数器赋值的话,就DMA失能、写传输计数器、DMA使能,这样就行了. 这就是DMA的编程思路。

在这里插入图片描述

DMAy_Channelx: where y can be 1 or 2 to select the DMA and 

既选择了那个DMA,也选择了是DMA的那个通道,


void MyDMA_Init(uint32_t  ADDrA,uint32_t ADDrB,uint16_t Size)
{RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);		  //配置时钟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);}
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.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();OLED_ShowHexNum(1,1,DataA[0],2);OLED_ShowHexNum(1,4,DataA[1],2);OLED_ShowHexNum(1,7,DataA[2],2);OLED_ShowHexNum(1,10,DataA[3],2);OLED_ShowHexNum(2,1,DataB[0],2);OLED_ShowHexNum(2,4,DataB[1],2);OLED_ShowHexNum(2,7,DataB[2],2);OLED_ShowHexNum(2,10,DataB[3],2);MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);OLED_ShowHexNum(3,1,DataA[0],2);OLED_ShowHexNum(3,4,DataA[1],2);OLED_ShowHexNum(3,7,DataA[2],2);OLED_ShowHexNum(3,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);while(1){}
}

实验现象
在这里插入图片描述

void MyDMA_Tranfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);DMA_Cmd(DMA1_Channel1,ENABLE);
}

main

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.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);while(1){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);MyDMA_Tranfer();	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);}
}

MyDMA.CH

#include "stm32f10x.h"                  // Device headeruint16_t MyDMA_Size;
void MyDMA_Init(uint32_t  ADDrA,uint32_t ADDrB,uint16_t Size)
{MyDMA_Size=Size;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);		  //配置时钟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_Tranfer(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);
}
#ifndef __MyDMA_H
#define __MyDMA_Hvoid MyDMA_Init(uint32_t  ADDrA,uint32_t ADDrB,uint16_t Size);
void MyDMA_Tranfer(void);
#endif

实验现象

DMA转运

在这里插入图片描述

二、DMA+AD多通道

在这里插入图片描述

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_InitStructure.ADC_ScanConvMode=DISABLE;							//扫描模式
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;							//扫描模式

扫描模式

	ADC_InitStructure.ADC_NbrOfChannel=4;								//通道数目:总共用到几个通道

通道数目4个菜
在这里插入图片描述

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

开启那个比如开启ADC1;

函数里面因为现在ADC还是单次模式,所以还需呀软件触发一次ADC开始,因为DMA也是正常的单词模式,所以在触发ADC之前,需要重新写入一下传输计数器,

void AD_GetValue(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1,4);DMA_Cmd(DMA1_Channel1,ENABLE);ADC_SoftwareStartConvCmd(ADC1,ENABLE);							//软件触发,ADC开始转换while (DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}

ADC单次扫描+DMA单次转运的模式

AD.Ch

#include "stm32f10x.h"                  // Device headeruint16_t ADValue[4];
void AD_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);		//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//开启GPIOA的时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);		  //配置时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//分频:72Mhz/6=12MhzGPIO_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_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_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_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)ADValue;						//存储器站点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_DMACmd(ADC1,ENABLE);				//开启那个外设请求进通道ADC_Cmd(ADC1,ENABLE);ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1)== SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1)== SET);
}void AD_GetValue(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1,4);DMA_Cmd(DMA1_Channel1,ENABLE);ADC_SoftwareStartConvCmd(ADC1,ENABLE);							//软件触发,ADC开始转换while (DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}
#ifndef    __AD_H
#define    __AD_Hextern uint16_t ADValue[4];
void AD_Init(void);
void AD_GetValue(void);#endif

main.CH

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include  "AD.h"uint16_t AD0,AD1,AD2,AD3;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,ADValue[0],4);OLED_ShowNum(2,5,ADValue[1],4);OLED_ShowNum(3,5,ADValue[2],4);OLED_ShowNum(4,5,ADValue[3],4);Delay_ms(100);}
}

ADC连续+DMA循环转运
在这里插入图片描述
在这里插入图片描述
当ADC触发之后,ADC连续转换,DMA循环转运,两者一直在工作,始终把最新的转换结果,刷新到SRAM数组中,我们想要数据时候,随时去数组里取就好了,GetValue就不需要了;

#include "stm32f10x.h"                  // Device headeruint16_t ADValue[4];
void AD_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);		//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//开启GPIOA的时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);		  //配置时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//分频:72Mhz/6=12MhzGPIO_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_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_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_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)ADValue;						//存储器站点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_DMACmd(ADC1,ENABLE);				//开启那个外设请求进通道ADC_Cmd(ADC1,ENABLE);ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1)== SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1)== SET);ADC_SoftwareStartConvCmd(ADC1,ENABLE);							//软件触发,ADC开始转换
}

还可以加一个外设,比如定时器,ADC用单次扫描,再用定时器去定时触发,这样就是定时器触发ADC,ADC触发DMA,整个过程完全自动,不需要程序手动进行操作,不用Delay了

可以看到此时硬件外设已经实现了相互配合和高度的自动化哈, 各种操作都是硬件自己完成的, 极大的减轻的软件负担, 软件什么都不需要做, 也不需要进任何中断,硬件自动就把活干完了, 另外这里你还可以再加一个外设,比如定时器ADC用单次扫描,再用定时器去定时触发,这样就是定时器触发ADC, ADC触发DMA整个过程完全自动, 不需要程序手动进行操作,节省软件资源。这就是STM32 中硬件自动化的一大特色啊. 各个外设互相连接, 互相交织, 不再是传统的这样一个CPU单独控制多个独立的外设, 这样的新型结构啊, 而是外设之间互相连接, 互相合作, 形成一个网状结构, 这样在完成某些简单且繁琐的工作的时候, 就不需要CPU来统一调度了, 可以直接通过外设之间的相互配合, 自动完成这些繁琐的工作, 这样不仅可以减轻CPU的负担, 还可以大大提高外设的性能.
在我们之前的学习中, 也经常遇到过这样的设计, 比如定时器的输出可以通向ADC, DAC或其他定时器,ADC的触发源可以来自定时器或外部中断, DMA的触发源可以来自ADC定时器串口等等, 这就是这个STM32 外设互相配合工作的特色。

问题

1、DMA存储器到存储器、外设到存储器、存储器到外设的情况
2、串口发送一批数据,就可以使用DMA进行存储器到外设的转运

总结

本节课主要是学了了DMA转运的过程,如何配置,完成了存储器到存储器的转运,后来还学了外设到存储器主要是和ADC配合一块使用。很复杂的感觉!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com