RTC简介
实时时钟(Real Time Clock,RTC),是一个可以不使用系统主电源供电的定时器。在系统主电源断开 的情况下,依靠纽扣电池供电继续计时,只要都VBAT不断,都不影响RTC正常工作,只有当系统电源VDD和纽扣电池VBAT都断开时,RTC才停止工作。RTC的时钟源有三个。第一个由外部高速时钟源(HSE)经过128分频得到,第二个来自外部低速时钟源(LSE),第三个来自内部低速时钟源(LSI)。只有LSE在系统主电源掉电时,可以由VBAT供电,因此如果想RTC在主电源掉电也能运行,只能选择LSE提供时钟。外部低速时钟(LSE)的晶振频率为32.768KHz,经过2^15=32768分频后,刚好为1Hz,即计数器每计数一次,刚好就是一秒。
RTC初始化配置
RTC相关参数的设置较少,只需要设置预分频系数和将RTC时钟源配置为LSE即可。具体代码如下。需要注意的是,设置RTC的预分频系数理论上是32768,但是由于实际的外部晶振的频率并不是准确的32.768kHz,所以RTC走时会较快或者较慢,这时就需要根据实际情况来调整预分频系数了。
//RTC初始化
void RTC_Init(void)
{
hrtc.Instance = RTC;
//这里可以设置为RTC_AUTO_1_SECOND,自动计算1秒对应的预分频值
hrtc.Init.AsynchPrediv = 32776;
if(HAL_RTC_Init(&hrtc) != HAL_OK)
{
printf("RTC初始化失败\r\n");
}
__HAL_RCC_RTC_ENABLE(); //使能RTC时钟
}
//HAL_RTC_Init回调硬件初始化
void HAL_RTC_MspInit(RTC_HandleTypeDef *RTC_Handle)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphCLKInitStruct;
//配置LSE时钟源
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
printf("LSE时钟源开启失败\r\n");
}
//配置RTC时钟
PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphCLKInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if(HAL_RCCEx_PeriphCLKConfig(&PeriphCLKInitStruct) != HAL_OK)
{
printf("RTC时钟源配置失败\r\n");
}
__HAL_RTC_ALARM_ENABLE_IT(&hrtc,RTC_IT_ALRA); //使能闹钟中断
HAL_NVIC_SetPriority(RTC_Alarm_IRQn,1,0);
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}
RTC时间的设置与获取
要配置RTC日历(时间和日期),使用HAL_RTC_SetTime()和HAL_RTC_SetDate()函数。读取RTC日历,使用HAL_RTC_GetTime()和HAL_RTC_GetDate()函数。
具体代码如下,值得注意的是,获取RTC时间和日期时,需要先调用HAL_RTC_GetTime获取时间再调用HAL_RTC_GetDate获取日期,否则会出现获取的时间不准等一系列问题。
//定义日期和时间结构体,用于接收时间和日期信息
RTC_DateTypeDef RTC_DataStruct;
RTC_TimeTypeDef RTC_TimeStruct;
//设置RTC时间和日期(数据格式 BIN,即使用 10 进制表示)
void RTC_SetTime(uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t min, uint8_t sec)
{
// 使能访问后备寄存器相关条件
__HAL_RCC_PWR_CLK_ENABLE(); // 使能 PWR 电源时钟
__HAL_RCC_BKP_CLK_ENABLE(); // 使能 BKP 后备寄存器时钟
HAL_PWR_EnableBkUpAccess(); // 使能对 BKP 后备寄存器访问
//由该结构体的定义得知年份参数范围是0到99,所以要将具体的年份减去2000
RTC_DataStruct.Year = year - 2000;
RTC_DataStruct.Month= month;
RTC_DataStruct.Date= day;
RTC_DataStruct.WeekDay = RTC_WEEKDAY_MONDAY; //星期会自动计算,这里传入任意值
HAL_RTC_SetDate(&hrtc,&RTC_DataStruct,RTC_FORMAT_BIN);
RTC_TimeStruct.Hours = hour;
RTC_TimeStruct.Minutes= min;
RTC_TimeStruct.Seconds= sec;
HAL_RTC_SetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
}
//获取RTC时间和日期
void RTC_GetTime(void)
{
HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&RTC_DataStruct,RTC_FORMAT_BIN);
}
这里再插一个注意:STM32F1系列使用的RTC版本为V1版本。V2(其他系列)支持的所有特性在F1上都不支持。
在V2中,主要的RTC特性由HW管理。而在F1上,日期特性完全由软件管理。所以,与其他系列相比,有一些限制:
•HAL只支持24小时格式(不支持12小时格式)
•日期保存在SRAM中。当MCU处于STOP或STANDBY模式时,或者掉电重新上电数据将丢失。若想在下次上电或者低功耗唤醒之后仍然可以获取到日期信息需要另寻他法。
RTC中断
秒中断:
如果在RTC_CR寄存器中使能了SECIE位(Second interrupt enable),则每个TR_CLK周期RTC会产生一
个中断。通常TR_CLK周期为1秒,因此该中断也被称为秒中断。
闹钟中断:
闹钟中断就是设置一个预设定的值,当目前时间到达设定的值,就会产生中断信号。当然,RTC闹钟中断还有一个功能就是将MCU从低功耗模式下唤醒,而不用依靠外部中断唤醒的方式
这里主要介绍闹钟中断的使用,秒中断的使用方法大同小异。
使用HAL_RTC_SetAlarm()函数配置RTC闹钟。使用HAL_RTC_SetAlarm_IT()函数配置中断模式的RTC闹钟。
读取RTC闹钟,使用HAL_RTC_GetAlarm()函数。下面是设置RTC闹钟和闹钟中断函数的代码,其中闹钟中断的中断优先级设置和使能等已经在RTC初始化配置过了。文章来源:https://www.toymoban.com/news/detail-417157.html
//RTC设置闹钟时间
void RTC_SetAlarm(uint8_t hour,uint8_t min,uint8_t sec)
{
RTC_AlarmStruct.AlarmTime.Hours = hour;
RTC_AlarmStruct.AlarmTime.Minutes = min;
RTC_AlarmStruct.AlarmTime.Seconds = sec;
HAL_RTC_SetAlarm_IT(&hrtc,&RTC_AlarmStruct,RTC_FORMAT_BIN);
}
//RTC闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{
HAL_RTC_AlarmIRQHandler(&hrtc);
}
//RTC闹钟唤醒中断回调函数
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *RTC_Handle)
{
__HAL_RTC_ALARM_EXTI_CLEAR_FLAG(); //清除闹钟中断标志位
//你的中断服务具体代码.....
//............
}
以上就是基于STM32HAL库的RTC时钟的一些我认为比较重要的点,当然还有一些没有介绍到,比如如何写入和读取后备寄存器还有RTC的32位向上计数器Uinx 时间戳转换等等。文章来源地址https://www.toymoban.com/news/detail-417157.html
到了这里,关于STM32F1系列HAL库开发——RTC实时时钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!