stm32AD单通道与多通道转换(DMA)

发布者:SparklingStar22最新更新时间:2020-11-07 来源: eefocus关键字:stm32  AD单通道  多通道转换  DMA 手机看文章 扫描二维码
随时随地手机看文章

本章的内容分两部分,第一是AD的单通道转换,第二是AD的多通道转换。首先先将单通道转换。


STM32中自带的AD最大的转换频率是14MHZ,共有16个转换通道,每个转


ADC123_IN10表明PC0管脚可以作为AD1,AD2,AD3的第10通道。


下面我们将PC0配置成AD1的通道10为例进行讲解。


3.1首先我们应将PC0设置成模拟输入:


#include "adc.h"


/*为何定义ADC1_DR_Address 为((u32)0x40012400+0x4c)


,因为存放AD转换结果的寄存器的地址就是0x4001244c*/


#define ADC1_DR_Address ((u32)0x40012400+0x4c)


/*定义变量ADC_ConvertedValue,放AD1通道10转换的数据*/


__IO uint16_t ADC_ConvertedValue;


static void ADC1_GPIO_Config(void)


{

GPIO_InitTypeDef GPIO_InitStructure;


/* Enable ADC1 and GPIOC clock */


RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1


RCC_APB2Periph_GPIOC,ENABLE);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;


GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;


GPIO_Init(GPIOC, &GPIO_InitStructure);


}


|


3.2设置完端口后下一步当然是对AD进行初始化:


这里需要补充一个知识点DMA,DMA就相当与CPU的一个秘书,他的作用就是帮CPU减轻负担的。说的再具体点就是帮CPU来转移数据的。我们都知道,AD每次转换结束后会将转换的结果放到一个固定的寄存器里,以往我们如果想将该寄存器中的值赋给某一变量时会用到赋值语句,如果不用DMA,则赋值语句便要CPU来完成,CPU本来就要忙着处理其他事情,现在还要来解决赋值语句这么简单的问题,肯到会蛋疼。所以需要DMA这个秘书来帮他解决这个问题。由于DMA只是个秘书,所以比较笨,你只有把任务交代清楚了她才能很好的完成任务。那么怎样来给DMA吩咐任务呢,聪明的人肯定想到了,那当然是“DMA_Init(DMA1_Channel1, &DMA_InitStructure)”这个函数啦。下面就来一步步的来给DMA交代任务。


/* 函数名:ADC1_Mode_Config


* 描述 :配置ADC1的工作模式为MDA模式


* 输入 : 无


* 输出 :无


* 调用 :内部调用


*/


static void ADC1_Mode_Config(void)


{

DMA_InitTypeDef DMA_InitStructure;


ADC_InitTypeDef ADC_InitStructure;


/* 将与DMA有关的寄存器设我初始值 */


DMA_DeInit(DMA1_Channel1);


/*定义DMA外设基地址, 这里的ADC1_DR_Address 是用户自己定义的,即为存放转换结果的寄存器 ,他的作用就是告诉DMA取数就到ADC1_DR_Address 这里来取。*/


DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address;


/*定义内存基地址,即告诉DMA要将从AD中取来的数放到ADC_ConvertedValue中 */


DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADC_ConvertedValue;


/*定义AD外设作为数据传输的来源,即告诉DMA是将AD中的数据取出放到内存中,不能反过来*/


DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;


/*指定DMA通道的DMA缓存的大小,即告诉DMA开辟几个内存空间,由于我们只取通道10的AD数据所以只需开辟一个内存空间*/


DMA_InitStructure.DMA_BufferSize = 1;


/*设定寄存器地址固定,即告诉DMA,只从固定的一个地方取数*/


DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;


/*设定内存地址固定,即每次DMA,,只将数搬到固定的内存中*/


DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;


/*设定外设数据宽度,即告诉DMA要取的数的大小*/


DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;


/*设定内存的的宽度*/


DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;


/*设定DMA工作再循环缓存模式,即告诉DMA要不停的搬运,不能偷懒*/ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;


/*设定DMA选定的通道软件优先级*/


DMA_InitStructure.DMA_Priority = DMA_Priority_High;


DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;


DMA_Init(DMA1_Channel1, &DMA_InitStructure);


/* Enable DMA channel1,CPU有好几个DMA秘书,现在只用 DMA1_Channel1


这个秘书*/


DMA_Cmd(DMA1_Channel1, ENABLE);


/*设置ADC工作在独立模式*/


ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;


/*规定AD转换工作在单次模式,即对一个通道采样*/


ADC_InitStructure.ADC_ScanConvMode = DISABLE ;


/*设定AD转化在连续模式*/


ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;


/*不使用外部促发转换*/


ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; /*采集的数据在寄存器中以右对齐的方式存放*/


ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;


/*设定要转换的AD通道数目*/


ADC_InitStructure.ADC_NbrOfChannel = 1;


ADC_Init(ADC1, &ADC_InitStructure);


/*配置ADC时钟,为PCLK2的8分频,即9MHz*/


RCC_ADCCLKConfig(RCC_PCLK2_Div8);


/*配置ADC1的通道11为55.5个采样周期 */


ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);


