9第八课ADC模数转换DMA方式.docx
- 文档编号:8837607
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:29
- 大小:310.49KB
9第八课ADC模数转换DMA方式.docx
《9第八课ADC模数转换DMA方式.docx》由会员分享,可在线阅读,更多相关《9第八课ADC模数转换DMA方式.docx(29页珍藏版)》请在冰豆网上搜索。
9第八课ADC模数转换DMA方式
ADC模数转换(DMA方式)
#.1ADC简介
ADC(AnalogtoDigitalConverter),模/数转换器。
在模拟信号需要以数字形式处理、存储或传输时,模/数转换器几乎必不可少。
STM32在片上集成的ADC外设非常强大。
在STM32F103xC、STM32F103xD和STM32F103xE增强型产品,内嵌3个12位的ADC,每个ADC共用多达21个外部通道,可以实现单次或多次扫描转换。
我们使用的STM32开发板用的是STM32F103VET6,属于增强型的CPU,它有18个通道,可测量16个外部和2个内部信号源。
各通道的A/D转换可以单次、连续、扫描或间断模式执行。
ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阈值。
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
#.2STM32的ADC主要技术指标
对于ADC来说,我们最关注的就是它的分辨率、转换速度、ADC类型、参考电压范围。
分辨率
12位分辨率。
不能直接测量负电压,所以没有符号位,即其最小量化单位
。
转换时间
转换时间是可编程的。
采样一次至少要用14个ADC时钟周期,而ADC的时钟频率最高为14MHz,也就是说,它的采样时间最短为1us。
足以胜任中、低频数字示波器的采样工作。
ADC类型
ADC的类型决定了它性能的极限,STM32的是逐次比较型ADC。
参考电压范围
STM32的ADC参考电压输入见表1。
引脚名称
信号类型
注解
VREF+
输入,模拟参考正极
ADC使用的高端/正极参考电压,2.4V≤VREF+≤VDDA
VDDA
(1)
输入,模拟电源
等效于VDD的模拟电源且:
2.4V≤VDDA≤VDD(3.6V)
VREF-
输入,模拟参考负极
ADC使用的低端/负极参考电压,VREF-=VSSA
VSSA
(1)
输入,模拟电源地
等效于VSS的模拟电源地
ADCx_IN[15:
0]
模拟输入信号
16个模拟输入通道
VDDA和VSSA应该分别连接到VDD和VSS。
从图中可知,它的参考电压负极是要接地的,即VREF-=0V。
而参考电压正极的范围为2.4V≦VREF+≦3.6V,所以STM32的ADC是不能直接测量负电压的,而且其输入的电压信号的范围为:
VREF-≦VIN≦VREF+。
当需要测量负电压或测量的电压信号超出范围时,要先经过运算电路进行平移或利用电阻分压。
#.3.ADC工作过程分析
我们以ADC的规则通道转换来进行过程分析。
所有的器件都是围绕中间的模拟至数字转换器部分(下面简称ADC部件)展开的。
它的左端为VREF+、VREF-等ADC参考电压,ADCx_IN0~ADCx_IN15为ADC的输入信号通道,即某些GPIO引脚。
输入信号经过这些通道被送到ADC部件,ADC部件需要受到触发信号才开始进行转换,如:
EXTI外部触发、定时器触发,也可以使用软件触发。
ADC部件接收到触发信号之后,在ADCCLK时钟的驱动下对输入通道的信号进行采样,并进行模数转换,其中ADCCLK是来自ADC预分频器的。
ADC部件转换后的数值被保存到一个16位的规则通道数据寄存器(或注入通道数据寄存器)之中,我们可以通过CPU指令或DMA把它读取到内存(变量)。
模数转换之后,可以触发DMA请求,或者触发ADC的转换结束事件。
如果配置了模拟看门狗,并且采集得的电压大于阈值,会触发看门狗中断。
#.3.1ADC开关控制
通过设置ADC_CR2寄存器的ADON位可给ADC上电。
当第一次设置ADON位时,它将ADC从断电状态下唤醒。
ADC上电延迟一段时间后(TSTAB),再次设置ADON位时开始进行转换。
通过清除ADON位可以停止转换,并将ADC置于断电模式。
在这个模式中,ADC几乎不耗电(仅几个μA)。
#.3.2ADC时钟
由时钟控制器提供的ADCCLK时钟和PCLK2(APB2时钟)同步。
RCC控制器为ADC时钟提供一个专用的可编程预分频器,详见小容量、中容量和大容量产品的复位和时钟控制(RCC)章节。
#.3.3通道选择
有16个多路通道。
可以把转换组织成两组:
规则组和注入组。
在任意多个通道上以任意顺序进行的一系列转换构成成组转换。
例如,可以如下顺序完成转换:
通道3、通道8、通道2、通道2、通道0、通道2、通道2、通道15。
●规则组由多达16个转换组成。
规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。
规则组中转换的总数应写入ADC_SQR1寄存器的L[3:
0]位中。
●注入组由多达4个转换组成。
注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。
注入组里的转换总数目应写入ADC_JSQR寄存器的L[1:
0]位中。
如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉冲将发送到ADC以转换新选择的组。
温度传感器/VREFINT内部通道
温度传感器和通道ADC1_IN16相连接,内部参照电压VREFINT和ADC1_IN17相连接。
可以按注入或规则通道对这两个内部通道进行转换。
注意:
温度传感器和VREFINT只能出现在主ADC1中。
#.3.4单次转换模式
单次转换模式下,ADC只执行一次转换。
该模式既可通过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0。
一旦选择通道的转换完成:
●如果一个规则通道被转换:
─转换数据被储存在16位ADC_DR寄存器中
─EOC(转换结束)标志被设置
─如果设置了EOCIE,则产生中断。
●如果一个注入通道被转换:
─转换数据被储存在16位的ADC_JDRx寄存器中
─JEOC(注入转换结束)标志被设置
─如果设置了JEOCIE位,则产生中断。
然后ADC停止。
#.3.5连续转换模式
在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。
此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。
每个转换后:
●如果一个规则通道被转换:
─转换数据被储存在16位的ADC_DR寄存器中
─EOC(转换结束)标志被设置
─如果设置了EOCIE,则产生中断。
●如果一个注入通道被转换:
─转换数据被储存在16位的ADC_DRJ1寄存器中
─JEOC(注入转换结束)标志被设置
─如果设置了JEOCIE位,则产生中断。
#.3.6时序图
如下图所示,ADC在开始精确转换前需要一个稳定时间TSTAB。
在开始ADC转换和14个时钟周期后,EOC标志被设置,16位ADC数据寄存器包含转换的结果。
#.3.7扫描模式
此模式用来扫描一组模拟通道。
扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。
一旦这个位被设置,ADC扫描所有被ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。
在每个组的每个通道上执行单次转换。
在每个转换结束时,同一组的下一个通道被自动转换。
如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。
如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中。
而注入通道转换的数据总是存储在ADC_JDRx寄存器中。
#.3.8数据对齐
ADC_CR2寄存器中的ALIGN位选择转换后数据储存的对齐方式。
数据可以左对齐或右对齐,如图29和图30所示。
注入组通道转换的数据值已经减去了在ADC_JOFRx寄存器中定义的偏移量,因此结果可以是一个负值。
SEXT位是扩展的符号值。
对于规则组通道,不需减去偏移值,因此只有12个位有效。
#.3.9可编程的通道采样时间
ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:
0]位更改。
每个通道可以分别用不同的时间采样。
总转换时间如下计算:
TCONV=采样时间+12.5个周期。
例如:
当ADCCLK=14MHz,采样时间为1.5周期TCONV=1.5+12.5=14周期=1μs。
#.3.10外部触发转换
转换可以由外部事件触发(例如:
定时器捕获、EXTI线)。
如果设置了EXTTRIG控制位,则外部事件就能够触发转换。
EXTSEL[2:
0]和JEXTSEL2:
0]控制位允许应用程序选择8个可能的事件中的某一个,可以触发规则和注入组的采样。
注意:
当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换。
#.3.11.DMA请求
因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。
只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户指定的目的地址。
注:
只有ADC1和ADC3拥有DMA功能。
由ADC2转化的数据可以通过双ADC模式,利用ADC1的DMA功能传输。
#.3.12ADC中断
规则和注入组转换结束时能产生中断,当模拟看门狗状态位被设置时也能产生中断。
它们都有独立的中断使能位。
注:
ADC1和ADC2的中断映射在同一个中断向量上,而ADC3的中断有自己的中断向量。
ADC_SR寄存器中有2个其他标志,但是它们没有相关联的中断:
●JSTRT(注入组通道转换的启动)
●STRT(规则组通道转换的启动)
表68ADC中断
中断事件
事件标志
使能控制位
规则组转换结束
EOC
EOCIE
注入组转换结束
JEOC
JEOCIE
设置了模拟看门狗状态位
AWD
AWDIE
#.3.13和ADC相关的寄存器
●ADC状态寄存器(ADC_SR)
●ADC控制寄存器1(ADC_CR1)
●ADC控制寄存器2(ADC_CR2)
●ADC采样时间寄存器1(ADC_SMPR1)
●ADC采样时间寄存器2(ADC_SMPR2)
●ADC注入通道数据偏移寄存器x(ADC_JOFRx)(x=1..4)
●ADC看门狗高阀值寄存器(ADC_HTR)
●ADC看门狗低阀值寄存器(ADC_LRT)
●ADC规则序列寄存器1(ADC_SQR1)
●ADC规则序列寄存器2(ADC_SQR2)
●ADC规则序列寄存器3(ADC_SQR3)
●ADC注入序列寄存器(ADC_JSQR)
●ADC注入数据寄存器x(ADC_JDRx)(x=1..4)
●ADC规则数据寄存器(ADC_DR)
具体说明见课本或者stm32手册吧。
#.4.ADC采集数据实例(采用DMA模式)
使用ADC时常常需要不间断采集大量的数据,在一般的器件中会使用中断进行处理,但使用中断的效率还是不够高。
在STM32中,使用ADC时往往采用DMA传输的方式,由DMA把ADC外设转换得的数据传输到SRAM,再进行处理,甚至直接把ADC的数据转移到串口发送给上位机。
本小节对ADC的DMA方式采集数据实例进行讲解,在讲解ADC的同时让读者进一步熟悉DMA的使用。
#.4.1.实验描述及工程文件清单
#.4.2.配置工程环境
本ADC(DMA方式)实验中我们用到了GPIO、RCC、USART、DMA及ADC外设,所以我们先要把以下库文件添加到工程stm32f10x_gpio.c、stm32f10x_rcc.c、stm32f10x_usart.c、stm32f10x_dma.c、stm32f10x_adc.c,添加旧工程中的外设用户文件usart1.c,新建adc.c及adc.h文件,并在stm32f10x_conf.h中把使用到的ST库的头文件注释去掉,见代码清单。
*********************************
#include"stm32f10x_adc.h"
#include"stm32f10x_dma.h"
#include"stm32f10x_gpio.h"
#include"stm32f10x_rcc.h"
#include"stm32f10x_usart.h"
*********************************
#.4.3.main文件
配置好工程环境之后,我们就从main文件开始分析。
**********************************
#include"stm32f10x.h"
#include"usart1.h"
#include"adc.h"
//ADC1转换的电压值通过dma方式传送到SRAM
//外部变量说明,表明该变量在函数的外部定义,但在函数的内部可以使用它们
extern__IOuint16_tADC_ConvertedValue;
//局部变量,用于保存转换后的电压值
floatADC_ConvertedValueLocal;
//软件延时
voidDelay(__IOuint32_tnCount)
{
for(;nCount!
=0;nCount--);
}
intmain(void)
{
/*USART1config*/
USART1_Config();
/*enableadc1andconfigadc1toDMAmode*/
ADC1_Init();
printf("\r\n---这是一个ADC实验(DMA方式)----\r\n");
while
(1)
{
ADC_ConvertedValueLocal=(float)ADC_ConvertedValue/4096*3.3;//读取转换的AD值
printf("\r\nThecurrentADvalue=0x%04X\r\n",ADC_ConvertedValue);
printf("\r\nThecurrentADvalue=%fV\r\n",ADC_ConvertedValueLocal);
Delay(0xffffee);
}
}
*********************************
浏览一遍main函数,在调用了用户函数USART1_Config()及ADC1_Init()配置好串口和ADC之后,就可以直接使用保存了ADC转换值的变量ADC_ConvertedValue了,在main函数中并没有对ADC_ConvertedValue重新赋值,这个变量是在什么时候改变的呢?
除了可能在中断服务函数修改了变量值,就只有DMA有这样的能耐了,而且大家知道,在使用DMA传输时,由于不是内核执行的指令,所以修改变量值是绝对不会出现赋值语句的。
#.4.4.ADC初始化
本实验代码中完全没有使用中断,而ADC及DMA的配置工作都由用户函数ADC1_Init()完成了。
配置完成ADC及DMA后,ADC就不停地采集数据,而DMA自动地把ADC采集得的数据转移至内存中的变量ADC_ConvertedValue中,所以在main函数的while循环中使用的ADC_ConvertedValue都是实时值。
接下来重点分析ADC1_Init()这个函数是如何配置ADC的。
ADC1_Init()函数使能了ADC1,并使ADC1工作于DMA方式。
ADC1_Init()这个函数是由在用户文件adc.c中实现的用户函数。
*************************************************
voidADC1_Init(void)
{
ADC1_GPIO_Config();
ADC1_Mode_Config();
}
*************************************************
ADC1_Init()调用了ADC1_GPIO_Config()和ADC1_Mode_Config()。
这两个函数的作用分别是配置好ADC1所用的I/O端口;配置ADC1初始化及DMA模式。
⏹配置GPIO端口
关于ADC使用的GPIO口配置,见ADC1_GPIO_Config()代码。
************************************
staticvoidADC1_GPIO_Config(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
/*EnableDMAclock*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
/*EnableADC1andGPIOAclock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA,ENABLE);
/*ConfigurePA.0asanaloginput*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_Init(GPIOA,&GPIO_InitStructure);//PA0,输入时不用设置速率
}
*************************************
ADC1_GPIO_Config()代码非常简单,就是使能DMA时钟,GPIO时钟及ADC1时钟。
然后把ADC1的通道0使用的GPIO引脚PA0配置成模拟输入模式,在作为ADC的输入时,必须使用模拟输入。
这里涉及到ADC通道的知识,每个ADC通道都对应着一个GPIO引脚端口,GPIO的引脚在设置为模拟输入模式后可用于模拟电压的输入端。
STM32F103VET6有三个ADC,这三个ADC共用16个外部通道,从《STM32数据手册》的引脚定义可找到ADC的通道与GPIO引脚的关系。
见表10-2。
表中的引脚名称标注中出现的ADC12_INx(x表示4~9或14~15之间的整数),表示这个引脚可以是ADC1_INx或ADC2_INx。
例如:
ADC12_IN9表示这个引脚可以配置为ADC1_IN9,也可以配置为ADC2_IN9。
本实验中使用的PA0对应的默认复用功能为ADC123_IN0,也就是说可以使用ADC1的通道0、ADC2的通道0或ADC3的通道0来采集PA0上的模拟电压数据,我们选择ADC1的通道0来采集。
n配置DMA
ADC模式及其DMA传输方式都是在用户函数ADC1_Mode_Config()中实现的,见ADC1_Mode_Config()函数。
************************************
staticvoidADC1_Mode_Config(void)
{
DMA_InitTypeDefDMA_InitStructure;
ADC_InitTypeDefADC_InitStructure;
/*DMAchannel1configuration*/
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr=ADC1_DR_Address;//ADC1地址
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&ADC_ConvertedValue;//内存地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize=1;
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址固定
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;//内存地址固定
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//半字
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//循环传输
DMA_InitStructure.DMA_Priority=DMA_Priority_High;
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
DMA_Init(DMA1_Channel1,&DMA_InitStructure);
/*EnableDMAchannel1*/
DMA_Cmd(DMA1_Channel1,ENABLE);
/*ADC1configuration*/
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//独立ADC模式
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//禁止扫描模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//开启连续转换模式,即不停的进行adc转换
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不使用外部触发
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//采集数据右对齐
ADC_InitStructure.ADC_NbrOfChannel=1;//要转换的通道数目为1
ADC_Init(ADC1,&ADC_InitStructure);
/*配置ADC时钟,为PCLK2的8分频,即9MHz*/
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
/*配置ADC1通道11的采样周期为55.5¸个采样周期,序列为1*/
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
/*EnableADC1DMA*/
ADC_DMACmd(ADC1,ENABLE);
/*
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 9第八课 ADC模数转换DMA方式 第八 ADC 转换 DMA 方式