晶片是stm32f407ve
軟體 stm32cubemx5.3.0 和keil5
F4的RTC提供了月曆時鐘和兩個可程式設計鬧鐘中斷,一個周期性可程式設計喚醒标志。這樣很友善設定系統時間,并不會像F1的RTC那樣要自己計算年月日時分秒。F4的RTC是一個獨立的BCD定時計數器,系統可以自動将月份天數補償為28、29(閏年)、30、31天。并且還可以進行夏令時補償。
1、設定RCC
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIXZ05WZj91YpB3IwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxCeFpXT3dGRP5WNXFWc5cVWvB3MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmL4IjM0QzN0QTMyIjMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
RTC裝置因為其獨特的運作方式(即掉電依舊運作)使用HSE分頻時鐘或者LSI的時候,在主電源VDD掉電的情況下,這兩個時鐘來源都會受到影響,資源消耗太大,小小的紐扣電池根本吃不消。沒法保證RTC正常工作.是以RTC一般都時鐘低速外部時鐘LSE。
2、設定RTC
Activate Clock Source 激活時鐘源
Activate calendar 激活月曆
設定初始的時間、日期和格式
低速的外部晶振我使用的是32768Hz的,根據計算公式
RTC時鐘頻率 = RTC時鐘源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))
32.768KHz / ((127+1)*(255+1)) = 1Hz,也就是1秒
Binary data format 十進制
BCD data format BCD碼進制
3、編寫代碼
生成工程後就可以讀取時間和日期了
RTC_TimeTypeDef GetTime;
RTC_DateTypeDef GetData;
GUI_SetColor(GUI_BLACK);
GUI_SetBkColor(GUI_WHITE);
GUI_SetFont(pFont_22);
HAL_RTC_GetTime(&hrtc,&GetTime,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&GetData,RTC_FORMAT_BIN);
Time2Asc(GetTime,aa);
GUI_DispStringAt(aa,300,10);
Date2Asc(GetData,aa);
GUI_DispStringAt(aa,380,10);
需要注意的是,必須在HAL_RTC_GetTime函數後面使用HAL_RTC_GetDate函數,否則是不能讀出資料的。
4、RTC備份寄存器
修改RTC初始化函數
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
/** 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 */
__HAL_RCC_PWR_CLK_ENABLE(); //開啟後備電源時鐘
HAL_PWR_EnableBkUpAccess(); //允許通路、RTC 備份寄存器
if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0xA2A2)
{
sTime.Hours = 0x0;
sTime.Minutes = 0x0;
sTime.Seconds = 0x0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x1;
sDate.Year = 0x00;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xA2A2);
}
else
{
}
/* USER CODE END Check_RTC_BKUP */
/** Initialize RTC and set the Time and Date
*/
// sTime.Hours = 0x0;
// sTime.Minutes = 0x0;
// sTime.Seconds = 0x0;
// sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
// sTime.StoreOperation = RTC_STOREOPERATION_RESET;
// if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
// {
// Error_Handler();
// }
// sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
// sDate.Month = RTC_MONTH_JANUARY;
// sDate.Date = 0x1;
// sDate.Year = 0x2000;
// if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
// {
// Error_Handler();
// }
}
這樣斷電後或者複位後,時鐘會儲存下來,不會是複位值
遇到的問題
自己手動修改了日期之後,再讀取時,讀出來的年份總是錯誤的,其他的月份什麼的沒有問題,後來在儲存日期之前,把星期也重新設定一下再儲存,這樣就沒有問題
應該是因為用HAL_RTC_SetDate這個函數儲存的時候,他是将整個RTC_DR寄存器都進行了指派再儲存的,如果不設定星期,那麼對RTC_DR寄存器指派的時候,WDU[2:0]會是一個未知的值,是以後面讀取的時候可能會出現問題
assert_param(IS_RTC_YEAR(sDate->Year));
assert_param(IS_RTC_MONTH(sDate->Month));
assert_param(IS_RTC_DATE(sDate->Date));
datetmpreg = (((uint32_t)RTC_ByteToBcd2(sDate->Year) << 16U) | \
((uint32_t)RTC_ByteToBcd2(sDate->Month) << 8U) | \
((uint32_t)RTC_ByteToBcd2(sDate->Date)) | \
((uint32_t)sDate->WeekDay << 13U));
上面是HAL_RTC_SetDate函數中的一段語句,可以看出Week會左移13位,而week是uint8_t類型的資料,左移13位的話,正好會影響年份的值。
包括後面設定時間時,單獨設定時間,或者單獨設定12小時制再讀出來就有問題,一起設定的話就可以,是以現在都是先讀取一下,在修改某一項,再整體儲存