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

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


全自动核酸提取仪的产品特点的详细介绍
Linux ftrace工具宏定义
单片机中的拉电流和灌电流是什么意思
5G产业未来的发展趋势分析
手机无线充电主流芯片介绍
MM32F0163D7P的ADC内部1.2V参考电压的使用
DAS Environmental Expert致力于通过高科技解决方案改善中国的空气质量标准
食品重金属检测仪的工作原理
什么是机器学习机器学习到底有什么重要性详细资料说明
完美逆转——由汽车安全引领的MEMS传感器复苏之路
工业&amp;协作机器人在CIMT2023上掀起的一股“协作&智能”风暴
电池修复技术交流学习-电池气死回生的反充可行吗?
科迎法电气EherCAT远程I/O模块新增一款EtherCAT通讯协议
新华三对集群路由器未来的产品规划
湖北黄冈首座电杆塔附挂5G基站成功落点
企业如何选择合适的云平台
马云利用区块链技术把菜鸟物流打造国家智能物流主干搜集
微星Stealth 15M纯净白即将上架预约,采用11代低压酷睿+RTX 2060配置的轻薄游戏本
硫化物固态电池负极该怎么选择和设计?
FLIR上月发布可见光和热感双重相机模块