分享知识,希望对各位读者有所帮助!
前言
前文介绍了外挂ADC芯片,本文介绍STM32F103内置的ADC外设
一、ADC(模数转换器)
(1)作用
ADC外设可以将引脚上连续变化的模拟电压转换为数字变量。
(2)精度
ADC转换的精度与位数有关,位数越多,精度越精准。
本文介绍的ADC外设是12位的,那么 0V ~ 3.3V范围就是0 ~
- 1 >>0 ~ 4095。
(3)硬件参数
芯片ADC外设最多有18个输入通道,分别是16个GPIO口、内部温度传感器和内部1.2V的基准电压。
- 温度传感器可以用来测量CPU温度
- 基础电压可以用来校准输入信号是否正确。
二、ADC转换原理
ADC的转换原理为逐次逼近型
取一个已知值来与输入未知值进行比较,例如目前转换范围是0 ~ 256,此时取128与未知值进行比较,若比128小,则再取64进行比较,以此类推,就可以确定未知值是多少了。
三、ADC转换原理
根据上文,我们知道了ADC的基础知识,那么ADC内部转换到底是怎么完成的呢?
我们可以根据下图ADC框图来进行总结
- 可以看到ADC在GPIO端口共有16个输入通道,并且在芯片内部还有温度传感器和基准电压两个输入源。
- 在模拟至数字转换器中,有一个注入通道和规则通道。
- 注入通道可以同时对四个ADC通道进行转换,并将四个转换结果同时存入注入通道数据寄存器。
- 规则通道可以同时对16个ADC通道进行转换,但规则通道数据寄存器只能存放一个转换结果。若将16个转换结果都放入数据寄存器中,那么只有最后一个转换结果会存在,前15个都会被覆盖。
- 规则通道和注入通道转换结束后,都会在状态寄存器中将标志位(EOC 和 JEOC) 置1。同时这个标志位还可以用来触发中断
- 那么如何触发转换呢?我们可以看到触发源来自定时器,为避免频繁进中断而导致程序出错,我们选择TIM_TRGO更新事件触发更为保险
四、ADC转换模式
(1)单次转换,非扫描模式
只能对一个ADC通道进行转换,并且每次转换前都要进行触发
(2)连续转换,非扫描模式
只能对一个ADC通道进行转换,并且触发一次后,就可以不断地进行转换
(3) 单次转换,扫描模式
可以对最多16个ADC通道进行连续转换,并且每次转换前都要进行触发
(4) 连续转换,扫描模式
可以对最多16个ADC通道进行连续转换,并且触发一次后,就可以不断地进行转换
五、ADC多通道配置代码实现
(1)硬件连接
光敏传感器------AO PA0 热敏传感器----- AO PA1 对射式红外传感器---AO PA2
(2)代码实现
AD.c
/*
函数:初始化ADC引脚,模式
参数:无
返回值:无
*/
void MyADC1_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1外设的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //将分频系数设置为6,ADCCLK时钟频率为 72M/6 = 12M
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模式为模拟输入,近似引脚断开,避免引脚变化影响数值转换
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; //初始化ADC1外设的0、1、2通道
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //选择独立模式,即只使用ADC1
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //使用软件触发,不需要外部触发
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //失能连续转换
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //失能扫描模式,只读取第一个序列
ADC_InitStructure.ADC_NbrOfChannel = 1; //规则组的通道数为1
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
/*ADC校准*/
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}
/*
函数:获取AD转换后的值
参数:某个通道
返回值:转换后的值
*/
uint16_t MyADC_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位 置1,即等待AD转换结束
return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}
main.c
uint16_t AD0, AD1, AD2; //定义AD值变量
int main(void)
{
MyADC1_Init();
OLED_Init();
OLED_ShowString(0, 0, "AD0:", OLED_8X16);
OLED_ShowString(0, 16, "AD1:", OLED_8X16);
OLED_ShowString(0, 32, "AD2:", OLED_8X16);
while (1)
{
AD0 = MyADC_GetValue(ADC_Channel_0);//ADC1外设通道0
AD1 = MyADC_GetValue(ADC_Channel_1);//ADC1外设通道1
AD2 = MyADC_GetValue(ADC_Channel_2);//ADC1外设通道2
OLED_ShowNum(32, 0, AD0, 4, OLED_8X16);
OLED_ShowNum(32, 16, AD1, 4, OLED_8X16);
OLED_ShowNum(32, 32, AD2, 4, OLED_8X16);
Delay_ms(100);
OLED_Update();
}
}
(3)实验现象
实验结果:功能显示正常,三个通道的AD值均可被外界所影响,且数值变化正确
总结
本文介绍了STM32F103芯片的内置ADC外设及基本代码实现,希望对各位读者有所帮助。