天天看點

stm32cube 生成RTC時鐘

晶片是stm32f407ve

軟體 stm32cubemx5.3.0 和keil5

F4的RTC提供了月曆時鐘和兩個可程式設計鬧鐘中斷,一個周期性可程式設計喚醒标志。這樣很友善設定系統時間,并不會像F1的RTC那樣要自己計算年月日時分秒。F4的RTC是一個獨立的BCD定時計數器,系統可以自動将月份天數補償為28、29(閏年)、30、31天。并且還可以進行夏令時補償。

1、設定RCC

stm32cube 生成RTC時鐘

RTC裝置因為其獨特的運作方式(即掉電依舊運作)使用HSE分頻時鐘或者LSI的時候,在主電源VDD掉電的情況下,這兩個時鐘來源都會受到影響,資源消耗太大,小小的紐扣電池根本吃不消。沒法保證RTC正常工作.是以RTC一般都時鐘低速外部時鐘LSE。

2、設定RTC

stm32cube 生成RTC時鐘

Activate Clock Source 激活時鐘源

Activate calendar 激活月曆

stm32cube 生成RTC時鐘

設定初始的時間、日期和格式

低速的外部晶振我使用的是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函數,否則是不能讀出資料的。

stm32cube 生成RTC時鐘

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]會是一個未知的值,是以後面讀取的時候可能會出現問題

stm32cube 生成RTC時鐘
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小時制再讀出來就有問題,一起設定的話就可以,是以現在都是先讀取一下,在修改某一項,再整體儲存

繼續閱讀