RTC簡介: RTC是一個獨立的定時器,它可以連續計數和提供了時鐘日曆功能。使用BKP寄存器存儲具有掉電保存功能 存粹的計時的, 觸發中斷 ——鬧鐘中斷,用來產生一個可編程的鬧鐘中斷。 ——秒中斷,用來產生一個可編程的周期性中斷信號(最快1秒,最慢1秒,只能1秒) ——溢出中斷,指示內部可編程計數器 ...
RTC簡介:
- RTC是一個獨立的定時器,它可以連續計數和提供了時鐘日曆功能。使用BKP寄存器存儲具有掉電保存功能
- 存粹的計時的,
- 觸發中斷
——鬧鐘中斷,用來產生一個可編程的鬧鐘中斷。
——秒中斷,用來產生一個可編程的周期性中斷信號(最快1秒,最慢1秒,只能1秒)
——溢出中斷,指示內部可編程計數器溢出並回傳為0的狀態。
- RTC的特性掉電之後保存數據,但是f1的日期數據是保存到運行寄存器的(掉電丟失)
- 是它是一個 32 位的計數器只能向上計 數。它的時鐘來源有三種,分別為高速外部時鐘的 128 分頻( HSE/128 )、 低速內部時鐘 LSI 以及低速外部時鐘 LSE。
- 時間寄存器,日期寄存器(32位的)分別存儲時分秒,年月日。
啟用RTC流程:
開始遇到的問題:
1.
2.
3.
4.
5.
6. 開啟串口用於列印時間信息:
STM32CubeMX設置RTC就完成了,以下是代碼:
1. 定義結構體變數,獲取數據
RTC_TimeTypeDef GET_Time; /* 獲取時間結構體 */
RTC_DateTypeDef GET_Date; /* 獲取時期結構體 */
2. 列印數據
/* 列印時間結構體數據 */ HAL_RTC_GetDate(&hrtc, &GET_Date, RTC_FORMAT_BIN); HAL_RTC_GetTime(&hrtc, &GET_Time, RTC_FORMAT_BIN); /* 列印時期結構體數據 */ printf("%04d/%02d/%02d/\r\n",2000+GET_Date.Year,GET_Date.Month,GET_Date.Date); printf("%02d:%02d:%02d:\r\n",GET_Time.Hours,GET_Time.Minutes,GET_Time.Seconds); /* 延時 */ HAL_Delay(1000);
列印日曆成功
註意:這個是掉電丟失的!,因為f103的RTC功能日期是保存到BKP裡面的,但是我門每次複位或掉電之後,都是會重覆初始化 void MX_RTC_Init(void)這個函數,所以掉電之後或複位之後重新計時。
怎麼掉電不丟失:
1. 掉電丟失的問題一
可以看到圖二這裡面根據CubeMX裡面的配置初始化了存儲時期與時間的結構體(變數)如下圖一:
圖一
/** Initialize RTC and set the Time and Date */ sTime.Hours = 0x20; sTime.Minutes = 0x44; sTime.Seconds = 0x00; if( HAL_RTC_SetTime( &hrtc, &sTime, RTC_FORMAT_BCD ) != HAL_OK ) { Error_Handler(); } DateToUpdate.WeekDay = RTC_WEEKDAY_WEDNESDAY; DateToUpdate.Month = RTC_MONTH_MAY; DateToUpdate.Date = 0x31; DateToUpdate.Year = 0x23;
void MX_RTC_Init(void): 圖二
/* RTC init function */ void MX_RTC_Init(void) { /* USER CODE BEGIN RTC_Init 0 */ /* USER CODE END RTC_Init 0 */ RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef DateToUpdate = {0}; /* USER CODE BEGIN RTC_Init 1 */ /* USER CODE END RTC_Init 1 */ /** Initialize RTC Only */ hrtc.Instance = RTC; hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND; hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN Check_RTC_BKUP */ /* USER CODE END Check_RTC_BKUP */ /** Initialize RTC and set the Time and Date */ sTime.Hours = 9; sTime.Minutes = 40; sTime.Seconds = 0; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY; DateToUpdate.Month = RTC_MONTH_JUNE; DateToUpdate.Date = 6; DateToUpdate.Year = 23; if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN RTC_Init 2 */ /* USER CODE END RTC_Init 2 */ }
2. 在MX_RTC_Init函數的結尾,把0x7240這段數據寫入BKP某個16位的寄存器裡面,之後在MX_RTC_Init函數的開始寫一個判斷BKP某個寄存器是否為0x7240這段數據,如果條件為真則return出函數。這樣就達到了初始化一次的效果了。
(BKP的特性掉電不丟失,可以去查看手冊)
(0x7240這段數據可以寫任意數,別太大了)
以下是代碼:
MX_RTC_Init頭
/* USER CODE BEGIN Check_RTC_BKUP */ /* 只初始化一次 */ if( HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR1 ) == 0x7240 ) { return ; } /* USER CODE END Check_RTC_BKUP */
MX_RTC_Init尾
HAL_RTCEx_BKUPWrite( &hrtc,RTC_BKP_DR1,0x7240 );
2. 掉電丟失的問題二
f103的RTC日期是不保存的,我門可以利用定時器中斷來計數保存數據,代碼如下:
1. 開啟RTC定時器
2. 在stm32f1xx_it.c裡面寫,中斷後存數據到指定BKP寄存器
/** * @brief This function handles RTC global interrupt. */ void RTC_IRQHandler(void) { /* USER CODE BEGIN RTC_IRQn 0 */ /* USER CODE END RTC_IRQn 0 */ HAL_RTCEx_RTCIRQHandler(&hrtc); /* USER CODE BEGIN RTC_IRQn 1 */ HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR2,hrtc.DateToUpdate.Year); HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR3,hrtc.DateToUpdate.Month); HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR4,hrtc.DateToUpdate.Date); /* USER CODE END RTC_IRQn 1 */ }
3. rtc.c的HAL_RTC_MspInit函數內寫
__HAL_RTC_ALARM_ENABLE_IT(&hrtc,RTC_IT_SEC);
4. 讀BKP寄存器的日期數據到計時變數內
/* 只初始化一次 */ if( HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR1 ) == 0x7240 ) { /* 讀BKP寄存器的日期數據到計時變數內 */ hrtc.DateToUpdate.Year = HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR2 ); hrtc.DateToUpdate.Month = HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR3 ); hrtc.DateToUpdate.Date = HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR4 ); HAL_RTC_GetTime( &hrtc, &sTime, RTC_FORMAT_BIN ); return ; }
這樣就達到了日期存儲的功能了。
以下是代碼下載鏈接: