STM32系列MCU單片機芯片很多時候我們需要將程序中的一些參數(shù)、數(shù)據(jù)等存儲在EEPROM或者Flash中,達到掉電保存的目的。但有些情況下,程序需要頻繁的修改這些參數(shù),如果每次修改參數(shù)都進行一次保存,那將大大降低存儲器的壽命。尤其是單片機內(nèi)部Flash,以STM32F030K6T6為例的MCU芯片,擦寫壽命只有1000次。當然,這是最小值,實際可能比這個多,但也是有風險。
因此,最好的辦法就是在程序運行中不進行保存操作,只在斷電時保存一次。
掉電保存的關(guān)鍵是怎樣檢測掉電瞬間,方法有很多種:
1 通過外部電路檢測電源,觸發(fā)IO中斷。
2 通過單片機的PVD(可編程電壓檢測器) 中斷檢測。
3 通過ADC看門狗中斷檢測。
不管哪種方式,一般都是通過中斷來實現(xiàn),主要是為了快速響應(yīng)。
今天主要介紹第三種方式,通過ADC看門狗實現(xiàn)掉電保存。
02
? 硬件設(shè)計??
2.1掉電時間
掉電保存的前提是斷電后電源電壓是緩慢下降的,這樣才有足夠的時間去檢測掉電并保存數(shù)據(jù)。因此,電源上必須有個大電容,保證電源斷開后能繼續(xù)給MCU單片機供電。
具體需要維持多長時間,要看存儲器的擦寫周期。以STM32F030K6T6的MCU內(nèi)部存儲器為例,擦除一頁需要30ms,寫入一個16位數(shù)據(jù)需要53.5us。根據(jù)實際需要擦除和寫入的數(shù)據(jù)多少來計算至少需要多少時間。
還需要關(guān)注一個參數(shù),編程電壓。在用示波器測量掉電時的波形時,測量出從斷電瞬間到電壓降低到2.4V時的時間,該時間大于總的數(shù)據(jù)擦寫的時間即可。當然要留有一定裕量。如果時間不夠,就要加大電容了。
2.2ADC檢測
? ? ? ?ADC檢測掉電的方式有兩種,一種是通過某個通道直接采集電源電壓(或者分壓后采集),另一種是采集內(nèi)部參考電壓Vrefint來判斷電源電壓。
第一種方式很好理解,采樣值就代表電源電壓,可以直接去觸發(fā)ADC的看門狗中斷。
第二種方式由于內(nèi)部參考電壓是不變的,STM32F030是1.23V,有一定誤差。當電源電壓變化時,ADC采集的參考電壓會發(fā)生變化,因此也可以通過這個變化觸發(fā)看門狗中斷。這里有個前提,即單片機的VREF引腳或AVDD引腳就是要檢測的電源電壓。
03
? 軟件設(shè)計??
首先打開STM32CubeMx,配置一下ADC,如下。
首先需要使能Vrefint Channel,如果需要其它通道也可以使能。
其次需要使能ADC的看門狗,看門狗通道選擇Vrefint,設(shè)置一下高/低門限值,使能看門狗中斷模式,同時ADC的中斷也要打開。
這里的高/低門限是指,當ADC的采樣值大于高門限或小于低門限時,ADC的看門狗中斷將被觸發(fā)。
如果是用于掉電檢測,只要關(guān)心高門限就行。正常時ADC采樣值=1.23*4096/3.3,大約是1526左右,由于Vrefint和電源電壓都有誤差,所以只是個大概。如果我們將掉電電壓檢測值設(shè)為3.1V,那對應(yīng)的ADC看門狗的高門限值應(yīng)為1.23*4096/3.1,約1625左右。
生成代碼后,在初始化完成啟動ADC采樣,如下:
uint32_t adc_buf;
HAL_ADCEx_Calibration_Start(&hadc);
HAL_Delay(100);
HAL_ADC_Start_DMA(&hadc,(uint32_t*)&adc_buf,1);
然后再ADC的中斷中添加保存數(shù)據(jù)的程序即。
void ADC1_IRQHandler(void)
{
? /* USER CODE BEGIN ADC1_IRQn 0 */
? /* USER CODE END ADC1_IRQn 0 */
? HAL_ADC_IRQHandler(&hadc);
? /* USER CODE BEGIN ADC1_IRQn 1 */
? Save_Param();? //保存參數(shù)
? while(1);
? /* USER CODE END ADC1_IRQn 1 */
}
這里有兩點需要注意:
一是在中斷中先關(guān)閉功耗較大的外設(shè),比如液晶背光、數(shù)碼管等。使斷電時電源電壓下降不至于太快。
二是在保存數(shù)據(jù)后關(guān)閉看門狗中斷,或者直接死循環(huán)(因為已經(jīng)斷電,也不需要執(zhí)行其它程序了)。這樣做主要是為了防止電壓下降的太慢,多次觸發(fā)看門狗中斷,導致最后一次寫入錯誤。