MM32F0163D7P的ADC内部1.2V参考电压的使用

模拟技术

2414人已加入

描述

1

MM32F0160的ADC简介

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





审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分