1
ADC外設(shè)是12位的逐次逼近型(SAR)模擬數(shù)字轉(zhuǎn)換器,可以將模擬信號(hào)轉(zhuǎn)換成數(shù)字信號(hào)。
ADC有16 個(gè)通道可測(cè)量?jī)?nèi)部或外部信號(hào)源,其中ADC有14 路外部輸入通道和2路內(nèi)部通道,如下圖1 ADC的系統(tǒng)框圖所示分別是通道14內(nèi)部溫度溫度傳感器通道,通道15內(nèi)部電壓傳感器通道,即內(nèi)部1.2V參考電壓通道。
ADC的通道可以單次、單周期和連續(xù)進(jìn)行轉(zhuǎn)換。根據(jù)不同的方式又可以選擇普通通道轉(zhuǎn)換、任意通道轉(zhuǎn)換、注入通道轉(zhuǎn)換。ADC 的輸入時(shí)鐘不得超過16M,他是由 APB2 時(shí)鐘(PCLK2) 分頻產(chǎn)生。

圖1 ADC系統(tǒng)框圖
2
MM32F0160內(nèi)部1.2V參考電壓簡(jiǎn)介
MM32系列MCU出廠時(shí),在Flash特定的內(nèi)存地址存儲(chǔ)了1.2V參考電壓的校準(zhǔn)值,即VDDA為3V3時(shí)采樣1.2V電壓的校準(zhǔn)值。該校準(zhǔn)值可以通過UM手冊(cè)查閱。例如,可通過UM_MM32F0160_SC手冊(cè)的ADC章節(jié)查閱到MM32F0163D7P的ADC內(nèi)部1.2V參考電壓的校準(zhǔn)值存儲(chǔ)在Flash特定的內(nèi)存地址0x1FFFF7E0區(qū)域。
根據(jù)本文章節(jié)1圖1的ADC系統(tǒng)框圖可知ADC內(nèi)部1.2V參考電壓通道為通道15。MM32其它系列的MCU的ADC內(nèi)部1.2V參考電壓校準(zhǔn)值在Flash內(nèi)存的存儲(chǔ)地址,內(nèi)部1.2V參考電壓通道的通道號(hào)如下表1所示(注:其它MCU系列請(qǐng)參考UM手冊(cè))。

