5.1 ADC模数转换原理
ADC就是一种数模转换器。ADC的输入电压为0-3.3v,如果ADC我们设置为12位,那么3.3v对应这2的12次方即4096,那么单位数字量对应的模拟量则为3.3/4096。而ADC的功能可以获取数字量X,那么读取ADC获取的数字量X再乘以3.3/4096,就是电压值。
12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。 ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
5.1.1 ADC电路结构
注入通道:最多一次性选4路通道,配合4个16位寄存器,就可以一次性转换4路模拟数据。
规则通道:最多一次性选16路通道,但只有1个16位寄存器,存在新来的数据覆盖上一个数据的问题,此时要么尽快将数据取走,要是使用DMA帮助转运数据,进而可以实现一次性转换16路模拟数据。当然,一次就选一个通道,就是普通的ADC功能。
触发转换电路:stm32中的ADC触发方式:
软件触发:在程序中手动调一句代码。
硬件触发:上图所示的触发源。主要来自于定时器TIMx,也可以外部中断引脚EXTI。正常思路是:定时器每隔1ms产生一次中断 --> 中断函数中开启触发转换信号 --> ADC完成一次转换。
VDDA、VSSA:ADC的供电引脚。
VREF+、VREF-:ADC的参考电压,决定了ADC的输入电压的范围。stm32内部已经和VDDA、VSSA连接在一起了。
ADCCLK:来自ADC的预分频器,这个ADC的预分频器则来自于“RCC时钟树”。具体可以查看时钟树的电路,默认情况就是对72MHz进行ADC预分频,由于ADCCLK最大18MHz,所以只能选择6分频/8分频。
DMA请求:触发DMA进行数据转运。下一章讲。
注入通道数据寄存器、规则通道数据寄存器:用于存放转换结果。
模拟看门狗:一旦高于上阈值或低于下阈值,就会申请模拟看门狗的中断,最终进入NVIC。
转换结束EOC:规则通道转换完成,会在状态寄存器置标志位。
注入转换结束JEOC:注入通道转换完成,会在状态寄存器置标志位。
NVIC:嵌套向量中断控制器,控制是否响应上面这三个中断。
5.1.2 规则组的转换模式
stm32的ADC最多同时支持16个通道,那么ADC每次扫描1个通道还是多个通道,便是选择 非扫描模式/扫描模式;而对于单个通道的ADC转换来说,触发一次ADC是只转换一次,还是自动的进行连续转换,便是选择 单次转换/连续转换。两两组合就有四种模式。
1.单次转换、非扫描模式
触发一次仅转换一次。读取数据时,需要等待EOC标志位置1,然后从数据寄存器读取结果。如要再进行转换,就需要再次触发转换。
2. 连续转换、非扫描模式
仅需要一次触发,ADC就会在一次转换完成后立刻进入下一次转换,实现不断地自动进行转换。此时就不需要读EOC看转换是否完成,直接想读数据的时候就读。
3. 单次转换、扫描模式
可以一次性转换多个通道,不过还是触发一次、所有通道只转换一次。
4. 连续转换、扫描模式
不仅可以一次性转换多个通道,还可以实现触发一次、自动不间断转换。
5.1.3 数据对齐
右对齐【常用】:读出的值就是实际值。
左对齐:有时候不需要太大的分辨率,便将12位ADC的转换数据左对齐,然后只取高8位。
void adcInit (void)
{
//IO初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure = {0}; //创建结构体
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //选择引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //选择速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //选择模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //选择引脚
GPIO_Init(GPIOC, &GPIO_InitStructure);
//外设初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADC的时钟频率
ADC_DeInit(ADC1);
ADC_InitTypeDef ADC_InitStructure = {0};
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立工作模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //是否开启扫描
ADC_InitStructure.ADC_ContinuousConvMode =ENABLE; //是否开启连续模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //触发方式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //对齐方式
ADC_InitStructure.ADC_NbrOfChannel = 2; //通道个数
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1,ENABLE); //启动ADC
//校准
ADC_ResetCalibration(ADC1); //重置ADC校准
while(ADC_GetResetCalibrationStatus( ADC1)) //等待初始化完成
{
ADC_StartCalibration(ADC1); // 开始校准
}
while (ADC_GetCalibrationStatus(ADC1)); // 等待校准完成
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5); //规定规则组内转换顺序,采样时间
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动转换 软件触发
ADC_DMACmd(ADC1, ENABLE);
}