在做低功耗產(chǎn)品的時(shí)候讀取芯片溫度和當(dāng)前電壓是十分重要的一件事情。通過(guò)當(dāng)前供電電壓可以知曉電池電量是否低于水平值實(shí)現(xiàn)電池缺電報(bào)警。讀取芯片溫度也很重要,可以在使用內(nèi)部振蕩器的時(shí)候通過(guò)校準(zhǔn)算法根據(jù)溫度變化來(lái)實(shí)現(xiàn)實(shí)時(shí)校準(zhǔn)芯片。如果不使用或盡量少使用外部元器件來(lái)實(shí)現(xiàn)這兩個(gè)功能是擺在我們面前一個(gè)很重要的事情,遺憾的是現(xiàn)在網(wǎng)上的資料非常混亂,基本上直接使用總有點(diǎn)那么別扭。如何讀取芯片電壓?當(dāng)然肯定是需要用ADC了。不過(guò)這個(gè)時(shí)候需要有一個(gè)參考電壓作為比對(duì),很多人提出在外面使用一組LDO實(shí)現(xiàn)參考電壓,那樣其實(shí)LDO本身也有一定能耗,在我們追求極致低消耗的時(shí)候也不適合。當(dāng)然很多人說(shuō)了為什么不使用PVD來(lái)做,那么我來(lái)說(shuō)說(shuō),PVD本身是做電壓曲線檢測(cè)的,如果你要求低于2.5V就報(bào)警,你會(huì)發(fā)現(xiàn)如果你啟動(dòng)電壓<2.5V的時(shí)候無(wú)法檢測(cè)出來(lái)。所以還是自己做。還好STM32L0單片機(jī)在內(nèi)部有一個(gè)核心電壓,并且有一個(gè)寄存器VREFINT_CAL值可以用作基準(zhǔn)參考從而計(jì)算出相當(dāng)比較精準(zhǔn)的電壓。經(jīng)過(guò)測(cè)量,誤差還是基本滿足電池供電檢測(cè)的要求。如何讀取芯片溫度?在STM32L0下,只要讀到當(dāng)前電壓,配合溫度寄存器,就可以取得當(dāng)前溫度了。當(dāng)前溫度誤差比較大,即使高精度采樣,為了節(jié)省運(yùn)算時(shí)間,誤差還是有3度的誤差,因此這個(gè)地方需要寬泛一些。
#include "stm32l0xx_ll_adc.h" //需要這個(gè)庫(kù)實(shí)現(xiàn)公式計(jì)算//初始化void init_adc1(void){ ADC_ChannelConfTypeDef sConfig;
hadc.Instance = ADC1; hadc.Init.OversamplingMode = DISABLE; hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1; hadc.Init.Resolution = ADC_RESOLUTION_12B;//ADC_RESOLUTION_12B; hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5; //160.5cycles如果低于39.5cycles溫度采樣精準(zhǔn)度不夠 hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ContinuousConvMode = DISABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DMAContinuousRequests = DISABLE; hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerFrequencyMode = DISABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; if (HAL_ADC_Init(&hadc) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }/**Configure for the selected ADC regular channel to be converted. */ sConfig.Channel = ADC_CHANNEL_VREFINT; //初始化VREFINT_CAL參考電壓 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; //初始化芯片溫度傳感器 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }}//讀取adc1值uint16_t readchannel_adc1(uint32_t Channel){ ADC_ChannelConfTypeDef adcConf; uint16_t adcData = 0; /* wait the the Vrefint used by adc is set */ while (__HAL_PWR_GET_FLAG(PWR_FLAG_VREFINTRDY) == RESET) {};//啟動(dòng)CLK時(shí)鐘 __HAL_RCC_ADC1_CLK_ENABLE();
/*calibrate ADC if any calibraiton hardware*/ HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED );
/* Deselects all channels*/ adcConf.Channel = ADC_CHANNEL_MASK; adcConf.Rank = ADC_RANK_NONE; HAL_ADC_ConfigChannel( &hadc, &adcConf);
/* configure adc channel */ adcConf.Channel = Channel; adcConf.Rank = ADC_RANK_CHANNEL_NUMBER; HAL_ADC_ConfigChannel( &hadc, &adcConf);
/* Start the conversion process */ HAL_ADC_Start(&hadc);
/* Wait for the end of conversion */ HAL_ADC_PollForConversion( &hadc, HAL_MAX_DELAY );
/* Get the converted value of regular channel */adcData+=HAL_ADC_GetValue(&hadc);
__HAL_ADC_DISABLE(&hadc);
__HAL_RCC_ADC1_CLK_DISABLE();
return adcData;}//具體調(diào)用代碼void main(void){ init_adc1(); //完成初始化 uint16_tvdda_mV=__LL_ADC_CALC_VREFANALOG_VOLTAGE(readchannel_adc1(ADC_CHANNEL_VREFINT),LL_ADC_RESOLUTION_12B);//取得當(dāng)前VDDA的電壓,單位mV uint16_t temp_degress = __LL_ADC_CALC_TEMPERATURE(vdda_mV,readchannel_adc1(ADC_CHANNEL_TEMPSENSOR),LL_ADC_RESOLUTION_12B); //取得當(dāng)前的溫度,單位攝氏度}
-
芯片
+關(guān)注
關(guān)注
452文章
50216瀏覽量
420956 -
電壓
+關(guān)注
關(guān)注
45文章
5539瀏覽量
115490 -
STM32
+關(guān)注
關(guān)注
2264文章
10854瀏覽量
354302
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論