表1 MM32系列ADC內(nèi)部1.2V參考電壓校準(zhǔn)值的存儲(chǔ)地址和1.2V參考電壓通道號(hào)
3
ADC內(nèi)部1.2V參考電壓的應(yīng)用場(chǎng)景舉例
ADC的參考電壓為VDD,當(dāng)MCU的供電VDD不穩(wěn)定或采用電池供電時(shí)ADC的參考電壓會(huì)隨著VDD的波動(dòng)而波動(dòng),隨著電池電量和電壓的下降而變化,從而影響ADC的采集和測(cè)量精度,這種場(chǎng)景就可以考慮使用MCU出廠時(shí)VDD為3.3V時(shí)ADC采樣1.2V電壓得到的采樣校準(zhǔn)值,讀取該采樣校準(zhǔn)值并轉(zhuǎn)換成電壓值,作為ADC的間接參考電壓使用。
4
ADC內(nèi)部1.2V參考電壓采樣值的讀取
以MM32F0163D7P為例,查閱UM_MM32F0160_SC手冊(cè)ADC章節(jié)的ADC系統(tǒng)框圖可知ADC內(nèi)部1.2V參考電壓通道為通道15(VSENSOR),在讀取ADC內(nèi)部1.2V參考電壓采樣值前需配置ADC通道15并使能該通道,使用任意通道配置核心代碼如下所示,本文后面8.3章節(jié)有詳細(xì)的應(yīng)用舉例。
?
/*?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內(nèi)部1.2V參考電壓校準(zhǔn)值的讀取
以MM32F0163D7P為例,讀取出廠VDDA為3V3時(shí)采樣1.2V電壓的采樣校準(zhǔn)值,并換算成電壓值,核心代碼如下所示。本文8.4章節(jié)有詳細(xì)的讀取舉例。
?
/*?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通道采樣電壓值換算關(guān)系
定義Calcu_ADC_Channel_V為緩存ADC各通道采樣電壓值,gADC_Sample_Value為緩存ADC各通道的采樣值。ADC_Channel_Samp_Value[4]為緩存ADC各通道的采樣值包括ADC的1.2V通道實(shí)時(shí)采樣值,Vref_1_2V_Cali為VDDA為3V3時(shí)采樣1.2V電壓的采樣校準(zhǔn)值,Vref_1_2V_Cali由以上章節(jié)5 ADC內(nèi)部1.2V參考電壓校準(zhǔn)值的讀取得到,換算成電壓值為Vref_1_2V_Cali_V = (float)(Vref_1_2V_Cali * (3.3/4096)) ,則存在以下關(guān)系式:
Calcu_ADC_Channel_V / gADC_Sample_Value = Vref_1_2V_Cali_V /ADC_Channel_Samp_Value[i]
其中i表示ADC各通道號(hào)包括ADC的1.2V通道。
由此,推得ADC各個(gè)通道的采樣電壓值為
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通道的實(shí)時(shí)采樣值。即:ADC各通道的采樣電壓值=ADC各通道的采樣值*(ADC內(nèi)部采樣1.2V電壓的采樣校準(zhǔn)值換算得到的電壓值 / ADC的1.2V通道的實(shí)時(shí)采樣值)。
7
根據(jù)出廠ADC內(nèi)部1.2V參考電壓的校準(zhǔn)值
反推VDDA的電壓值
由于Vref_1_2V_Cali / ADC_V1_2V_Channel_Sample = VDDA / 4096
得到VDDA = ( Vref_1_2V_Cali * 4096 ) / ADC_V1_2_Channel_Sample
注意事項(xiàng):讀取ADC_V1_2_Channel_Sample 采樣值前需配置和使能1.2V通道(MM32F0163D7P的ADC 1.2V通道為通道15)。注:本文章節(jié)4有提到配置方法。
8
ADC使用注意事項(xiàng)
1
ADC高達(dá)1Msps轉(zhuǎn)換速率,每個(gè)通道可以獨(dú)立的設(shè)置采樣保持時(shí)間,但需注意的是采樣保持時(shí)間最小為2.5個(gè)ADC時(shí)鐘周期,最大為240.5個(gè)ADC時(shí)鐘周期,在應(yīng)用場(chǎng)景條件允許情況下,在此范圍內(nèi)適當(dāng)加大采樣保持時(shí)間可以保證ADC采樣精度。條件允許情況下適當(dāng)降低ADC時(shí)鐘頻率也可以保證采樣精度,但ADC的時(shí)鐘不得超過16MHz。
2
ADC的內(nèi)部1.2V Vref通道轉(zhuǎn)換周期比規(guī)則轉(zhuǎn)換通道的轉(zhuǎn)換周期稍大一些,如果對(duì)ADC的采樣速率有應(yīng)用場(chǎng)景的要求,建議使用ADC的注入通道功能。
3
ADC的采樣值受到輸入阻抗的影響,關(guān)于ADC輸入阻抗的計(jì)算可參考對(duì)應(yīng)MCU系列的DS手冊(cè),電氣特性,工作條件的ADC特性。
4
使用ADC時(shí)應(yīng)注意用作ADC功能的GPIO的IO類型,例如IO類型為“TC”類型即標(biāo)準(zhǔn)的IO類型,不容忍VDD電壓即ADC的輸入采樣電壓不得超過VDD電源電壓。此外GPIO內(nèi)部帶有上下拉鉗位二極管,用戶應(yīng)避免輸入ADC的采樣電壓過高引起倒灌影響ADC的工作條件和采樣精度(關(guān)于IO類型的說(shuō)明請(qǐng)參考對(duì)應(yīng)MCU系列的DS手冊(cè)管腳定義章節(jié))。
9
ADC內(nèi)部1.2V參考電壓的使用完整舉例
1
以MM32F0163D7P為例,查閱DS手冊(cè)得到GPIO與ADC通道對(duì)應(yīng)關(guān)系如下表2所示。

表2 GPIO與ADC通道對(duì)應(yīng)關(guān)系
2
以MM32F0163D7P為例,完整舉例ADC內(nèi)部1.2V參考電壓的使用,本示例外接采樣3路ADC電壓值,首先初始化3路ADC通道,ADC輸入的GPIO的分別為PA0對(duì)應(yīng)ADC_Channel_0,PA1對(duì)應(yīng)ADC_Channel_1,PA2對(duì)應(yīng)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精度,時(shí)鐘為72M預(yù)分頻為16分頻,連續(xù)轉(zhuǎn)換模式,數(shù)據(jù)格式右對(duì)齊,采樣保持時(shí)間為240.5個(gè)ADC時(shí)鐘周期,配置任意通道模式,配置并使能ADC內(nèi)部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時(shí)采樣1.2V電壓的采樣校準(zhǔn)值,并換算成電壓值,代碼如下所示。
?
#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章節(jié)讀取出廠VDDA為3V3時(shí)采樣1.2V電壓的采樣校準(zhǔn)值,由以上9.3章節(jié)ADC內(nèi)部1.2V參考電壓通道的配置和使能,ADC的1.2V采樣電壓的校準(zhǔn)值根據(jù)以上章節(jié)6表述的公式,結(jié)合ADC的1.2V通道15的實(shí)時(shí)采樣值可用于反推VDDA的電壓值,同時(shí)該采樣校準(zhǔn)值換算成電壓值后可間接作為ADC多通道連續(xù)采樣的參考電壓。
ADC內(nèi)部1.2V參考電壓實(shí)時(shí)采樣值,ADC各通道采樣值的讀取并換算成電壓值以及在main函數(shù)初始化UART1打印功能,ADC外設(shè)的初始化,讀取ADC采樣1.2V的校準(zhǔn)值,在while(1)主循環(huán)中調(diào)用獲取ADC各通道采樣電壓值函數(shù)的詳細(xì)實(shí)現(xiàn)的代碼如下所示。本示例通過UART1每隔200ms毫秒打印輸出ADC各通道采樣并換算得到電壓值到串口調(diào)試助手。
?
/*?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各通道采樣換算得到的電壓值打印輸出到串口調(diào)試助手,測(cè)試結(jié)果分別為ADC_VDDA該值是通過讀取出廠VDDA為3V3時(shí)采樣1.2V電壓的采樣校準(zhǔn)值結(jié)合1.2V通道15的實(shí)時(shí)采樣值反推得到的VDDA(即VDD的電壓值)的電壓值。ADC_CH0采集1.0V電壓,實(shí)際采到1.03V,ADC_CH1接GND采集0V電壓,實(shí)際采集到0V,ADC_CH2采集0.50V電壓,實(shí)際采集到0.50V。其中ADC_CH15_VREF采集ADC內(nèi)部1.2V通道實(shí)時(shí)采樣得到的電壓值,采集到1.18V,該值可參考以上9.4章節(jié)表述的出廠VDDA為3V3時(shí)采樣1.2V電壓的采樣校準(zhǔn)值換算得到的電壓值接近。

圖2
7
如下圖3所示,換一組電壓采集,ADC_CH0采集2.50V電壓實(shí)際采集到2.51V,ADC_CH1采集3.32V電源電壓實(shí)際采集到3.31V,ADC_CH2采集1.50V電壓,實(shí)際采到1.50V電壓。以上測(cè)試均在ADC允許的誤差范圍。

圖3
審核編輯:劉清
電子發(fā)燒友App




評(píng)論