1
ADC外设是12位的逐次逼近型(SAR)模拟数字转换器,可以将模拟信号转换成数字信号。
ADC有16 个通道可测量内部或外部信号源,其中ADC有14 路外部输入通道和2路内部通道,如下图1 ADC的系统框图所示分别是通道14内部温度温度传感器通道,通道15内部电压传感器通道,即内部1.2V参考电压通道。
ADC的通道可以单次、单周期和连续进行转换。根据不同的方式又可以选择普通通道转换、任意通道转换、注入通道转换。ADC 的输入时钟不得超过16M,他是由 APB2 时钟(PCLK2) 分频产生。
图1 ADC系统框图
2
MM32F0160内部1.2V参考电压简介
MM32系列MCU出厂时,在Flash特定的内存地址存储了1.2V参考电压的校准值,即VDDA为3V3时采样1.2V电压的校准值。该校准值可以通过UM手册查阅。例如,可通过UM_MM32F0160_SC手册的ADC章节查阅到MM32F0163D7P的ADC内部1.2V参考电压的校准值存储在Flash特定的内存地址0x1FFFF7E0区域。
根据本文章节1图1的ADC系统框图可知ADC内部1.2V参考电压通道为通道15。MM32其它系列的MCU的ADC内部1.2V参考电压校准值在Flash内存的存储地址,内部1.2V参考电压通道的通道号如下表1所示(注:其它MCU系列请参考UM手册)。
表1 MM32系列ADC内部1.2V参考电压校准值的存储地址和1.2V参考电压通道号
3
ADC内部1.2V参考电压的应用场景举例
ADC的参考电压为VDD,当MCU的供电VDD不稳定或采用电池供电时ADC的参考电压会随着VDD的波动而波动,随着电池电量和电压的下降而变化,从而影响ADC的采集和测量精度,这种场景就可以考虑使用MCU出厂时VDD为3.3V时ADC采样1.2V电压得到的采样校准值,读取该采样校准值并转换成电压值,作为ADC的间接参考电压使用。
4
ADC内部1.2V参考电压采样值的读取
以MM32F0163D7P为例,查阅UM_MM32F0160_SC手册ADC章节的ADC系统框图可知ADC内部1.2V参考电压通道为通道15(VSENSOR),在读取ADC内部1.2V参考电压采样值前需配置ADC通道15并使能该通道,使用任意通道配置核心代码如下所示,本文后面8.3章节有详细的应用举例。
/* Sampling value of each channel of ADC */ uint16_t ADC_Channel_Samp_Value[4] = {0x00}; /* Assign ADC1 1.2V Vref channel_15 to RANK 3 */ ADC_ANY_CH_Config(ADC1,3,ADC_Channel_VoltReference); /* Enable ADC 1.2V channel_15 voltage reference */ ADC1->ADCFG |= ADC_ADCFG_VSEN; /* Get the sampling value of ADC 1.2V channel 15 */ ADC_Channel_Samp_Value[3] = ADC1->ADDR15;
5
ADC内部1.2V参考电压校准值的读取
以MM32F0163D7P为例,读取出厂VDDA为3V3时采样1.2V电压的采样校准值,并换算成电压值,核心代码如下所示。本文8.4章节有详细的读取举例。
/* 1.2V sampling calibration value storage address */ #define ADC_1_2V_SAMPLE_CALI_VALUE_MEM_ADDR 0x1FFFF7E0 /* Read ADC 1.2V Sample value */ Vref_1_2V_Cali = *(uint16_t*)(ADC_1_2V_SAMPLE_CALI_VALUE_MEM_ADDR); /* Convert to voltage value */ Vref_1_2V_Cali_V = (float)(Vref_1_2V_Cali * (3.3/4096));
6
ADC各通道采样电压值
与1.2V通道采样电压值换算关系
定义Calcu_ADC_Channel_V为缓存ADC各通道采样电压值,gADC_Sample_Value为缓存ADC各通道的采样值。ADC_Channel_Samp_Value[4]为缓存ADC各通道的采样值包括ADC的1.2V通道实时采样值,Vref_1_2V_Cali为VDDA为3V3时采样1.2V电压的采样校准值,Vref_1_2V_Cali由以上章节5 ADC内部1.2V参考电压校准值的读取得到,换算成电压值为Vref_1_2V_Cali_V = (float)(Vref_1_2V_Cali * (3.3/4096)) ,则存在以下关系式:
Calcu_ADC_Channel_V / gADC_Sample_Value = Vref_1_2V_Cali_V /ADC_Channel_Samp_Value[i]
其中i表示ADC各通道号包括ADC的1.2V通道。
由此,推得ADC各个通道的采样电压值为
Calcu_ADC_Channel_V = (float)(gADC_Sample_Value * (Vref_1_2V_Cali_V/ADC_Channel_Samp_Value[3]))
ADC_Channel_Samp_Value[3]缓存ADC的1.2V通道的实时采样值。即:ADC各通道的采样电压值=ADC各通道的采样值*(ADC内部采样1.2V电压的采样校准值换算得到的电压值 / ADC的1.2V通道的实时采样值)。
7
根据出厂ADC内部1.2V参考电压的校准值
反推VDDA的电压值
由于Vref_1_2V_Cali / ADC_V1_2V_Channel_Sample = VDDA / 4096
得到VDDA = ( Vref_1_2V_Cali * 4096 ) / ADC_V1_2_Channel_Sample
注意事项:读取ADC_V1_2_Channel_Sample 采样值前需配置和使能1.2V通道(MM32F0163D7P的ADC 1.2V通道为通道15)。注:本文章节4有提到配置方法。
8
ADC使用注意事项
1
ADC高达1Msps转换速率,每个通道可以独立的设置采样保持时间,但需注意的是采样保持时间最小为2.5个ADC时钟周期,最大为240.5个ADC时钟周期,在应用场景条件允许情况下,在此范围内适当加大采样保持时间可以保证ADC采样精度。条件允许情况下适当降低ADC时钟频率也可以保证采样精度,但ADC的时钟不得超过16MHz。
2
ADC的内部1.2V Vref通道转换周期比规则转换通道的转换周期稍大一些,如果对ADC的采样速率有应用场景的要求,建议使用ADC的注入通道功能。
3
ADC的采样值受到输入阻抗的影响,关于ADC输入阻抗的计算可参考对应MCU系列的DS手册,电气特性,工作条件的ADC特性。
4
使用ADC时应注意用作ADC功能的GPIO的IO类型,例如IO类型为“TC”类型即标准的IO类型,不容忍VDD电压即ADC的输入采样电压不得超过VDD电源电压。此外GPIO内部带有上下拉钳位二极管,用户应避免输入ADC的采样电压过高引起倒灌影响ADC的工作条件和采样精度(关于IO类型的说明请参考对应MCU系列的DS手册管脚定义章节)。
9
ADC内部1.2V参考电压的使用完整举例
1
以MM32F0163D7P为例,查阅DS手册得到GPIO与ADC通道对应关系如下表2所示。
表2 GPIO与ADC通道对应关系
2
以MM32F0163D7P为例,完整举例ADC内部1.2V参考电压的使用,本示例外接采样3路ADC电压值,首先初始化3路ADC通道,ADC输入的GPIO的分别为PA0对应ADC_Channel_0,PA1对应ADC_Channel_1,PA2对应ADC_Channel_2,ADC的GPIO初始化代码如下所示。
void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; /* Enable GPIOA Clock */ RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); GPIO_StructInit(&GPIO_InitStruct); /* PA0 ADC_CH0, PA1 ADC_CH1, PA2 ADC_CH2 */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStruct); }
3
以MM32F0163D7P为例,初始化ADC为12bit精度,时钟为72M预分频为16分频,连续转换模式,数据格式右对齐,采样保持时间为240.5个ADC时钟周期,配置任意通道模式,配置并使能ADC内部1.2V通道Channel15,ADC的初始化代码如下所示。
void ADC_Configure(void) { ADC_InitTypeDef ADC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC, ENABLE); /* Enable ADC clock */ ADC_StructInit(&ADC_InitStruct); ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; ADC_InitStruct.ADC_PRESCARE = ADC_PCLK2_PRESCARE_16; /* ADC continue scan convert mode */ ADC_InitStruct.ADC_Mode = ADC_Mode_Continue; /* AD data right-justified */ ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_Init(ADC1, &ADC_InitStruct); /* Configure ADC ADC_Channel_x Sample time */ ADC_Channel_Sample_time_Configure(ADC1,ADC_Channel_0,ADC_Samctl_240_5); ADC_Channel_Sample_time_Configure(ADC1,ADC_Channel_1,ADC_Samctl_240_5); ADC_Channel_Sample_time_Configure(ADC1,ADC_Channel_2,ADC_Samctl_240_5); ADC_ANY_Cmd(ADC1, DISABLE); /* Disable ADC ANYChannel */ ADC_ANY_NUM_Config(ADC1,3); /* Configure Multi-Channel num */ /* Assign PA0 ADC1 channel_0 to RANK 0 */ ADC_ANY_CH_Config(ADC1,0,ADC_Channel_0); /* Assign PA1 ADC1 channel_1 to RANK 1 */ ADC_ANY_CH_Config(ADC1,1,ADC_Channel_1); /* Assign PA2 ADC1 channel_2 to RANK 2 */ ADC_ANY_CH_Config(ADC1,2,ADC_Channel_2); /* Assign ADC1 1.2V Vref channel_15 to RANK 3 */ ADC_ANY_CH_Config(ADC1,3,ADC_Channel_VoltReference); ADC_ANY_Cmd(ADC1, ENABLE); /* Enable ADC ANYChannel */ /* Enable ADC 1.2V channel_15 voltage reference */ ADC1->ADCFG |= ADC_ADCFG_VSEN; ADC_Cmd(ADC1, ENABLE); /* Enable ADC */ }
4
以MM32F0163D7P为例,读取出厂VDDA为3V3时采样1.2V电压的采样校准值,并换算成电压值,代码如下所示。
#define VDDA 3.3F #define ADC_12BIT 4096U #define ADC_RESOLUTION VDDA / ADC_12BIT /* 1.2V sampling calibration value storage address */ #define ADC_1_2V_SAMPLE_CALI_VALUE_MEM_ADDR 0x1FFFF7E0 /* 1.2V sampling calibration value */ uint16_t Vref_1_2V_Cali = 0; /* 1.2V sampling calibration value Convert to voltage value */ float Vref_1_2V_Cali_V = 0.0; void Read_Factory_1_2V_Sample_CaliValue(void) { /* Read ADC 1.2V Sample value */ Vref_1_2V_Cali = *(uint16_t*)(ADC_1_2V_SAMPLE_CALI_VALUE_MEM_ADDR); /* Convert to voltage value */ Vref_1_2V_Cali_V = (float)(Vref_1_2V_Cali * ADC_RESOLUTION); }
5
以MM32F0163D7P为例,由以上9.4章节读取出厂VDDA为3V3时采样1.2V电压的采样校准值,由以上9.3章节ADC内部1.2V参考电压通道的配置和使能,ADC的1.2V采样电压的校准值根据以上章节6表述的公式,结合ADC的1.2V通道15的实时采样值可用于反推VDDA的电压值,同时该采样校准值换算成电压值后可间接作为ADC多通道连续采样的参考电压。
ADC内部1.2V参考电压实时采样值,ADC各通道采样值的读取并换算成电压值以及在main函数初始化UART1打印功能,ADC外设的初始化,读取ADC采样1.2V的校准值,在while(1)主循环中调用获取ADC各通道采样电压值函数的详细实现的代码如下所示。本示例通过UART1每隔200ms毫秒打印输出ADC各通道采样并换算得到电压值到串口调试助手。
/* Buffer the VDDA voltage value of the reversed ADC */ float ADC_VDDA = 0.0; /* Sampling value of each channel of ADC */ uint16_t ADC_Channel_Samp_Value[4] = {0x00}; /* Buffer the sampling value of each channel of the ADC */ uint16_t gADC_Sample_Value = 0; /* Buffer the voltage value of each channel of ADC */ float Calcu_ADC_Channel_V = 0.0; void Calcu_ADC_Each_Channel_Voltage_Value(void) { uint8_t i = 0; /* Software starts the ADC conversion */ ADC_SoftwareStartConvCmd(ADC1, ENABLE); /* ADC conversion flag */ while(ADC_GetFlagStatus(ADC1, ADC_IT_EOC) == 0); /* Clears the adc's pending flags */ ADC_ClearFlag(ADC1, ADC_IT_EOC); /* Get the sampling value of ADC PA0 channel 0 */ ADC_Channel_Samp_Value[0] = ADC1->ADDR0; /* Get the sampling value of ADC PA1 channel 1 */ ADC_Channel_Samp_Value[1] = ADC1->ADDR1; /* Get the sampling value of ADC PA2 channel 2 */ ADC_Channel_Samp_Value[2] = ADC1->ADDR2; /* Get the sampling value of ADC 1.2V channel 15 */ ADC_Channel_Samp_Value[3] = ADC1->ADDR15; /* The factory 1.2V sampling calibration value and the 1.2V channel sampling value reverse the VDDA voltage value */ ADC_VDDA = (Vref_1_2V_Cali_V *4096) / ADC_Channel_Samp_Value[3]; printf("ADC_VDDA = %0.2f ",ADC_VDDA); /* Print out the voltage value of each channel calculated by ADC */ for(i = 0; i < 4; i++) { /* Obtain the sampling value of each channel of the ADC */ gADC_Sample_Value = ADC_Channel_Samp_Value[i]; /* Calculate the voltage value of each channel according to the sampling value of each channel of the ADC */ Calcu_ADC_Channel_V = (float)(gADC_Sample_Value * (Vref_1_2V_Cali_V/ADC_Channel_Samp_Value[3])); if(i == 3) { printf("ADC1_CH15_VREF: %0.2fV ",Calcu_ADC_Channel_V); } else { printf("ADC1_CH%d: %0.2fV ",i,Calcu_ADC_Channel_V); } } }
int main(void) { /* SysTick Init */ DELAY_Init(); /* UART1 Init */ CONSOLE_Init(115200); /* ADC Pin Configure */ ADC_GPIO_Configure(); /* ADC function Configure */ ADC_Configure(); /* Read factory 1.2V sample calibration value and convert to voltage value */ Read_Factory_1_2V_Sample_CaliValue(); while (1) { if(Tick_200ms_Flag == true) { Tick_200ms_Flag = false; /* Get and Calculate the voltage value of each channel of the ADC */ Calcu_ADC_Each_Channel_Voltage_Value(); } } }
6
编译程序把烧录程序到核心板,如下图2所示,3路ADC分别采集外接的电压值,ADC各通道采样换算得到的电压值打印输出到串口调试助手,测试结果分别为ADC_VDDA该值是通过读取出厂VDDA为3V3时采样1.2V电压的采样校准值结合1.2V通道15的实时采样值反推得到的VDDA(即VDD的电压值)的电压值。ADC_CH0采集1.0V电压,实际采到1.03V,ADC_CH1接GND采集0V电压,实际采集到0V,ADC_CH2采集0.50V电压,实际采集到0.50V。其中ADC_CH15_VREF采集ADC内部1.2V通道实时采样得到的电压值,采集到1.18V,该值可参考以上9.4章节表述的出厂VDDA为3V3时采样1.2V电压的采样校准值换算得到的电压值接近。
图2
7
如下图3所示,换一组电压采集,ADC_CH0采集2.50V电压实际采集到2.51V,ADC_CH1采集3.32V电源电压实际采集到3.31V,ADC_CH2采集1.50V电压,实际采到1.50V电压。以上测试均在ADC允许的误差范围。
图3
审核编辑:刘清
评论
查看更多