本例程测量的是PB0口的电压
1、配置ADC使用的GPIO口
void ADC_GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输出PB0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
2、配置ADC1
void ADC1_Config()
{
//使用ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//ADC1模式配置
ADC1_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC1_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC1_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置TIM2_CC2为触发源
ADC1_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC1_InitStructure.ADC_NbrOfChannel = 1;
ADC1_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1,&ADC1_InitStructure);
//配置ADC转换时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div2);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_55Cycles5);
//使能ADC的DMA模块
ADC_DMACmd(ADC1,ENABLE);
ADC_Cmd(ADC1,ENABLE);
/* 复位校准寄存器 */
ADC_ResetCalibration(ADC1);
/* 等待校准寄存器复位完成 */
while(ADC_GetResetCalibrationStatus(ADC1));
//开始ADC1的校准
ADC_StartCalibration(ADC1);
//等待ADC1校准完成
while(ADC_GetCalibrationStatus(ADC1));
//使用外部触发模式使能
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
ADC模式配置说明:
1)ADC_Mode :STM32 具有多个ADC,而不同的ADC又是共同通道的,当两个ADC采集同一个通道的先后顺序、时间间隔不同时,就演变出各种各样的模式,如同步注入模式、通不规则模式等10种模式,应选择适当的模式应适应数据采集的要求。
2)ADC_ScanConvMode :当有多个通道需要采集信号时,可以把ADC配置为按照一定顺序对各个通道进行扫描转换,即轮流采集各个通道的值。若采集多个通道,必须开启此模式。
3)ADC_ContinuousConvMode :连续转换模式。此模式与单次转换模式相反,单次转换模式只采集以此ADC数据就停止转换了,而连续采集模式则是在上一次ADC转换完成之后,立即开启下一次的转换。
4)ADC_ExternalTrigConv :ADC需要在收到外部触发信号之后才能开始转换,如外部中断信号、定时器触发,这两个信号为外部触发信号。,如果不能使用外部触发信号,可以使用外部软件触发(ADC_ExternalTrigConv_None)。
5)ADC_DataAlign :ADC数据对齐方式,ADC转换之后的数值被保存在数据寄存器之中(ADC_DR的015或者1632位当中)
左对齐 —> ADC转换数值的最高位与存储区的最高位相对齐,即D12对Bit15
右对齐 —> ADC转换数值的最低位与存储区的最低位相对其,即D0对Bit0
6)ADC_NbrOfChannel :保存进行ADC数据转换的通道数。可以为1~16个
ADC时钟配置说明:
1)ADC时钟有上限,即不能超过14MHz;
使用RCC_ADCCLKConfig(分频值)进行配置
分频值为:
分频值 | 数值 |
---|---|
RCC_PCLK2_Div2 | ADC_clock = PCLK2/2 |
RCC_PCLK2_Div4 | ADC_clock = PCLK2/4 |
RCC_PCLK2_Div6 | ADC_clock = PCLK2/6 |
RCC_PCLK2_Div8 | ADC_clock = PCLK2/8 |
当PCLK2为72MHz时,考虑到ADC_Clk需要低于14MHz,所以分频值应该为RCC_PCLK2_Div6
2)ADC_RegularChannelConfig()。ADC转换速率不只与时钟有关系,还与采样周期相关。每个ADC通道都可以使用不同的采样周期
函数参数说明:
- Rank:针对多通道采集而言的,比如对于1、4、7通道而言,如果他们的Rank值被分别配置为3、2、1,那么扫描顺序就是先7,后4,最后是1
- ADC-SampleTime:用于配置本通道的采样周期,最短可配置为1.5个采样周期。这里的周期指的是ADC_CLK的时钟周期。
STM32ADC采样时间计算公式:TCONV = 采样周期 + 12.5个ADC时钟周期
其中采样周期就是指ADC_RegularChannelConfig()所配置的周期。
所以,本案例的ADC转换时间为TCONV = (55.5+12.5)*1/12 ~= 5.67us
ADC的自校准:
在开始ADC转换之前,需要启动ADC自校准。ADC有一个内部自校准模式,校准可大幅减少因内部电容器组的变化而造成的精准度误差。在校准期间,在每个电容器上都会计算出一个修正误码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。
3、电压数值量化
case1:对于64PIN以下的STM32系列,其VREF与VDDA内部相连接,所以参考电压为3.3V。
此时,电压量化计算公式应该是:
SendBuff1 = SendBuff*3.3/4096;//参考电压
case2:对于100PIN以及以上的STM32系列而言,其单独引出VREF,可以使用外部基准IC作为参考电压,例如使用2.5V的基准IC,
此时,电压应该为:
SendBuff1 = SendBuff2.5/4096;//参考电压
case3:使用STM32内部参考电压,先读取该值,在比较计算
adc电压计算 Vread =(Adc(readx)/4096(根据ADC位数不同,此处值不同)) Vref。读取通道17,因为是个定值,所以可以计算出Vref = 1.24096/Adc(read17)); 任意通道的电压值 Vread = (Adc(readx)/4096)(1.24096/adc(read17))) = 1.2Adc(readx)/Adc(read17)
参考文献:
【1】STM32 ADC的基本原理、寄存器(超基础、详细版)
【2】STM32 ADC转换时间