ADC简介
- ADC(Analog-Digitial Converter)模拟-数字转化器。
- ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
- 12位逐字逼近型ADC,1us转化时间(1MHz)。
- 输入电压范围:0-3.3V,转化结果范围:0-4095(0到2的12次方-1)。
- 18个输入通道,可测量16个外部(GPIO)和2个内部信号源(内部温度传感器和内部参考电压1.2V)。
- 规则组(常规)和注入组(特殊)两个转换单元。
- 模拟看门狗自动检测输入电压范围。
- STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
- PWM波实现了DAC的功能,PWM只有完全导通和完全断开两种状态(无功率损耗),使用大功率电机,使用PWM比使用DAC更好,PWM挤占了DAC很多应用空间。
- DAC 应用于信号发生器,音频解码器芯片。
逐次逼近型ADC
11. 地址锁存和译码 :这部分用于Enable通道选择开关,ALE用于Enable器件,ADDA、ADDB、ADDC为地址码,输入对应的地址码让通道选择开关选择对应IN0、IN1等等输入。
12. CLOCK、START :CLOCK选择ADC时钟信号、START选择开始信号
13. EOC :ADC完成转化之后输出的信号
14. 逐字逼近寄存器SAR : 通过比较器比较INx,对寄存器中位数逐一比较,大于等一的该位置1,否则置0.,该寄存器十六位,只选择12位作为逐一比较,选择靠右对齐即可。
ADC基本结构
- 开启RCC时钟,包括ADC和GPIO的时钟,ADCCLK分频器也需要配置一下
- 配置GPIO,把需要的GPIO配置成模拟输入的模式
- 配置多路开关,将左边的通道接入到右边的规则组表里(即选择合适通道)
- 配置ADC转化器(结构体配置)
- 如果开启看门狗,在中断输出控制里用ITConfig函数开启对应的中断输出。然后在NIVC里配置优先级(选)
- 开启ADC、校准
规则组常用四种模式
- 单次转化,非扫描模式
- 单次转化,扫描模式
- 连续,非扫描模式
- 连续,扫描模式(使用DMA最好)
代码实现
- 开启RCC时钟,包括ADC和GPIO的时钟,ADCCLK分频器也需要配置一下
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72MHz / 6 = 12MHz
这里开启APB2上的GPIOA、ADC两个外设,ADC外设需要进行分屏输入START
- 配置GPIO,把需要的GPIO配置成模拟输入的模式
GPIO_InitTypeDef GPIO_InitTypeDefStructure;
GPIO_InitTypeDefStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitTypeDefStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitTypeDefStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitTypeDefStructure);
- 配置多路开关,将左边的通道接入到右边的规则组表里(即选择合适通道),这里STM32有一个函数ADC_RegularChannelConfig 可配置通道以及规则组,如何需要配置注入组ADC_InjectedChannelConfig 配置,这里选择配置规则组。
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 55.5 + 12.5 = 68 ADCCLK period
- 配置ADC转化器(结构体配置)选择连续非扫描模式
ADC_InitTypeDef ADC_InitTypeDefStructure;
ADC_InitTypeDefStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitTypeDefStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitTypeDefStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //Non Need EXT(软件触发)
ADC_InitTypeDefStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitTypeDefStructure.ADC_NbrOfChannel = 1; //有多少个序列
ADC_InitTypeDefStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1, &ADC_InitTypeDefStructure);
ADC_Cmd(ADC1, ENABLE);
- 开启ADC、校准(固定搭配)
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
完整代码:
#include "stm32f10x.h" // Device header
/**
******************************************************************************
1、开启RCC时钟,包括ADC和GPIO的时钟,ADCCLK分频器也需要配置一下
2、配置GPIO,把需要的GPIO配置成模拟输入的模式
3、配置多路开关,将左边的通道接入到右边的规则组表里
4、配置ADC转化器(结构体配置)
5、如果开启看门狗,在中断输出控制里用ITConfig函数开启对应的中断输出。然后在NIVC里配置优先级(选)
6、开启ADC、校准
******************************************************************************
*/
uint16_t WatchDogSignal;
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72MHz / 6 = 12MHz
GPIO_InitTypeDef GPIO_InitTypeDefStructure;
GPIO_InitTypeDefStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitTypeDefStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitTypeDefStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitTypeDefStructure);
// 配置规则组
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 55.5 + 12.5 = 68 ADCCLK period
// //非连续单通道
// ADC_InitTypeDef ADC_InitTypeDefStructure;
// ADC_InitTypeDefStructure.ADC_ContinuousConvMode = DISABLE;
// ADC_InitTypeDefStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ADC_InitTypeDefStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //Non Need EXT(软件触发)
// ADC_InitTypeDefStructure.ADC_Mode = ADC_Mode_Independent;
// ADC_InitTypeDefStructure.ADC_NbrOfChannel = 1; //有多少个序列
// ADC_InitTypeDefStructure.ADC_ScanConvMode = DISABLE;
// ADC_Init(ADC1, &ADC_InitTypeDefStructure);
ADC_InitTypeDef ADC_InitTypeDefStructure;
ADC_InitTypeDefStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitTypeDefStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitTypeDefStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //Non Need EXT(软件触发)
ADC_InitTypeDefStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitTypeDefStructure.ADC_NbrOfChannel = 1; //有多少个序列
ADC_InitTypeDefStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1, &ADC_InitTypeDefStructure);
ADC_Cmd(ADC1, ENABLE);
/* 校准 */
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使用软件触发 (连续)非连续需要注释
}
uint16_t AD_GetValue(void)
{
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使用软件触发
// while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 68 period / 12MHz = 5.6us
return ADC_GetConversionValue(ADC1); // 读取寄存器并自动清除EOC标志位
}