/* Enable ADC1 DMA */


ADC_DMACmd(ADC1, ENABLE);


/* Enable ADC1 */


ADC_Cmd(ADC1, ENABLE);


/*复位校准寄存器 */


ADC_ResetCalibration(ADC1);


/*等待校准寄存器复位完成 */


while(ADC_GetResetCalibrationStatus(ADC1));


/* ADC校准 */


ADC_StartCalibration(ADC1);


/* 等待校准完成*/


while(ADC_GetCalibrationStatus(ADC1));


/* 由于没有采用外部触发,所以使用软件触发ADC转换 */


ADC_SoftwareStartConvCmd(ADC1, ENABLE);


}


配置完以上的程序,那么AD每转换一次,DMA都会将转换结果搬到变量


ADC_ConvertedValue中,而不需用每次都用赋值语句来取值AD转换的值。


第二部分:AD多路采样


#include "adc.h"


#define ADC1_DR_Address ((u32)0x40012400+0x4c)


/*定义数组变量ADC_ConvertedValue[2],分别放AD1通道10和11转换的数据*/


__IO uint16_t ADC_ConvertedValue[2];


/*


* 函数名:ADC1_GPIO_Config


* 描述 :使能ADC1和DMA1的时钟,设置PC0,PC1为模拟输入


* 输入 : 无


* 输出 :无


* 调用 :内部调用


*/


static void ADC1_GPIO_Config(void)


{

GPIO_InitTypeDef GPIO_InitStructure;


/* Enable DMA clock */


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


/* Enable ADC1 and GPIOC clock */


RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC,ENABLE);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;


GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;


GPIO_Init(GPIOC, &GPIO_InitStructure);


}


/* 函数名:ADC1_Mode_Config


* 描述 :配置ADC1的工作模式为MDA模式


* 输入 : 无


* 输出 :无


* 调用 :内部调用


*/


static void ADC1_Mode_Config(void)


{

DMA_InitTypeDef DMA_InitStructure;


ADC_InitTypeDef ADC_InitStructure;


/* DMA channel1 configuration */


DMA_DeInit(DMA1_Channel1);


/*定义DMA外设基地址,即为存放转换结果的寄存器*/


DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address; /*定义内存基地址*/


DMA_InitStructure.DMA_MemoryBaseAddr


=(u32)&ADC_ConvertedValue;


/*定义AD外设作为数据传输的来源*/


DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;


/*指定DMA通道的DMA缓存的大小,即需要开辟几个内存空间,本实验有两个转换通道,所以开辟两个*/


DMA_InitStructure.DMA_BufferSize = 2;


/*设定寄存器地址固定*/


DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /*设定内存地址递加,即每次DMA都是将该外设寄存器中的值传到两个内存空间中*/


DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /*设定外设数据宽度*/


DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;


/*设定内存的的宽度*/


DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;


/*设定DMA工作再循环缓存模式*/


DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;


/*设定DMA选定的通道软件优先级*/


DMA_InitStructure.DMA_Priority = DMA_Priority_High;


DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;


DMA_Init(DMA1_Channel1, &DMA_InitStructure);


/* Enable DMA channel1 */


DMA_Cmd(DMA1_Channel1, ENABLE);


/*设置ADC工作在独立模式*/


ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;


/*规定AD转换工作在扫描模式,即对多个通道采样*/ ADC_InitStructure.ADC_ScanConvMode = ENABLE ;


/*设定AD转化在连续模式*/


ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;


/*不使用外部促发转换*/


ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;


/*采集的数据在寄存器中以右对齐的方式存放*/


ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;


/*设定要转换的AD通道数目*/


ADC_InitStructure.ADC_NbrOfChannel = 2;


ADC_Init(ADC1, &ADC_InitStructure);


/*配置ADC时钟,为PCLK2的8分频,即9MHz*/


RCC_ADCCLKConfig(RCC_PCLK2_Div8);


/*配置ADC1的通道10和11的转换先后顺序以及采样时间为为55.5个采样周期 */


ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);


ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);


/* Enable ADC1 DMA */


ADC_DMACmd(ADC1, ENABLE);


/* Enable ADC1 */


ADC_Cmd(ADC1, ENABLE);


/*复位校准寄存器 */


ADC_ResetCalibration(ADC1);


/*等待校准寄存器复位完成 */


while(ADC_GetResetCalibrationStatus(ADC1));


/* ADC校准 */


ADC_StartCalibration(ADC1);


/* 等待校准完成*/


while(ADC_GetCalibrationStatus(ADC1));


/* 由于没有采用外部触发,所以使用软件触发ADC转换 */


ADC_SoftwareStartConvCmd(ADC1, ENABLE);


}


!!!!!单通道采样与多通道采样的不同点都在


第二段程序中用红色标出来了,注意比较。


