关联:
STM32超全笔记【秋招自用】【含PID小车、飞控等项目】
【ADC的一些简单原理和知识】
ADC是一种用于将模拟信号转换为数字信号的电子设备或模块。
【问】模拟信号是什么??
指在某一范围内可以连续变化的量,可表示任意值,(如温度、压力、速度等)
例如,当我们用模拟信号表示温度时,温度可以在一定范围内连续变化,如从25.2℃到30.2°。
【问】数字量是什么??
指具有离散状态的量。在数字信号中,信号的幅度和时间都是离散的。例如整数、有限的小数等。数字量的表示和传输具有较高的稳定性和准确性。
【问】为什么要模拟---数字转换?
在现实世界中,许多物理现象是模拟的,但为了便于计算机处理,通常会通过数据采集设备(如模数转换器,ADC)将模拟信号转换为数字信号。同样,将数字信号转换回模拟信号以供模拟设备使用,也需要数字模拟转换器(DAC)。
【问】ADC的功能原理:采样和量化
采样是指将模拟波形在时间域上进行切分,每个切片大小大致等于原来波形的值。
采样完成后,给每个时间片分配一个数字,这样的一个过程称为量化,量化生成的数字可以交由计算机进行处理。
通常采用逐次逼近型ADC。
【问】逐次逼近型ADC? (类似C语言里面的二分查找)
逐次逼近转换过程和用天平称物重非常相似。天平称重物过程是从最重的砝码开始试放,与被称物体进行比较,若物体重于砝码,则该砝码保留,否则移去。在加上第二个次重砝码,由物体的重量是否大于砝码的重量决定第二个砝码是否留下还是移去。以此类推,一直加到最小一个砝码为止。然后将所有留下的砝码重量相加,就得此物体的重量。
逐次逼近型ADC,就是将输入模拟量与不同的参考电压作多次比较。使转换所得的数字量在数值上逐次逼近输入模拟量对应值。
【STM32 -- ADC】
STM32有三个ADC,精度12位。其中ADC1和ADC2都有16个外部通道,ADC3一般有8个外部通道,各通道的A/D转换可以单次、连续、扫描或间断执行,ADC转换的结果可以左对齐或右对齐储存在16位数据寄存器中。ADC的输入时钟不得超过14MHz。、
STM32的ADC框图:
虽然框图非常杂乱,但是其实过程就是:
1.选择输入通道IO口,模式肯定选择模拟输入。
2.选择注入通道(重要的信号用这个)和规则通道(一般)。
3.选择触发源:软件触发和外部中断、定时器触发。
4.ADC时钟:ADC时钟源由PCLK2分频产生,PCLK2一般72MHz,预分频系数设置6,就得到ADC时钟为12MHz。(ADC的输入时钟不得超过14MHz)
5.数据寄存器:ADC精度是12位的,但是数据级寄存器存放数据的位宽是16位,所以允许选择数据对齐方式:左对齐右对齐。
【问】规则组最多16个输入通道,如果一个规则组同时用多个通道,数据如何读取?
DMA。
按照规则组的顺序:上一个通道转换的数据会被下一个通道转换的数据所覆盖。
所以通道转换完毕后要及时把数据取走。
ADC的输入时钟不得超过14MHz)、
6.ADC中断
ADC中断分为:规则组转换结束中断、注入组转换结束中断、设置了模拟看门狗状
态位中断。它们都有独立的中断使能位,分别由 ADC_CR 寄存器的 EOCIE、JEOCIE、AWDIE
位设置,对应的标志位分别是 EOC、JEOC、AWD。
【扫描模式与非扫描模式】
非扫描模式下,只能选择一个通道进行转换。转换完成后,可以手动或通过中断等方式改变通道选择来执行下一次转换。
扫描模式下,可以通过设置多个输入通道进行连续转换。ADC将按照通道号的顺序对设置的多个通道进行转换,并将结果按顺序保存在对应的数据寄存器中。可以通过使用EOC标志或DMA传输等方式来获取每个通道的转换结果。
【单次转换与连续转换】
单次转换模式,ADC按照设定的配置执行一次转换,然后停止转换并等待进一步的触发。
连续转换模式,ADC在完成一次转换后自动开始下一次转换,无需外部触发。这种模式适用于需要持续采样的应用场景,如数据采集。
【例程9】AD单通道采集电压实验
使用ADC1,GPIO引脚为PA0,配置为模拟输入,测引脚也就是电源电压。
【ADC和GPIO结构体的配置】
void AD_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*设置ADC时钟*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入
/*规则组通道配置*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
/*ADC初始化*/
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; //扫描模式,失能,只转换规则组的序列1这一个位置
ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
/*ADC使能*/
ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
/*ADC校准*/
ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}
初始化完成后记得cmd使能。
【读ADC值】
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}
ADC_SoftwareStartConvCmd(ADC1, ENABLE); 软件触发AD转换一次
对应了ADC初始化代码中的ADC_ExternalTrigConv_None; 使用软件触发,不需要外部触发。
返回值就是读取数据寄存器中的AD转换值。(还没有转换为电压值)
【主函数】
ADValue = AD_GetValue(); //获取AD转换的值
Voltage = (float)ADValue / 4095 * 3.3; //将AD值线性变换到0~3.3的范围,表示电压
OLED_ShowNum(1, 9, ADValue, 4); //显示AD值
OLED_ShowNum(2, 9, Voltage, 1); //显示电压值的整数部分
OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); //显示电压值的小数部分
Delay_ms(100); //延时100ms,手动增加一些转换的间隔时间
在主函数中把ADC采样值0 - 4096转换为电压值0 - 3.3V 。然后OLED上显示出来。
4096就是2的12次方。ADC精度和数据就是12位的。