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
審核編輯:劉清
評論
查看更多