1. 程式人生 > 其它 >14-CubeMx+Keil+Proteus模擬STM32 - RTC

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,無校驗。

硬體設計

  1. 第一節的基礎上,在Proteus中新增電路如下圖所示。

    除錯過程也可以新增一個虛擬儀器VIRTUAL TERMINAL,配置如下,用來檢視微控制器收到的串列埠資料,具體參考

    第11節

  2. RTC簡介:
    1)RTC是Real Time Clock(實時時鐘)的首字母縮寫形式,是一種常用的電子功能模組,有獨立的RTC晶片,也有集成於微控制器內的獨立功能模組,常用於製作電子鐘、電子錶、電子萬年曆等計時工具。
    2)STM32微控制器的RTC可以看作特殊的定時器,它可以根據輸入的時鐘源自動計時,此外還提供了1個“鬧鐘”中斷源和1個“秒”中斷源。

  3. 開啟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_TXUSART1_RX,即USART1的傳送端和接收端。

    再點選“NVIC Settings”,選中USART global interruptEXTI line[9:5] interrupts,使能Enabled串列埠1的中斷功能和GPIO的外部中斷。

    最後,實踐中為了追求時間的精度,我們會採用外部低速晶振LSE作為RTC的時鐘源,由於本次採用Proteus進行模擬,我們選擇預設的LSI作為RTC的時鐘源。

  4. 點選“Generator Code”生成Keil工程。

軟體編寫

  1. 本次我們需要實現實時時鐘自動走時,並通過串列埠傳送輸出,需要用到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碼資料格式
  2. 點選“Open Project”在Keil中開啟工程,雙擊“main.c”檔案。

  3. 首先我們需要在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 */
    

聯合除錯

  1. 點選執行,生成HEX檔案。
  2. 在Proteus中載入相應HEX檔案,點選執行。可以看到“Virtual Terminal”從“2022-05-20 05:20:00”開始自動走時,每秒輸出一個結果,按下BTN按鍵,又重新從“2022-05-20 05:20:00”開始自動走時。