STM32F4 HAL库开发 -- RTC
一、STM32F407 RTC時鐘簡介
STM32F407的RTC,是一個獨立的BCD定時器/計數器。RTC提供了一個日歷時鐘(包含年月日時分秒信息)、兩個可編程鬧鐘(ALARM A和ALARM B)中斷,以及一個具有中斷功能的周期性可編程喚醒標志。
兩個32位寄存器(TR和DR)包含二進碼十進制格式(BCD)的秒、分鐘、小時(12或24小時制)、星期、日期、月份和年份。此外,還可提供二進制格式的亞秒值。
STM32F429 的 RTC 可以自動將月份的天數補償為 28、 29(閏年)、 30 和 31 天。
二、HAL庫配置RTC
1、使能電源時鐘,并使能RTC及RTC后備寄存器寫訪問
電源時鐘使能,通過RCC_APB1ENR寄存器來設置:RTC及RTC備份寄存器的寫訪問,通過PWR_CR寄存器的DBP位設置。
HAL庫設置方法為:
2、開啟外部低速振蕩器LSE,選擇RTC時鐘,并使能
配置開啟LSE的函數為 HAL_RCC_OscConfig,使用方法為:
RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_LSE;//LSE 配置 RCC_OscInitStruct.PLL.PLLState=RCC_PLL_NONE; RCC_OscInitStruct.LSEState=RCC_LSE_ON; //RTC 使用 LSE HAL_RCC_OscConfig(&RCC_OscInitStruct);選擇RTC時鐘源函數為HAL_RCCEx_PeriphCLKConfig,使用方法為:
PeriphClkInitStruct.PeriphClockSelection=RCC_PERIPHCLK_RTC;//外設為 RTC PeriphClkInitStruct.RTCClockSelection=RCC_RTCCLKSOURCE_LSE;//RTC 時鐘源為 LSE HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);使能RTC時鐘方法為:
__HAL_RCC_RTC_ENABLE();//RTC 時鐘使能3、初始化RTC,設置RTC的分頻,以及配置RTC參數
在HAL中,初始化RTC是通過函數HAL_RTC_Init實現的,該函數聲明為:
HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc);同樣按照以前的方式,我們來看看RTC初始化參數結構體RTC_HandleTypeDef 定義:
typedef struct { RTC_TypeDef *Instance; RTC_InitTypeDef Init; HAL_LockTypeDef Lock; __IO HAL_RTCStateTypeDef State; }RTC_HandleTypeDef;這里我們著重講解成員變量Init含義,因為它是真正的RTC初始化變量,它是RTC_InitTypeDef 結構體類型,結構體 RTC_InitTypeDef 定義為:
typedef struct { uint32_t HourFormat; //小時格式 uint32_t AsynchPrediv; //異步預分頻系數 uint32_t SynchPrediv; //同步預分頻系數 uint32_t OutPut; //選擇連接到 RTC_ALARM 輸出的標志 uint32_t OutPutPolarity; //設置 RTC_ALARM 的輸出極性 uint32_t OutPutType; //設置 RTC_ALARM 的輸出類型為開漏輸出還是推挽輸出 }RTC_InitTypeDef;該結構體有6個成員變量。
成員變量 HourFormat 用來設置小時格式,為12小時制或者24小時制,取值為RTC_HOURFORMAT_12 或者 RTC_HOURFORMAT_24。
AsynchPrediv 用來設置RTC的異步預分頻系數,也就是設置RTC_PRER寄存器的PREDIV_A相關位,因為異步分頻系數是7位,所以最大值位0x7F,不能超過這個值。
SynchPrediv 用來設置RTC的同步預分頻系數,也就是設置 RTC_PRER寄存器的PREDIV_S相關位,因為同步預分頻系數也是15位,所以最大值位0x7FFF,不能超過這個值。
OutPut 用來選擇要連接到 RTC_ALARM 輸出的標志,取值為: RTC_OUTPUT_DISABLE(禁止輸出), RTC_OUTPUT_ALARMA(使能鬧鐘 A 輸出), RTC_OUTPUT_ALARMB(使能鬧鐘 B 輸出)和 RTC_OUTPUT_WAKEUP(使能喚醒輸出)。
OutPutPolarity 用來設置 RTC_ALARM 的輸出極性,與 Output 成員變量配合使用,取值為RTC_OUTPUT_POLARITY_HIGH(高電平)或 RTC_OUTPUT_POLARITY_LOW(低電平)。
OutPutType 用 來 設 置 RTC_ALARM 的 輸 出 類 型 為 開 漏 輸 出( RTC_OUTPUT_TYPE_OPENDRAIN)還是推挽輸出( RTC_OUTPUT_TYPE_PUSHPULL),與成員變量 OutPut 和 OutPutPolarity 配合使用。
RTC初始化的一般格式:
hrtc.Instance = RTC;hrtc.Init.HourFormat = RTC_HOURFORMAT_24; //RTC 設置為 24 小時格式hrtc.Init.AsynchPrediv = 127; //RTC 異步分頻系數(1~0X7F)hrtc.Init.SynchPrediv = 255; //RTC 同步分頻系數(0~7FFF)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();}同樣, HAL 庫也提供了 RTC 初始化 MSP 函數。函數聲明為:
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle) {if(rtcHandle->Instance==RTC){/* USER CODE BEGIN RTC_MspInit 0 *//* USER CODE END RTC_MspInit 0 *//* RTC clock enable */__HAL_RCC_RTC_ENABLE();/* USER CODE BEGIN RTC_MspInit 1 *//* USER CODE END RTC_MspInit 1 */} }該函數內部一般存放時鐘使能,時鐘源選擇等操作程序。
4、設置RTC的時間
HAL庫中,設置RTC時間的函數為:
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);HAL_RTC_SetTime 函數的第三個參數 Format,用來設置輸入的時間格式為BIN格式還是BCD格式,可選值為 RTC_FORMAT_BIN(使用十進制 例如 18年你得到到是 18年)和 RTC_FORMAT_BCD(使用16進制 例如 18年你得到的是 0x18年
)。
結構體 RTC_TimeTypeDef 的定義:
實例:
RTC_TimeTypeDef sTime = {0};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();}5、設置RTC的日期
設置RTC的日期函數為:
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);我們著重講解第二個入口參數sData,它是結構體
RTC_DateTypeDef 指針類型變量,結構體 RTC_DateTypeDef 定義如下:
6、獲取RTC當前日期和時間
獲取當前 RTC 時間的函數為:
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);獲取當前 RTC 日期的函數為:
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);三、計時器
SYS_DATETIME rtctime = { 0 }; uint32_t Inctime = 0; uint32_t Networktime = 0;//設置RTC時間 void RTC_Sync_SYS_Time(SYS_DATETIME *pDTime) {RTC_DateTypeDef RTC_DateStruct;RTC_TimeTypeDef RTC_TimeStruct;RTC_DateStruct.Year = pDTime->year - DEFAULT_YEAR;RTC_DateStruct.Month = pDTime->month;RTC_DateStruct.Date = pDTime->day;if (HAL_RTC_SetDate(&hrtc, &RTC_DateStruct, RTC_FORMAT_BCD) != HAL_OK){Error_Handler();}RTC_TimeStruct.Hours = pDTime->hour;RTC_TimeStruct.Minutes = pDTime->minute;RTC_TimeStruct.Seconds = pDTime->second;if (HAL_RTC_SetTime(&hrtc, &RTC_TimeStruct, RTC_FORMAT_BCD) != HAL_OK){Error_Handler();} }//得到RTC時間 void SYS_Time_Sync_RTC(SYS_DATETIME *pDTime) {RTC_DateTypeDef RTC_DateStruct;RTC_TimeTypeDef RTC_TimeStruct;HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);pDTime->hour = RTC_TimeStruct.Hours;pDTime->minute = RTC_TimeStruct.Minutes;pDTime->second = RTC_TimeStruct.Seconds;HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);pDTime->year = (RTC_DateStruct.Year + DEFAULT_YEAR);pDTime->month = RTC_DateStruct.Month;pDTime->day = RTC_DateStruct.Date; }//判斷閏年 uint8_t Is_Leap_Year(uint16_t year) {if(((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)){return 1;}else{return 0;} }//判斷2月 uint8_t Last_Day_Of_Mon(uint8_t month, uint16_t year) {const uint8_t Sys_Mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};if ((month == 0) || (month > 12)){return Sys_Mon[1] + Is_Leap_Year(year);}if (month != 2){return Sys_Mon[month - 1];}else{return Sys_Mon[1] + Is_Leap_Year(year);} }//UNIX時間轉RTC時間 void Unix2Rtc(uint32_t temp, SYS_DATETIME *rtctime, uint8_t time_zone) {uint32_t sec;uint16_t y;uint32_t day;uint8_t m;uint16_t d;/* time zone */temp += (time_zone * SEC_PER_HOUR);/* hour */sec = temp % SEC_PER_DAY;rtctime->hour = sec / SEC_PER_HOUR;/* min */sec %= SEC_PER_HOUR;rtctime->minute = sec / SEC_PER_MIN;/* sec */rtctime->second = sec % SEC_PER_MIN;/* year */day = temp / SEC_PER_DAY;for (y = UTC_BASE_YEAR; day > 0; y++){d = (DAY_PER_YEAR + Is_Leap_Year(y));if (day >= d){day -= d;}else{break;}}rtctime->year = y;/* month */for (m = 1; m < MONTH_PER_YEAR; m++){d = Last_Day_Of_Mon(m, y);if (day >= d){day -= d;}else{break;}}rtctime->month = m;/*day*/rtctime->day = day + 1; }//RTC時間轉UNIX時間 uint32_t RTC2Unix(SYS_DATETIME *systime) {uint16_t i;uint32_t no_of_days = 0;uint32_t utc_time;if (systime->year < UTC_BASE_YEAR){return 0;}/* year */for (i = UTC_BASE_YEAR; i < systime->year; i++){no_of_days += (DAY_PER_YEAR + Is_Leap_Year(i));}/* month */for (i = 1; i < systime->month; i++){no_of_days += Last_Day_Of_Mon((unsigned char) i, systime->year);}/* day */no_of_days += (systime->day - 1);/* sec */utc_time = no_of_days * SEC_PER_DAY + (systime->hour * SEC_PER_HOUR + systime->minute * SEC_PER_MIN + systime->second);return utc_time; }//設置RTC時間 void THC_Set_RTC_Time(uint32_t time) {memset(&rtctime, 0, sizeof(rtctime));Unix2Rtc(time, &rtctime, 8);RTC_Sync_SYS_Time(&rtctime);Networktime = time;Inctime = 0; }//得到RTC時間 void THC_Get_RTC_Time(void) {memset(&rtctime, 0, sizeof(rtctime));SYS_Time_Sync_RTC(&rtctime);Networktime = RTC2Unix(&rtctime);Inctime = 0; }//得到RTC時間 SYS_DATETIME THC_Get_SysTime(void) {SYS_DATETIME sRTCtime;uint32_t time = 0;time = Networktime + (Inctime/10);Unix2Rtc(time, &sRTCtime, 8);return sRTCtime; }//TIM中斷函數 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {//100ms定時中斷if(htim==(&htim7)) {Inctime++; //RTC計時} }總結
以上是生活随笔為你收集整理的STM32F4 HAL库开发 -- RTC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 红人职业化发展报告
- 下一篇: B端产品经理要掌握的基本功