1、ADC简介
2、逐次逼近型ADC
3、 ADC框图
左边ADC输入通道16个GPIO口,IN0~IN15和两个内部通道,一个温度传感器,一个VREFINT(V Reference Internal),内部参考电压。
模式转换器执行的就是逐次比较的工程,然后转换结果放在数据寄存器中。
规则通道虽然能有十六组数据,但是寄存器只能存储最后一组,前面的都会被覆盖。需要结合DMA使用。
RCC为72M时,ADC预分频只能6分频12M或者8分频9M。
4、ADC基本结构
5、 输入通道与引脚复用关系
通道 | ADC1 | ADC2 | ADC3 |
通道0 | PA0 | PA0 | PA0 |
通道1 | PA1 | PA1 | PA1 |
通道2 | PA2 | PA2 | PA2 |
通道3 | PA3 | PA3 | PA3 |
通道4 | PA4 | PA4 | PF6 |
通道5 | PA5 | PA5 | PF7 |
通道6 | PA6 | PA6 | PF8 |
通道7 | PA7 | PA7 | PF9 |
通道8 | PB0 | PB0 | PF10 |
通道9 | PB1 | PB1 | |
通道10 | PC0 | PC0 | PC0 |
通道11 | PC1 | PC1 | PC1 |
通道12 | PC2 | PC2 | PC2 |
通道13 | PC3 | PC3 | PC3 |
通道14 | PC4 | PC4 | |
通道15 | PC5 | PC5 | |
通道16 | 温度传感器 | ||
通道17 | 内部参考电压 |
6、转换模式
单次非扫描
在序列1定义通道2触发转换,然后模拟电压转换为数字信号,存储在寄存器里,同时,EOC标志置1。然后在想使用,同上。
连续转换非扫描
优点,开始转换后一直转换,不需要手动开始转换
单次转换扫描模式
在初始化的时候,需要给予通道数目,转换后需要多次读取数据防止覆盖结合DMC来使用产生EOC信号,,转换结束,下次手动开启。
连续转换扫描模式
7、触发控制
8、 数据对齐
常用右对齐,左对齐左移得到的数据较大。
9、 转换时间
TCONV = 采样时间 + 12.5个ADC周期
TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
10、校准
•ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
•建议在每次上电后执行一次校准
•启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
11、ADC单通道采集
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue;
float Voltage;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(0,0,"ADValue:");
OLED_ShowString(0,3,"Volatge: . V");
while (1)
{
ADValue=AD_GetValue();
Voltage=(float)ADValue/4095*3.3;
OLED_ShowNum(60,0,ADValue,5,16);
OLED_ShowNum(62,3,Voltage/1000,1,16);
OLED_ShowNum(75,3,(uint16_t)(Voltage*100)%100,2,16);
}
}
AD.C
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC是APB2上的设备
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK六分频在RCC.H里面找680
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AIN;//ADC专属模式,在AIN模式下GPIO口无效,防止干扰
GPIO_Initstructure.GPIO_Pin=GPIO_Pin_0;
GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure);
/************选择规则组输入通道***********/
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1, ADC_SampleTime_55Cycles5);
//规则组菜单第一个位置写入通道0,采样时间为55.5个ADCCLK的周期
/************用结构体初始化ADC************/
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//连续转换模式:
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right ;//数据对齐:右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部触发控制的触发源:内部触发,软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent ;//工作模式:独立模式
ADC_InitStructure.ADC_NbrOfChannel = 1;//通道数目
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描转换模式:
ADC_Init(ADC1,&ADC_InitStructure);
/************开启ADC电源************/
ADC_Cmd(ADC1,ENABLE);
/************ADC进行校准************/
ADC_ResetCalibration(ADC1);//四步骤:复位校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
ADC_StartCalibration(ADC1);//开始校准
while (ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
}
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换函数
while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//获取EOC标志位状态:规则组转换完成标志位
//大概等待5.6us,1/12M*(55.5+12.5)=5.6us
return ADC_GetConversionValue(ADC1);
}
12、多通道
main
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
#include "LED.h"
uint16_t AD0,AD1;
int main(void)
{
OLED_Init();
AD_Init();
LED_Init();
OLED_ShowString(0,0,"AD0:");
OLED_ShowString(0,3,"AD1:");
while (1)
{
AD0=AD_GetValue(ADC_Channel_0);
AD1=AD_GetValue(ADC_Channel_1);
OLED_ShowNum(60,0,AD0,5,16);
OLED_ShowNum(60,3,AD1,5,16);
Delay_ms(100);
}
}
AD
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC是APB2上的设备
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK六分频在RCC.H里面找680
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AIN;//ADC专属模式,在AIN模式下GPIO口无效,防止干扰
GPIO_Initstructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure);
/************选择规则组输入通道***********/
/************用结构体初始化ADC************/
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//连续转换模式:
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right ;//数据对齐:右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部触发控制的触发源:内部触发,软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent ;//工作模式:独立模式
ADC_InitStructure.ADC_NbrOfChannel = 1;//通道数目
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描转换模式:
ADC_Init(ADC1,&ADC_InitStructure);
/************开启ADC电源************/
ADC_Cmd(ADC1,ENABLE);
/************ADC进行校准************/
ADC_ResetCalibration(ADC1);//四步骤:复位校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
ADC_StartCalibration(ADC1);//开始校准
while (ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
}
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1,ADC_Channel,1, ADC_SampleTime_55Cycles5);
//规则组菜单第一个位置写入通道0,采样时间为55.5个ADCCLK的周期
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换函数
while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//获取EOC标志位状态:规则组转换完成标志位
//大概等待5.6us,1/12M*(55.5+12.5)=5.6us
return ADC_GetConversionValue(ADC1);
}
实物