STM32CubeMX教程11 RTC 实时时钟 - 入侵检测和时间戳
使用STM32CubeMX軟件配置STM32F407開發(fā)板RTC實現(xiàn)入侵檢測和時間戳功能,具體為周期喚醒回調(diào)中使用串口輸出當前RTC時間,按鍵WK_UP存儲當前RTC時間到備份寄存器,按鍵KEY_2從備份寄存器中讀取上次存儲的時間,按鍵KEY_1負責產(chǎn)生入侵事件
1、準備材料
開發(fā)板(正點原子stm32f407探索者開發(fā)板V2.4)
ST-LINK/V2驅(qū)動
STM32CubeMX軟件(Version 6.10.0)
keil μVision5 IDE(MDK-Arm)
CH340G Windows系統(tǒng)驅(qū)動程序(CH341SER.EXE)
XCOM V2.6串口助手
杜邦線一根
2、實驗目標
使用STM32CubeMX軟件配置STM32F407開發(fā)板RTC實現(xiàn)入侵檢測和時間戳功能,具體為周期喚醒回調(diào)中使用串口輸出當前RTC時間,按鍵WK_UP存儲當前RTC時間到備份寄存器,按鍵KEY_2從備份寄存器中讀取上次存儲的時間,按鍵KEY_1負責產(chǎn)生入侵事件
3、實驗流程
3.0、前提知識
STM32F407的RTC上有兩個入侵檢測模塊,但是筆者使用的LQFP144封裝的STM32F407ZGT6只有一個入侵檢測模塊,只有一個入侵檢測模塊的STM32F407單片機是利用RTC_AF1(PC13)引腳來進行觸發(fā)的,和按鍵外部中斷類似,如果設置入侵檢測觸發(fā)為低電平觸發(fā),那么當PC13為低電平時就會進入Tampere1事件回調(diào)函數(shù),當發(fā)生入侵事件時,RTC的20個備份寄存器中的值會全部丟失
由于開發(fā)板上PC13引腳并沒有按鍵控制,不方便實現(xiàn)其電平的翻轉(zhuǎn)變化操作,因此本實驗需要一根杜邦線,將按鍵KEY_1所使用的PE3引腳與PC13引腳短接,相當于使用按鍵KEY_1來間接控制PC13的電平變化,如下圖所示,當按鍵KEY_1松開時,此時PE3/PC13狀態(tài)應該由外部上/下拉決定,而當按鍵KEY_1按下時,PE3/PC13的狀態(tài)應該為低電平,通過設置PC13外部上拉,就可以實現(xiàn)KEY_1按鍵松開時為高電平,按下為低電平
3.1、CubeMX相關配置
請閱讀“STM32CubeMX教程10 RTC 實時時鐘 - 周期喚醒、鬧鐘A/B事件和備份寄存器”實驗3.1.1小節(jié)配置RCC和SYS
3.1.1、時鐘樹配置
系統(tǒng)時鐘樹配置與上一實驗一致,均設置為STM32F407總線能達到的最高時鐘頻率,配置LSE,RTC時鐘頻率為32.768kHz,具體如下圖所示
3.1.2、外設參數(shù)配置
本實驗需要需要初始化USART1作為輸出信息渠道,具體配置步驟請閱讀“STM32CubeMX教程9 USART/UART 異步通信”
單擊Pinout & Configuration頁面左邊Timers/RTC,并在頁面中間激活日歷,周期喚醒WakeUp采用內(nèi)部模式,勾選入侵檢測1將其輸入復用到引腳RTC_AF1(PC13),則此后PC13引腳便作為入侵檢測引腳,具體配置如下圖所示
與上一小節(jié)實驗類似,需要配置RTC通用參數(shù)、日歷日期時間、周期喚醒參數(shù)和入侵檢測參數(shù)
① 濾波設置中,如果不濾波則入侵檢測的觸發(fā)方式只能選擇邊沿觸發(fā),而如果選擇濾波,則觸發(fā)方式只能選擇電平觸發(fā),這里由于使用的機械按鍵存在抖動,因此對輸入濾波
② 入侵引腳是否上拉設置中,如上述3.0小節(jié)所述,我們需要PE3/PC13外部上拉才能實現(xiàn)目標,因此此處選擇上拉
③ 保存了入侵時間戳就可以在Tampere1事件回調(diào)函數(shù)中使用HAL_RTCEx_GetTimeStamp獲取入侵時間戳
④ 入侵檢測觸發(fā)方式設置中,由于按鍵按下為低電平,因此這里選擇低電平
3.1.3、外設中斷配置
在Pinout & Configuration頁面左邊System Core/NVIC中勾選入侵檢測及周期喚醒中斷,然后選擇合適的中斷優(yōu)先級即可
3.2、生成代碼
請先閱讀“STM32CubeMX教程1 工程建立”實驗3.4.3小節(jié)配置Project Manager
單擊頁面右上角GENERATE CODE生成工程
3.2.1、外設初始化調(diào)用流程
與上一小節(jié)RTC初始化函數(shù)MX_RTC_Init對比,可以發(fā)現(xiàn)本小節(jié)的初始化函數(shù)中減少了鬧鐘A/B的初始化,但是新增加了入侵檢測的初始化,如下圖所示,也即我們在CubeMX中設置的參數(shù),類似的中斷相關的初始化設置仍然在HAL_RTC_MspInit函數(shù)中
3.2.2、外設中斷調(diào)用流程
在CubeMX中勾選RTC入侵檢測啟動中斷后,在stm32f4xx_it.c中均會生成對應的中斷服務函數(shù)TAMP_STAMP_IRQHandler()
在該TAMP_STAMP_IRQHandler()中斷服務函數(shù)中調(diào)用了HAL庫HAL_RTCEx_TamperTimeStampIRQHandler()函數(shù)統(tǒng)一處理時間戳/入侵事件
最終根據(jù)發(fā)生的事件來源調(diào)用了時間戳事件回調(diào)函數(shù)HAL_RTCEx_TimeStampEventCallback()、入侵檢測1事件回調(diào)函數(shù)HAL_RTCEx_Tamper1EventCallback()和入侵檢測2事件HAL_RTCEx_Tamper2EventCallback()
具體流程如下圖所示
3.2.3、添加其他必要代碼
由于無入侵檢測2,筆者這里只實現(xiàn)了入侵檢測1事件回調(diào)函數(shù)HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc),將其實現(xiàn)在了rtc.c中,另外周期喚醒回調(diào)函數(shù)內(nèi)容與上一小結(jié)內(nèi)容一致,這里不再贅述,入侵檢測1事件回調(diào)函數(shù)具體代碼如下圖所示
源代碼如下
/*Tampere1事件回調(diào)函數(shù)*/
void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
if(HAL_RTCEx_GetTimeStamp(hrtc, &sTime, &sDate, RTC_FORMAT_BIN) == HAL_OK)
{
char str[24];
sprintf(str,"TimeStamp = %2d:%2d:%2d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
printf("Tampere1 Event Happend, %s", str);
}
HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port,GREEN_LED_Pin);
}
經(jīng)過了上述的過程之后目前還缺少兩個操作,利用按鍵WK_UP存儲當前RTC時間到備份寄存器,按鍵KEY_2從備份寄存器中讀取上次存儲的時間,其代碼實現(xiàn)在了主函數(shù)主循環(huán)中,簡單采用輪詢的方式處理按鍵,如下圖所示
源代碼如下
/*按下WK_UP按鍵將當前時間存儲到備份寄存器*/
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == GPIO_PIN_SET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == GPIO_PIN_SET)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
if(HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN) == HAL_OK)
{
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR2, sTime.Hours);
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR3, sTime.Minutes);
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR4, sTime.Seconds);
char timeStr[30];
sprintf(timeStr,"%2d:%2d:%2d",sTime.Hours,sTime.Minutes,sTime.Seconds);
printf("Store %s to the backup register\r\n", timeStr);
while(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin));
}
}
}
/*按下KEY2按鍵將存儲到備份寄存器的時間利用串口輸出*/
if(HAL_GPIO_ReadPin(KEY_2_GPIO_Port,KEY_2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY_2_GPIO_Port,KEY_2_Pin) == GPIO_PIN_RESET)
{
uint32_t sHour,sMinute,sSecond;
sHour = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2); //Hour
sMinute = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3); //Minute
sSecond = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4); //Second
char timeStr[30];
sprintf(timeStr,"%u:%u:%u",sHour,sMinute,sSecond);
printf("Read out %s from the backup register\r\n", timeStr);
while(!HAL_GPIO_ReadPin(KEY_2_GPIO_Port,KEY_2_Pin));
}
}
4、常用函數(shù)
/*時間戳回調(diào)函數(shù)*/
void HAL_RTCEx_TimeStampEventCallback(RTC_HandleTypeDef *hrtc)
/*Tampere1事件回調(diào)函數(shù)*/
void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc)
/*Tampere2事件回調(diào)函數(shù)*/
void HAL_RTCEx_Tamper2EventCallback(RTC_HandleTypeDef *hrtc)
/*獲取RTC時間戳*/
HAL_StatusTypeDef HAL_RTCEx_GetTimeStamp(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTimeStamp, RTC_DateTypeDef *sTimeStampDate, uint32_t Format)
5、燒錄驗證
5.1、具體步驟
“RTC Mode and Configuration中啟用內(nèi)部模式的WakeUp周期喚醒 -> 勾選入侵檢測Tamper1 Routed to AF1 -> 配置合適的日歷通用參數(shù)、日歷日期時間、周期喚醒參數(shù)和入侵檢測參數(shù) -> NVIC中勾選RTC周期喚醒中斷及RTC入侵檢測中斷,并選擇合適的中斷優(yōu)先級 -> 在生成的工程代碼中重新實現(xiàn)周期喚醒回調(diào)函數(shù)、Tampere1事件回調(diào)函數(shù)HAL_RTCEx_Tamper1EventCallback -> 添加必要的代碼邏輯(具體看上述3.2)”
5.2、實驗現(xiàn)象
燒錄程序,利用杜邦線短接PE3和PC13,當開發(fā)板上電后,會在周期喚醒回調(diào)函數(shù)中不斷地輸出當前RTC的時間,另外開發(fā)板上的紅色LED燈也會不斷地閃爍,當按下開發(fā)板上的WK_UP按鍵之后會將當前RTC日歷的時間存儲到備份寄存器RTC_BKP_DR2~4中,按下開發(fā)板上的KEY_2按鍵可以從備份寄存器中將上次存儲的時間讀出來
然后當按下按鍵KEY_1的時候,會發(fā)生入侵事件,此時入侵被檢測到,會觸發(fā)Tampere1事件回調(diào)函數(shù)通過串口輸出入侵事件的信息,并且如果再去通過KEY_2按鍵讀取備份寄存器中存儲的時間會發(fā)現(xiàn)由于入侵的發(fā)生,備份寄存器中的值已經(jīng)被清空
上述整個流程串口輸出信息如下圖所示
6、奇怪的現(xiàn)象
有時候會出現(xiàn)寫備份寄存器寫不進去的情況,如果你也遇到了,可以嘗試將開發(fā)板完全斷電(電源線、USB串口和調(diào)試器接口),然后重新上電復位再向備份寄存器中寫入試試
參考資料
STM32Cube高效開發(fā)教程(基礎篇)
更多內(nèi)容請瀏覽 OSnotes的CSDN博客
總結(jié)
以上是生活随笔為你收集整理的STM32CubeMX教程11 RTC 实时时钟 - 入侵检测和时间戳的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高可用架构,去中心化有多重要?
- 下一篇: uniapp中实现H5录音和上传、实时语