本文例子參考《STM32單片機開發實例——基於Proteus虛擬模擬與HAL/LL庫》 源代碼:https://github.com/LanLinnet/STM33F103R6 項目要求 單片機每隔1s以“YYYY-MM-DD HH:MM:SS”的格式自動向串口輸出日期和時間信息(“ASCII格式” ...
本文例子參考《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
,配置如下,用來查看單片機收到的串口數據,具體參考第11節。
-
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”開始自動走時。