总结:DMA就是一个无私奉献的搬运工,想将外设寄存器中的值放入内存中原本需要CPU来完成,现在DMA来帮CPU完成,这在一定程度上解放了CPU.


关键字:stm32  AD单通道  多通道转换  DMA 引用地址:stm32AD单通道与多通道转换(DMA)

上一篇:STM32固件库详解
下一篇:STM32用IO口控制步进电机的简单程序

推荐阅读最新更新时间:2024-11-22 21:12

Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发
概述 Windows下使用Keil MDK5进行 STM32F407VET6 的开发和编译, 配合ST-LINK工具进行烧录, 使用标准外设库SPL. STM32F407硬件环境 主要参数 STM32F407VET6 Arm Cortex-M4 168MHz Max Clock Speed 512k flash 192k ram LQFP 100 pins Backup SRAM 4k STM32F407VET6 Black Board 开发板 具体说明可以查看 https://stm32-base.org/boards/STM32F407VET6-STM32-F4VE-V2.0.html ST-Link 编程器 使用
[单片机]
Keil MDK <font color='red'>STM32</font>系列(三) 基于标准外设库SPL的STM32F407开发
STM32中功能复用重映射是什么意思
就是IO口可以有多种用途,比如可以作为普通的输入输出口使用,也可以作为PWM通道使用,还有DAC通道等 但需要相应的配置。I/O口不可以同时进行这三个功能的使用,只能是配置为什么功能使用相应的功能。
[单片机]
stm32gpio的工作模式
1、推挽输出 可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两个互补 信号 的控制,总是在一个三极管导通的时候另一个截止。高低电平由 IC 的 电源 决定。 推挽电路是两个 参数 相同的三极管或 MOSFET ,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌 电流 ,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。 2、开漏输出 输出端相当于三极管的集电极,要得到高电平状态需要上拉 电阻 才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。 3、浮空输入 对于浮空输
[单片机]
stm32gpio的工作模式
STM32 keil4 extern问题
最近一个项目,在stm32 keil中移植了别人的一些库文件,编译时出现如下错误提示 .OBJW5100_SPI.axf: Error: L6218E: Undefined symbol FLAG_comerr (referred from master.o). .OBJW5100_SPI.axf: Error: L6218E: Undefined symbol adcval (referred from master.o). .OBJW5100_SPI.axf: Error: L6218E: Undefined symbol nzval (referred from master.o). .OBJW5100_SPI.ax
[单片机]
DMA传输实验
DMA简介 DMA(Direct Memory Access)一种直接存储器存取,单片机的一个外设,它的主要功能就是用传输数据的,好处就是传输数据的时候不占用CPU。数据传输的方向有 外设到存储器,存储器到存储器,外设到外设这里的存储器包括SRAM和FLASH。 DMA 的要素 1.DMA请求如果外设想要通过DMA传输数据,必须先给DMA控制器发送DMA请求。DMA收到信号后控制器会给外设发送一个应答信号,当外设收到应答信号且DMA控制器收到应答信号之后,就会启动DMA传输,直到传输完毕 2通道。DMA具有12个独立的可编程通道,每个通道对应不同的外设的DMA请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一
[单片机]
STM32过滤器的作用
STM32普通型芯片的CAN有14组过滤器组(互联型有28组过滤器组),用以对接收到的帧进行过滤。每组过滤器包括了2个可配置的32位寄存器:CAN_FxR0和CAN_FxR1。对于过滤器组,可以将其配置成屏蔽位模式,这样CAN_FxR0中保存的就是标识符匹配值,CAN_FxR1中保存的是屏蔽码,即CAN_FxR1中如果某一位为1,则CAN_FxR0中相应的位必须与收到的帧的标志符中的相应位吻合才能通过过滤器;CAN_FxR1中为0的位表示CAN_FxR0中的相应位可不必与收到的帧进行匹配。过滤器组还可以被配置成标识符列表模式,此时CAN_FxR0和CAN_FxR1中的都是要匹配的标识符,收到的帧的标识符必须与其中的一个吻合才能通过
[单片机]
STM32的外部中断配置
一.配置中断 void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Set the Vector Table base location at 0x08004000 NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000); // 1.分配中断向量表 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级 /* Enable the EXTI1 Interrupt NVIC_InitStructure.NVIC_IRQCha
[单片机]
stm32--虚拟串口--辅助调试工具
在调试串口通信软件时,通常需要接收串口通信的数据,这时会自己编写一个软件模拟发送数据源,然后调试目标程序。两个程序之间通过计算机的物理串口连接通信,而现在的计算机带有两个串口的很少,而笔记本基本都没有串口了,这时可以使用虚拟串口软件,虚拟一对串口,对于我们编写的软件来说和真实的串口完全一样。 猛击下载虚拟串口 运行rar压缩包中的vspdxp_install.exe安装,完成后运行vspdconfig.exe设置串口,如图所示,点击图中Add pair添加COM4与COM5虚拟串口。 完成后可以在计算管理中查看到虚拟串口,如图所示。
[单片机]
stm32--虚拟串口--辅助调试工具
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved