Stm32CubeMX配置RTC時鐘

環境:

Stm32CubeMX V5.6.0

stm32F412RETx芯片,芯片的VBAT引腳接電池

RTC使用的外部晶振,內部的振盪器配置後斷電後不跑,原因未知,下面直接上使用外部晶振的方案


配置RTC使用外部晶振,外部晶振是32.768KHz的

配置RTC,啓用日曆和時鐘

stm32CubeMX默認填入的分頻是使用32.768KHz的,但是內部振盪器是32KHz的,所以估計都是推薦使用外部晶振,使用內部振盪器的自己按公式重新計算分頻值

公式如下:

RTC時鐘頻率 = RTC時鐘源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))

套用一下公式

32.768KHz / ((127+1)*(255+1)) = 1Hz,也就是1秒

年是從1970年算起的,其他月日時分秒以及24或者12小時制沒什麼好說的

數據格式Data Format,我使用Binary data format

stm32定義了RTC_FORMAT_BIN和RTC_FORMAT_BCD兩種格式

RTC_FORMAT_BIN:爲10進制,RTC_FORMAT_BCD爲16進制,開始我也是這樣認爲的,然後並不是

看一下stm32f4xx_hal_rtc.h頭文件中對月份的定義:

/** @defgroup RTC_Month_Date_Definitions RTC Month Date Definitions
  * @{
  */
/* Coded in BCD format */
#define RTC_MONTH_JANUARY              ((uint8_t)0x01)
#define RTC_MONTH_FEBRUARY             ((uint8_t)0x02)
#define RTC_MONTH_MARCH                ((uint8_t)0x03)
#define RTC_MONTH_APRIL                ((uint8_t)0x04)
#define RTC_MONTH_MAY                  ((uint8_t)0x05)
#define RTC_MONTH_JUNE                 ((uint8_t)0x06)
#define RTC_MONTH_JULY                 ((uint8_t)0x07)
#define RTC_MONTH_AUGUST               ((uint8_t)0x08)
#define RTC_MONTH_SEPTEMBER            ((uint8_t)0x09)
#define RTC_MONTH_OCTOBER              ((uint8_t)0x10)
#define RTC_MONTH_NOVEMBER             ((uint8_t)0x11)
#define RTC_MONTH_DECEMBER             ((uint8_t)0x12)

/** @defgroup RTC_WeekDay_Definitions RTC WeekDay Definitions
  * @{
  */
#define RTC_WEEKDAY_MONDAY             ((uint8_t)0x01)
#define RTC_WEEKDAY_TUESDAY            ((uint8_t)0x02)
#define RTC_WEEKDAY_WEDNESDAY          ((uint8_t)0x03)
#define RTC_WEEKDAY_THURSDAY           ((uint8_t)0x04)
#define RTC_WEEKDAY_FRIDAY             ((uint8_t)0x05)
#define RTC_WEEKDAY_SATURDAY           ((uint8_t)0x06)
#define RTC_WEEKDAY_SUNDAY             ((uint8_t)0x07)

比如12月份RTC_MONTH_DECEMBER的值是等於0x12的,轉成10進制等於18,也就是RTC_FORMAT_BCD也不是16進制,只是用了16進制的樣式,0x12不看0x直接看數字部分,就是12月份

再來看看stm32內部的兩種格式的轉換函數

/**
  * @brief  Converts a 2 digit decimal to BCD format.
  * @param  Value Byte to be converted
  * @retval Converted byte
  */
uint8_t RTC_ByteToBcd2(uint8_t Value)
{
  uint32_t bcdhigh = 0U;

  while(Value >= 10U)
  {
    bcdhigh++;
    Value -= 10U;
  }

  return  ((uint8_t)(bcdhigh << 4U) | Value);
}

/**
  * @brief  Converts from 2 digit BCD to Binary.
  * @param  Value BCD value to be converted
  * @retval Converted word
  */
uint8_t RTC_Bcd2ToByte(uint8_t Value)
{
  uint32_t tmp = 0U;
  tmp = ((uint8_t)(Value & (uint8_t)0xF0) >> (uint8_t)0x4) * 10;
  return (tmp + (Value & (uint8_t)0x0F));
}

轉換函數代碼自己看不說明,總之覺得很奇怪的用法

配置完成,生成工程

找到static void MX_RTC_Init(void)函數,在 HAL_RTC_Init後,使用RTC的後備寄存器保存是否初始化過時間的標誌,RTC的後備寄存器也是後備電源供電的,所以主電源斷電後數據還在,也可以用這些寄存器保存數據,讀寫函數如下:

void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data);
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister);

MX_RTC_Init函數修改如下:

static void MX_RTC_Init(void)
{

    /* USER CODE BEGIN RTC_Init 0 */

    /* USER CODE END RTC_Init 0 */

    RTC_TimeTypeDef sTime = {0};
    RTC_DateTypeDef sDate = {0};

    /* USER CODE BEGIN RTC_Init 1 */

    /* USER CODE END RTC_Init 1 */
    /** Initialize RTC Only
    */
    hrtc.Instance = RTC;
    hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
    hrtc.Init.AsynchPrediv = 127;
    hrtc.Init.SynchPrediv = 255;
    hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
    hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
    if (HAL_RTC_Init(&hrtc) != HAL_OK)
    {
        Error_Handler();
    }

    /* USER CODE BEGIN Check_RTC_BKUP */

    // 檢查後備寄存器
    uint32_t iSetFlag = 0x5053;// 這個0x5053值自己隨意
    if(iSetFlag != HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0))
    {   //

        /* USER CODE END Check_RTC_BKUP */

        /** Initialize RTC and set the Time and Date
        */
        sTime.Hours = 9;
        sTime.Minutes = 45;
        sTime.Seconds = 0;
        sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
        sTime.StoreOperation = RTC_STOREOPERATION_RESET;
        if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
        {
            Error_Handler();
        }
        sDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
        sDate.Month = RTC_MONTH_MAY;
        sDate.Date = 13;
        sDate.Year = 50;

        if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
        {
            Error_Handler();
        }
        /* USER CODE BEGIN RTC_Init 2 */
        // 設置完時鐘,設置標誌
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, iSetFlag);
    }
    else
    {        
    }
    {
        // 獲取一次時間顯示
        RTC_TimeTypeDef sTime;
        HAL_StatusTypeDef status = HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);

        RTC_DateTypeDef sDate;
        status = HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

        printf("MX_RTC_Init:Date time: %d-%02d-%02d weekData:%d %02d:%02d:%02d\r\n"                   
                   , 1970 + sDate.Year, sDate.Month, sDate.Date, sDate.WeekDay
                   , sTime.Hours, sTime.Minutes, sTime.Seconds);
    }
    /* USER CODE END RTC_Init 2 */

}

獲取時間日期HAL_RTC_GetTime和HAL_RTC_GetDate有要求先後順序的,看函數定義處的說明:

You must call HAL_RTC_GetDate() after HAL_RTC_GetTime() to unlock the values in the higher-order calendar shadow registers to ensure consistency between the time and date values. Reading RTC current time locks the values in calendar shadow registers until Current date is read.

上google翻譯的結果:

必須在HAL_RTC_GetTime()之後調用HAL_RTC_GetDate()才能解鎖高階日曆影子寄存器中的值,以確保時間和日期值之間的一致性。 讀取RTC當前時間將鎖定日曆影子寄存器中的值,直到讀取當前日期爲止。

基本配置完成,斷主電源後,在次上電,查看輸出的時間是正常的

我用F103芯片配置過,發現F103的芯片日期斷電後就沒有了

 

參考:

https://blog.csdn.net/qq_24381977/article/details/94460855

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章