14-CubeMx+Keil+Proteus模擬STM32 - RTC
本文例子參考《STM32微控制器開發例項——基於Proteus虛擬模擬與HAL/LL庫》
原始碼:https://github.com/LanLinnet/STM33F103R6
專案要求
微控制器每隔1s以“YYYY-MM-DD HH:MM:SS”的格式自動向串列埠輸出日期和時間資訊(“ASCII格式”),起始時間設為“2022-05-20 05:20:00”,自動走時。按下按鈕BTN,時間自動恢復為起始時間。串列埠通訊引數:波特率為19200bit/s,無校驗。
硬體設計
-
在第一節的基礎上,在Proteus中新增電路如下圖所示。
除錯過程也可以新增一個虛擬儀器VIRTUAL TERMINAL
,配置如下,用來檢視微控制器收到的串列埠資料,具體參考 -
RTC簡介:
1)RTC是Real Time Clock(實時時鐘)的首字母縮寫形式,是一種常用的電子功能模組,有獨立的RTC晶片,也有集成於微控制器內的獨立功能模組,常用於製作電子鐘、電子錶、電子萬年曆等計時工具。
2)STM32微控制器的RTC可以看作特殊的定時器,它可以根據輸入的時鐘源自動計時,此外還提供了1個“鬧鐘”中斷源和1個“秒”中斷源。 -
開啟CubeMX,建立工程。
首先,設定PA5為GPIO_EXTI5
,點選“Categories”中的“GPIO”,將"GPIO mode"設定為External Interrupt Mode With Falling edge trigger detection
隨後,點選“Timers”列表中的“RTC”進行實時時鐘配置。選中“Active Clock Source”和“Active Calendar”複選框,啟用時鐘源和日曆。在“Parameter Settings”中設定時間和日期如下圖所示。其中,“Data Format”設定資料格式有2個選項:“Binary Data Format”(字面意思是二進位制資料格式,實際是十進位制資料格式)和“BCD Data Format”(BCD碼資料格式),實際設定時間時任意選其中一個即可。
然後,點選“Connectivity”列表中的“USART”進行串列埠配置。將Mode設定為Asynchronous
19200Bits/s
,字長設為8Bits
,校驗設為None
,停止位設為1
,資料傳送設為Receive and Transmit
(接收與傳送)。設定完成後,會看到右側的PA9和PA10引腳被自動設定為USART1_TX
和USART1_RX
,即USART1的傳送端和接收端。
再點選“NVIC Settings”,選中USART global interrupt
和EXTI line[9:5] interrupts
,使能Enabled
串列埠1的中斷功能和GPIO的外部中斷。
最後,實踐中為了追求時間的精度,我們會採用外部低速晶振LSE作為RTC的時鐘源,由於本次採用Proteus進行模擬,我們選擇預設的LSI作為RTC的時鐘源。
-
點選“Generator Code”生成Keil工程。
軟體編寫
-
本次我們需要實現實時時鐘自動走時,並通過串列埠傳送輸出,需要用到RTC相關函式其API文件如下:
HAL_RTC_GetTime RTC時間獲取函式
HAL_RTC_GetDate RTC日期獲取函式
HAL_RTC_SetTime RTC時間設定函式
HAL_RTC_SetDate RTC日期設定函式
其中,介紹兩個結構體:
時間結構體sTime
有以下3個元素- Hours(時),資料型別為uint8_t。
- Minutes(分),資料型別為uint8_t。
- Seconds(秒),資料型別為uint8_t。
日期結構體
sDate
有以下4個元素- Year(年),資料型別為uint8_t,取值範圍為0-99(BIN格式)或0-0x99(BCD格式)。
- Month(月),資料型別為uint8_t,取值範圍為1-12(BIN格式)或1-0x12(BCD格式)。
- Date(日),資料型別為uint8_t,取值範圍為1-31(BIN格式)或1-0x31(BCD格式)。
- WeekDay(星期),資料型別為uint8_t,取值範圍為1-7。
另外,
Format
有以下2個巨集定義選項- RTC_FORMAT_BIN:字面意思是二進位制資料格式,實際是十進位制資料格式
- RTC_FORMAT_BCD:BCD碼資料格式
-
點選“Open Project”在Keil中開啟工程,雙擊“main.c”檔案。
-
首先我們需要在main.c檔案中的最前面引入標準輸入輸出標頭檔案
/* USER CODE BEGIN Includes */ #include "stdio.h" /* USER CODE END Includes */
在main函式中定義日期結構體和時間結構體
/* USER CODE BEGIN 1 */ //定義日期結構體和時間結構體 RTC_DateTypeDef sDateStructure; RTC_TimeTypeDef sTimeStructure; char sYear[5]; char sMonth[3]; char sDate[3]; char sHour[3]; char sMin[3]; char sSec[3]; /* USER CODE END 1 */
隨後,在
/* USER CODE BEGIN 4 */
和/* USER CODE END 4 */
中插入外部中斷回撥函式,程式碼如下/* USER CODE BEGIN 4 */ //外部中斷回撥函式 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { //定義日期結構體和時間結構體 RTC_DateTypeDef sDateStructure; RTC_TimeTypeDef sTimeStructure; if(GPIO_Pin == GPIO_PIN_5) //檢測到EXTI5線產生外部中斷事件 { //設定日期 sDateStructure.Year = 22; sDateStructure.Month = 5; sDateStructure.Date = 20; sDateStructure.WeekDay = 5; //十進位制格式 HAL_RTC_SetDate(&hrtc, &sDateStructure, RTC_FORMAT_BIN); //設定時間 sTimeStructure.Hours = 0x05; sTimeStructure.Minutes = 0x20; sTimeStructure.Seconds = 0; //BCD碼格格式 HAL_RTC_SetTime(&hrtc, &sTimeStructure, RTC_FORMAT_BCD); while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET); //直到按鍵鬆開 } } /* USER CODE END 4 */
最後,在
while(1)
中插入程式碼如下,進行RTC和串列埠傳送相關操作/* USER CODE BEGIN WHILE */ while (1) { //十進位制格式 HAL_RTC_GetTime(&hrtc, &sTimeStructure, RTC_FORMAT_BIN); //RTC時間獲取函式 //BCD碼格式 HAL_RTC_GetDate(&hrtc, &sDateStructure, RTC_FORMAT_BCD); //RTC日期獲取函式 //格式轉換為字串 sprintf(sYear, "%04x", 0x2000+sDateStructure.Year); sprintf(sMonth, "%02x", sDateStructure.Month); sprintf(sDate, "%02x", sDateStructure.Date); sprintf(sHour, "%02d", sTimeStructure.Hours); sprintf(sMin, "%02d", sTimeStructure.Minutes); sprintf(sSec, "%02d", sTimeStructure.Seconds); //列印日期 HAL_UART_Transmit(&huart1, (uint8_t *)sYear, 4, 4); HAL_UART_Transmit(&huart1, (uint8_t *)&"-", 1, 1); HAL_UART_Transmit(&huart1, (uint8_t *)sMonth, 2, 2); HAL_UART_Transmit(&huart1, (uint8_t *)&"-", 1, 1); HAL_UART_Transmit(&huart1, (uint8_t *)sDate, 2, 2); HAL_UART_Transmit(&huart1, (uint8_t *)&" ", 1, 2); //列印時間 HAL_UART_Transmit(&huart1, (uint8_t *)sHour, 2, 2); HAL_UART_Transmit(&huart1, (uint8_t *)&":", 1, 1); HAL_UART_Transmit(&huart1, (uint8_t *)sMin, 2, 2); HAL_UART_Transmit(&huart1, (uint8_t *)&":", 1, 1); HAL_UART_Transmit(&huart1, (uint8_t *)sSec, 2, 2); HAL_UART_Transmit(&huart1, (uint8_t *)&"\n\r", 2, 2); //延時 HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
聯合除錯
- 點選執行,生成HEX檔案。
- 在Proteus中載入相應HEX檔案,點選執行。可以看到“Virtual Terminal”從“2022-05-20 05:20:00”開始自動走時,每秒輸出一個結果,按下BTN按鍵,又重新從“2022-05-20 05:20:00”開始自動走時。