引言
本文主要從BKP備份寄存器和RTC實時時鐘的原理,特性及應用三個方面展開討論,解析它們在STM32中的獨特價值,助力開發者更好的掌握和運用它們。
BKP備份寄存器的定義
STM32的BKP備份寄存器是一種特殊的存儲單元,它位于備份區域,即使在系統復位或電源關閉時,也能通過電池備份保持數據不丟失。它通常包含多個寄存器,用于存儲關鍵數據,如配置信息、狀態標志等。這些寄存器通過低功耗設計和獨立的備份電源,確保數據在主電源失效時仍能安全保存,為系統恢復和數據完整性提供可靠保障。
簡單來講,BKP備份寄存器可用于存儲用戶的程序數據,當VDD(也就是芯片電源)被切斷后,仍然可以通過VBAT引腳外接一個紐扣電池(通常在1.8v到3.6v)向芯片供電,讓系統處于低功耗模式下維持一些功能的運行,當系統或電源復位,它也不會被復位。
硬件設計
BKP備份寄存器與RTC實時時鐘的關系
首先,它們兩個是緊密相關的功能模塊,它們共同為系統提供數據部分和時間管理的功能,它們都是共享VBAT備用電源。
其次,BKP備份寄存器是用于數據的備份,而RTC實時時鐘模塊本身用于時間計數,所以RTC實時時鐘需要BKP備份寄存器來存儲一些數據。
BKP備份寄存器的特性及應用
我認為BKP備份寄存器最大的特性就是斷電不丟失數據,當然,如果VDD和VBAT同時斷電的話,那它就發揮不出它的作用了。很顯然,它的特性決定著它的應用,如低功耗模式下的數據保持,防拆功能(TAMPER)等。
配置TAMPER(防拆功能)的示例代碼
首先是使能PWR和BKP時鐘,開啟PWR時鐘是因為訪問備份域是由PWR模塊進行控制的,所以必須要使能它
void BKP_Init(void)
{// 使能PWR和BKP時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);// 使能訪問備份寄存器PWR_BackupAccessCmd(ENABLE);
}
其次是配置PC13引腳,因為大部分的TAMPER引腳都是PC13,可根據實際需求更改
void TAMPER_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 配置TAMPER引腳(PC13)為輸入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOC, &GPIO_InitStructure);// 配置TAMPER引腳為高電平有效BKP_TamperPinLevelConfig(BKP_TamperPinLevel_High);// 使能TAMPER引腳功能BKP_TamperPinCmd(ENABLE);
}
接著封裝一下寫入數據和讀出數據的函數
void BKP_WriteData(uint16_t Data)
{// 寫入數據到備份寄存器1BKP_WriteBackupRegister(BKP_DR1, Data);
}uint16_t BKP_ReadData(void)
{// 從備份寄存器1讀取數據return BKP_ReadBackupRegister(BKP_DR1);
}
最后是檢查TAMPER事件標志位,建議放在while循環中不斷查詢,當然,用戶可以在里面調用一些TAMPER事件發生后執行的函數,如通過串口打印輸出等,這里就不調用了。
void BKP_CheckTamper(void)
{// 檢查TAMPER事件標志位if (BKP_GetFlagStatus(BKP_FLAG_TAMP) != RESET){// 清除TAMPER事件標志位BKP_ClearFlag(BKP_FLAG_TAMP);}
}
總結一下
該示例代碼的邏輯思路是初始化BKP和TAMPER引腳,接著把想寫的數據寫入到備份寄存器中,然后再把寫入的數據讀出來,再關掉VDD同時保持VBAT連接備用電源,如果寫入的數據沒有被刪除,那這個BKP備份寄存器實驗就是成功的。同時將TAMPER引腳置于低電平,如果TAMPER事件發生,那么這個防拆功能的實驗也是成功的。
RTC實時時鐘定義
RTC(Real-Time Clock,實時時鐘)是一種硬件電路,用于為電子設備提供精確的時間和日期信息。它通常獨立于主處理器運行,即使在系統關閉或斷電時,也能通過備用電池繼續計時。RTC的主要功能是保持時間的連續性,提供秒、分、時、日、月、年的準確記錄,并支持鬧鐘和周期性喚醒功能。它廣泛應用于嵌入式系統、智能設備和低功耗應用中,確保設備在任何情況下都能準確地跟蹤時間。
RTC實時時鐘特性與應用
RTC實時時鐘具有高精度,低功耗,掉電保持的特性,廣泛應用于時鐘,日歷,數據采集等。
RTC實時時鐘示例代碼
1,設置實時時鐘時間函數
#include "time.h"uint32_t MyRTC_Time[] = {2025,8,18,10,41,00}; //定義全局的時間數組,數組內容分別為年、月、日、時、分、秒void MyRTC_SetTime(void)
{time_t time_cnt; //定義秒計數器數據類型struct tm time_date; //定義日期時間數據類型// 將數組的時間賦值給日期時間結構體time_date.tm_year = MyRTC_Time[0] - 1900; // 年份,從1900開始計算time_date.tm_mon = MyRTC_Time[1] - 1; // 月份,從0開始(0表示1月)time_date.tm_mday = MyRTC_Time[2]; // 日期time_date.tm_hour = MyRTC_Time[3]; // 小時time_date.tm_min = MyRTC_Time[4]; // 分鐘time_date.tm_sec = MyRTC_Time[5]; // 秒// 調用mktime函數,將日期時間轉換為秒計數器格式// - 8 * 60 * 60為東八區的時區調整time_cnt = mktime(&time_date) - 8 * 60 * 60;// 將秒計數器寫入到RTC的CNT中RTC_SetCounter(time_cnt);// 等待上一次操作完成RTC_WaitForLastTask();
}
從全局數組 MyRTC_Time[]中讀取時間值,將讀取的時間變量賦值給struct tm類型的變量time_data,再使用mktime函數將struct tm轉換為秒計數器格式,并調整時區。
2,RTC初始化函數
void MyRTC_Init(void)
{/*開啟時鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //開啟PWR的時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); //開啟BKP的時鐘/*備份寄存器訪問使能*/PWR_BackupAccessCmd(ENABLE); //使用PWR開啟對備份寄存器的訪問if (BKP_ReadBackupRegister(BKP_DR1) != 0x0000) //通過寫入備份寄存器的標志位,判斷RTC是否是第一次配置//if成立則執行第一次的RTC配置{RCC_LSEConfig(RCC_LSE_ON); //開啟LSE時鐘while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET); //等待LSE準備就緒RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //選擇RTCCLK來源為LSERCC_RTCCLKCmd(ENABLE); //RTCCLK使能RTC_WaitForSynchro(); //等待同步RTC_WaitForLastTask(); //等待上一次操作完成RTC_SetPrescaler(32768 - 1); //設置RTC預分頻器,預分頻后的計數頻率為1HzRTC_WaitForLastTask(); //等待上一次操作完成MyRTC_SetTime(); //設置時間,調用此函數,全局數組里時間值刷新到RTC硬件電路BKP_WriteBackupRegister(BKP_DR1, 0x0000); //在備份寄存器寫入自己規定的標志位,用于判斷RTC是不是第一次執行配置}else //RTC不是第一次配置{RTC_WaitForSynchro(); //等待同步RTC_WaitForLastTask(); //等待上一次操作完成}
}
首先判斷寫入BKP備份寄存器里面的BKP_DR1是不是等于0x0000,這個是提前寫入的值,當然,這個值可以自定義,這個判斷操作是檢查VBAT是否斷開,如果斷開就需要重新配置,選擇外部低速晶振,也就是我們常見的32.768khz,再進行預分頻為1hz,最后再調用刷新時間的函數,就初始化完成了。
3,RTC讀取時間函數
void MyRTC_ReadTime(void)
{time_t time_cnt; //定義秒計數器數據類型struct tm time_date; //定義日期時間數據類型time_cnt = RTC_GetCounter() + 8 * 60 * 60; //讀取RTC的CNT,獲取當前的秒計數器//+ 8 * 60 * 60為東八區的時區調整time_date = *localtime(&time_cnt); //使用localtime函數,將秒計數器轉換為日期時間格式MyRTC_Time[0] = time_date.tm_year + 1900; //將日期時間結構體賦值給數組的時間MyRTC_Time[1] = time_date.tm_mon + 1;MyRTC_Time[2] = time_date.tm_mday;MyRTC_Time[3] = time_date.tm_hour;MyRTC_Time[4] = time_date.tm_min;MyRTC_Time[5] = time_date.tm_sec;
}
最后在需要的地方調用此函數,就可以獲取時間了。
總結
本文介紹了STM32的BKP備份寄存器與RTC實時時鐘功能。BKP寄存器可在系統復位后保存關鍵數據,確保數據的連續性。RTC模塊則提供精確的時間管理,支持時鐘設置、時間更新等功能,二者結合可實現低功耗、高可靠性的數據備份與時間記錄,適用于多種嵌入式應用場景。