一、ADC简介
ADC:Analog-to-Digital Converter的缩写,指模拟/数字转换器。是将连续变量的模拟信号转换为离散的数字信号的器件。
典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。
STM32有三个独立的ADC,ADC1、ADC2和ADC3。
ADC特点:
可配置12位、10位、8位或6位分辨率。
在转换结束、注入转换结束以及发生模拟看门狗或溢出事件时产生中断。
数据对齐以保持内置数据一致性。
电源要求:全速运行时为2.4V到3.6V,慢速运行时为1.8V。
规则通道转换期间可产生DMA请求。
每个ADC都有18个通道,其中外部通道16个。
二、ADC功能框图
(1)电压输入范围
(2)输入通道
每个ADC具有18个通道,其中外部通道16个(ADCx_IN0 ~ ADCx_IN15)。
外部的16个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路。
规则通道:顾名思意,规则通道就是很规矩的意思,我们平时一般使用的就是这个通道。
注入通道:注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转换的时候强行插入要转换的一种
这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。
(3)转换顺序
1》规则通道
2》注入通道
(4)触发源
软件触发:ADC_CR2 :ADON/SWST ART/JSWSTART。
外部事件触发:内部定时器/外部IO 选择:ADC_CR2 :EXTSEL[2:0]和 JEXTSEL[2:0] 激活:ADC_CR2 :EXTEN 和 JEXTEN。
(5)转换时间
转换时间Tconv = 采样时间 + 12个周期数(12位)。
ADC_CLK:ADC模拟电路时钟,由PCLK2(84MHz)经过2/4/6/8分频得到,最大值为36MHz。
采样时间:ADC 需要若干个 ADC_CLK 周期完成对输入的模拟量进行采样,采样的周期数可通过ADC 采样时间寄存器
ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置, ADC_SMPR2控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每个通道
可以分别用不同的时间采样。其中采样周期最小是 3 个,即如果我们要达到最快的采样,那么应该设置采样周期为 3 个周期,这里说的周
期就是 1/ADC_CLK。
每种分辨率的最小转换时间为:(若经过4分频,则ADC_CLK = 21MHz)
12位:3 + 12 = 15个ADC_CLK周期 =15/21us = 0.71us
10位:3 + 10 = 13个ADC_CLK周期 = 13/21us = 0.62us
8位: 3 + 8 = 11个ADC_CLK周期 = 11/21us = 0.52us
6位: 3 + 6 = 9个ADC_CLK周期 = 9/21us = 0.42us
(6)转换方式
1》单次转换模式
2》连续转换模式
3》扫描模式
(7)数据寄存器
ADC 转换后的数据根据转换组的不同,规则组的数据放在规则数据寄存器ADC_DR内,注入组的数据放在注入数据寄存器JDRx
内。如果是使用双重或者三重模式那规矩组的数据是存放在通用规则寄存器 ADC_CDR 内的。
1》规则数据寄存器(ADC_DR)
16位有效,用于存放规则通道转换完的数据。
只有一个规则数据寄存器,多通道采集需要使用中断或DMA。
2》注入数据寄存器(ADC_JDRx,x=1..4)
16位有效,用于存放注入通道转换完的数据。
由4个注入数据寄存器。
3》通用规则寄存器(ADC_CDR)
32位有效,双重或三重ADC使用。
只有一个通过规则寄存器,必须配合DMA使用。
(8)电压转换
1、 电压输入范围为:0~3.3V
2、分辨率为12位
3、最小精度为:3.3/2^12
4、设数字量为X,则有模拟量 Y = (3.3 / 2^12)*X
三、ADC工作模式
(1)独立模式
只有一个ADC工作,可以是ADC1/2/3。
可以单通道,可以多通道。
转换后的数据放在规则数据寄存器ADC_DR中,可以采用中断或者DMA接收数据。
只用当一个点完成后,才会进行下一个点。
(2)双重规则同步模式
规则指的是只适用于规则通道,注入通道不行。
同步指的是两个/三个ADC同时采集多个通道,比如示波器的双通道同时采集。
不要在同步模式时采集同一个通道。
转换后的数据放在规则数据寄存器ADC_DR中,必须采用DMA接收数据。
(3)多重交替模式
交替模式只能用于规则组,通常只有一个通道,在一个ADC转换的时候,另一个ADC又开始采集,这样可以提高ADC的采样率,最高为6M。
数据传输时使用DMA模式2,当有两个数据项可用时(32bit),生成一个DMA请求。
转换后的数据放在通用规则数据寄存器ADC_CDR中,必须采用DMA接收数据。
四、初始化结构体
typedef struct
{
uint32_t ADC_Resolution; //配置ADC的分辨率,可选的分辨率有12/10/8/6位。
ADC_Resolution_12b
ADC_Resolution_10b
ADC_Resolution_8b
ADC_Resolution_6b
FunctionalState ADC_ScanConvMode; //配置是否使用扫描模式,单通道DISABLE,双通道ENABLE。
FunctionalState ADC_ContinuousConvMode; //配置是连续转换还是单次转换。连续转换ENABLE,单次转换DISABLE。
uint32_t ADC_ExternalTrigConvEdge; //外部触发极性选择。
ADC_ExternalTrigConvEdge_None (禁止触发检测)
ADC_ExternalTrigConvEdge_Rising(上升沿触发检测)
ADC_ExternalTrigConvEdge_Falling(下降沿触发检测)
ADC_ExternalTrigConvEdge_RisingFalling(上升沿和下降均可触发检测)
uint32_t ADC_ExternalTrigConv; //外部触发选择,一般使用软件自动触发。
uint32_t ADC_DataAlign; //转换结果数据对齐模式。
ADC_DataAlign_Right(右对齐)
ADC_DataAlign_Left(左对齐)
uint8_t ADC_NbrOfConversion; //AD转换通道数目。1 ~ 16
}ADC_InitTypeDef;
typedef struct
{
uint32_t ADC_Mode; //ADC工作模式选择,有独立模式、双重模式及三重模式。
ADC_Mode_Independent(独立模式)
ADC_DualMode_RegSimult_InjecSimult
ADC_DualMode_RegSimult_AlterTrig
ADC_DualMode_InjecSimult
ADC_DualMode_RegSimult
ADC_DualMode_Interl
ADC_DualMode_AlterTrig
ADC_TripleMode_RegSimult_InjecSimult
ADC_TripleMode_RegSimult_AlterTrig
ADC_TripleMode_InjecSimult
ADC_TripleMode_RegSimult
ADC_TripleMode_Interl
ADC_TripleMode_AlterTrig
uint32_t ADC_Prescaler; //ADC时钟分频系数选择,ADC时钟是PCLK2分频而来,分频系数决定ADC时钟频率。
ADC_Prescaler_Div2(2分频)
ADC_Prescaler_Div4(4分频)
ADC_Prescaler_Div6(6分频)
ADC_Prescaler_Div8(8分频)
uint32_t ADC_DMAAccessMode; //DMA模式设置,只有在双重或者三重模式才需要设置。
ADC_DMAAccessMode_Disabled
ADC_DMAAccessMode_1
ADC_DMAAccessMode_2
ADC_DMAAccessMode_3
uint32_t ADC_TwoSamplingDelay; //两个采样阶段之间的延迟,仅适用于双重或三重交错模式。
ADC_TwoSamplingDelay_5Cycles
ADC_TwoSamplingDelay_6Cycles
ADC_TwoSamplingDelay_7Cycles
ADC_TwoSamplingDelay_8Cycles
ADC_TwoSamplingDelay_9Cycles
ADC_TwoSamplingDelay_10Cycles
ADC_TwoSamplingDelay_11Cycles
ADC_TwoSamplingDelay_12Cycles
ADC_TwoSamplingDelay_13Cycles
ADC_TwoSamplingDelay_14Cycles
ADC_TwoSamplingDelay_15Cycles
ADC_TwoSamplingDelay_16Cycles
ADC_TwoSamplingDelay_17Cycles
ADC_TwoSamplingDelay_18Cycles
ADC_TwoSamplingDelay_19Cycles
ADC_TwoSamplingDelay_20Cycles
}ADC_CommonInitTypeDef;
五、常用固件库函数
(1)通用初始化
void ADC_CommonInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct);
(2)特定ADC初始化
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
(3)配置规则通道的转换顺序
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
(4)使能ADC
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
(5)软件开启转换
void ADC_SoftwareStartConv(ADC_TypeDef* ADCx);
(6)获取转换结果
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
(7)单重ADC DMA请求
void ADC_DMARequestAfterLastTransferCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
(8)多重ADC DMA请求
void ADC_MultiModeDMARequestAfterLastTransferCmd(FunctionalState NewState);
六、程序
(1)"独立模式---单通道---中断读取数据" 实验
bsp.adc.h文件
#ifndef __ADC_H__
#define __ADC_H__
#include "stm32f4xx_conf.h"
void ADC_Config(void);
uint16_t ADC_GetValue(void);
#endif
bsp.adc.c文件
#include "./ADC/adc.h"
/******************************
功能:配置ADC
参数:无
返回值:无
*******************************/
void ADC_Config(void)
{
GPIO_InitTypeDef initValue;
ADC_CommonInitTypeDef commonInitValue;
ADC_InitTypeDef adcInitValue;
/*1、打开时钟(GPIO和ADC)*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
/*2、配置GPIO的模拟输入功能*/
initValue.GPIO_Mode = GPIO_Mode_AIN;
initValue.GPIO_Pin = GPIO_Pin_5;
initValue.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA,&initValue);
/*2、复位ADC*/
ADC_DeInit();
/*3、初始化通用ADC*/
commonInitValue.ADC_DMAAccessMode = DISABLE;
commonInitValue.ADC_Mode = ADC_Mode_Independent;
commonInitValue.ADC_Prescaler = ADC_Prescaler_Div4;
commonInitValue.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&commonInitValue);
/*4、初始化ADC1*/
adcInitValue.ADC_ContinuousConvMode = DISABLE;
adcInitValue.ADC_DataAlign = ADC_DataAlign_Right;
//adcInitValue.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
adcInitValue.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adcInitValue.ADC_NbrOfConversion = 1;
adcInitValue.ADC_Resolution = ADC_Resolution_12b;
adcInitValue.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1,&adcInitValue);
/*5、使能ADC*/
ADC_Cmd(ADC1,ENABLE);
/*6、配置通道转换顺序*/
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_56Cycles);
/*7、开启软件转换*/
ADC_SoftwareStartConv(ADC1);
/*8、等待转换完成*/
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
}
/******************************
功能:获取转换后的数据
参数:无
返回值:转换后的数据
*******************************/
uint16_t ADC_GetValue(void)
{
return ADC_GetConversionValue(ADC1);
}
main.c文件
#include "delay.h"
#include "stdio.h"
#include "./USART/usart.h"
#include "./ADC/adc.h"
int main(void)
{
uint16_t value;
//初始化延时函数
delay_init(168);
//初始化串口
USART_Config();
//初始化ADC
ADC_Config();
while(1)
{
value = ADC_GetValue();
//打印ADC转换后的数据
printf("转换后的值 = %d \r\n",value);
//将转换后的数据还原为电压值
printf("电压值 = %f \r\n",(float)value*(3.3/4096));
delay_ms(2000);
printf("\r\n");
}
}