1.实时时钟
RTC是一个独立的BCD定时器/计数器。RTC提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包括用于管理低功耗模式的自动唤醒单元。
有两个32位的寄存器,包含二进制吗十进制格式BCD的秒,分,小时,星期,月份,年份。还提供二进制的亚秒。
系统还可以自动将月份的天数补偿到28,29,30,31天,夏令补时。等等等功能
2.实时时钟框图
上部分
时钟来源可以是LES,LSI,HSE。
7位预分频PTC_PRER(默认128预分频)后产生ck_apre(默认到256HZ)
ck_apre经过校准后的RTC_CALIBR在经过RTC_SSR的15位预分频(通常值位256),产生ck_spre1hz时钟
日历寄存器里面有RTC_TR,RTC_DR记时间与日期,影子寄存器会把当前的日历记住。这个三个寄存器确认了当前的时间
还有两个闹钟A与B,有专门的时间秒与亚秒寄存器,相等的时候会产生闹钟中断
亚秒是没有经过RTC_PRER分频的周期,就是256HZ,一个周期就是1/256s
下部分
HSE_RTC的时钟经过分频后产生一个时钟,还有一个CK_SPRE时钟可以选择。
根据选择的时钟然后,装入重装值不断下降直到溢出,就产生唤醒
3.实时时钟寄存器
1.BLP备份寄存器
共有20个32位寄存器,用于保存系统配置和相关标志位
这些寄存器有一个纽扣电池一直供电,不会消失。
2.RTC常用寄存器
3.预分频寄存器RTC_PRER
两个预分频,一个分频为亚秒,亚秒的时钟分频为为秒
4.时间寄存器RTC_TR
5.日期寄存器RTC_DR
6.亚秒寄存器RTC_SSR
7.控制寄存器RTC_CR
太多了,就列了一部分
8.初始化和状态寄存器RTC_ISR
就是状态标志,表面现在日历等的状态
9.唤醒定时器寄存器RTC_WUTR
10.闹钟定时器寄存器RTC_ALRMAR/RTC_ALRMBR
4.实时时钟HAL库函数
1.RTC初始化函数
*HAL_RTC_Init(RTC_HandleTypeDef hrtc);
初始化函数
第一个参数24小时还是12小时格式
异步同步参数
使能闹钟,唤醒等
输出极性与输出类型(唤醒与闹钟的输出)
*HAL_RTC_MspInit(RTC_HandleTypeDef hrtc);
回调函数
不说了,时钟使能与开启中断等
2.时间操作函数
**HAL_RTC_SetTime(RTC_HandleTypeDef hrtc, RTC_TimeTypeDef sTime, uint32_t Format);
时间设置函数
第一个参数就是配置信息结构体
第二个参数就是时间结构体
**HAL_RTC_GetTime(RTC_HandleTypeDef hrtc, RTC_TimeTypeDef sTime, uint32_t Format);
获取时间,获取到sTime结构体
3.日期操作函数
**HAL_RTC_SetDate(RTC_HandleTypeDef hrtc, RTC_DateTypeDef sDate, uint32_t Format);
日期设置
**HAL_RTC_GetDate(RTC_HandleTypeDef hrtc, RTC_DateTypeDef sDate, uint32_t Format);
日期获取
获取日期,获取到sDate结构体
这前面四个函数最后都有一个参数,确定是bin还是BCD
4.闹钟操作函数
5.周期性唤醒操作函数
6.备份区域操作函数
7.RTC时钟源操作函数
8.RTC中断服务函数
有一个Wake中断回调函数没有写
5.实时时钟代码步骤
1.日历一般配置步骤
1.使能PWR时钟,后备寄存器的时钟
2.使能后备寄存器,在断电的时候可以存贮配置的时间的信息,在上电的时候就直接读取后备寄存器就行了。
3.配置RTC的时钟源与使能RTC时钟
打开低速外部时钟LSE
RTC设置时钟源为LSE
使能RTC
4.设置RTC各参数
5.设置时间就行了
2.闹钟一般配置步骤
3.周期性自动唤醒一般配置步骤
6.实时时钟代码
1.日历
rtc.c文件
#include"rtc.h"
RTC_HandleTypeDef hrtc;
void MY_RTC_Set_Time(u8 hour,u8 minutes,u8 seconds) //设置时间
{
RTC_TimeTypeDef sTime;
sTime.Hours=hour;
sTime.Minutes=minutes;
sTime.Seconds=seconds;
sTime.DayLightSaving=RTC_DAYLIGHTSAVING_NONE; //没有夏令营
sTime.StoreOperation=RTC_STOREOPERATION_RESET; //保存上面设置
sTime.TimeFormat=RTC_HOURFORMAT12_AM;
HAL_RTC_SetTime(&hrtc,&sTime,RTC_FORMAT_BIN);
}
void MY_RTC_Set_Date(u8 year,u8 month,u8 date,u8 weekDay) //设置日期
{
RTC_DateTypeDef sTime;
sTime.Year=year;
sTime.Month=month;
sTime.Date=date;
sTime.WeekDay=weekDay; //一个礼拜新期几
HAL_RTC_SetDate(&hrtc,&sTime,RTC_FORMAT_BIN);
}
void MY_RTC_Init(void)
{
hrtc.Instance=RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24; \\24小时制度
hrtc.Init.AsynchPrediv =0x7f; //异步分频128
hrtc.Init.SynchPrediv=0xff; //同步分频256
HAL_RTC_Init(&hrtc);
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0)!=11) //寄存器判断时间是否设置过
{
MY_RTC_Set_Date(22,9,17,6);
MY_RTC_Set_Time(18,31,50);
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,11);
}
}
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
RCC_OscInitTypeDef RCC_OscInitStructure;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
__HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
HAL_PWR_EnableBkUpAccess(); //使能后备寄存器
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_LSE; //开启了LSE时钟
RCC_OscInitStructure.LSEState=RCC_LSE_ON;
HAL_RCC_OscConfig(&RCC_OscInitStructure); //开启时钟源的函数
PeriphClkInit.PeriphClockSelection=RCC_PERIPHCLK_RTC; //功能为RTC
PeriphClkInit.RTCClockSelection=RCC_RTCCLKSOURCE_LSE; //设置时钟源
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
__HAL_RCC_RTC_ENABLE();
}
2.闹钟与唤醒时钟
#include"rtc.h"
#include"led.h"
RTC_HandleTypeDef hrtc;
RTC_AlarmTypeDef sAlarm;
void MY_RTC_Set_Time(u8 hour,u8 minutes,u8 seconds) //时间确定
{
RTC_TimeTypeDef sTime;
sTime.Hours=hour;
sTime.Minutes=minutes;
sTime.Seconds=seconds;
sTime.DayLightSaving=RTC_DAYLIGHTSAVING_NONE; //无需夏命营时间
sTime.StoreOperation=RTC_STOREOPERATION_RESET; //保存设置
sTime.TimeFormat=RTC_HOURFORMAT12_AM;
HAL_RTC_SetTime(&hrtc,&sTime,RTC_FORMAT_BIN);
}
void MY_RTC_Set_Date(u8 year,u8 month,u8 date,u8 weekDay) //日期
{
RTC_DateTypeDef sTime;
sTime.Year=year;
sTime.Month=month;
sTime.Date=date;
sTime.WeekDay=weekDay; //一个礼拜新期几
HAL_RTC_SetDate(&hrtc,&sTime,RTC_FORMAT_BIN);
}
void MY_RTC_Init(void)
{
hrtc.Instance=RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv =0x7f; //异步时钟
hrtc.Init.SynchPrediv=0xff; //同步时钟
HAL_RTC_Init(&hrtc); //RTC初始化
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0)!=11) //寄存器保证设置一次
{
MY_RTC_Set_Date(22,9,17,6);
MY_RTC_Set_Time(18,31,50);
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,11);
}
}
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc) //初始化IO口,时钟等参数
{
RCC_OscInitTypeDef RCC_OscInitStructure;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
__HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
HAL_PWR_EnableBkUpAccess(); //使能后备寄存器
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_LSE; //开启了LSE时钟
RCC_OscInitStructure.LSEState=RCC_LSE_ON;
HAL_RCC_OscConfig(&RCC_OscInitStructure); //打开时钟
PeriphClkInit.PeriphClockSelection=RCC_PERIPHCLK_RTC; //功能为RTC
PeriphClkInit.RTCClockSelection=RCC_RTCCLKSOURCE_LSE; //设置时钟源
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
__HAL_RCC_RTC_ENABLE();
}
void MY_RTC_ALAMA_Set(u8 week,u8 hour,u8 minute,u8 second)
{
sAlarm.Alarm=RTC_ALARM_A; //A时钟
sAlarm.AlarmMask = RTC_ALARMMASK_NONE; //不需要检测的时间
sAlarm.AlarmDateWeekDaySel=RTC_ALARMDATEWEEKDAYSEL_WEEKDAY; //按周来
sAlarm.AlarmDateWeekDay=week;
sAlarm.AlarmTime.Hours=hour;
sAlarm.AlarmTime.Minutes=minute;
sAlarm.AlarmTime.Seconds=second;
sAlarm.AlarmTime.SubSeconds=0;
sAlarm.AlarmSubSecondMask=RTC_ALARMSUBSECONDMASK_NONE;
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn); //使能Alman中断通道
HAL_NVIC_SetPriority(RTC_Alarm_IRQn,2,2); //抢占优先级3,子优先级3
HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,RTC_FORMAT_BIN);
}
void MY_RTC_WakeUP_Set(u16 cnt)
{
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc,RTC_FLAG_WUTWF);
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc,cnt,RTC_WAKEUPCLOCK_CK_SPRE_16BITS); //第二个参数计数器的值,第三个选择时钟源
HAL_NVIC_SetPriority(RTC_WKUP_IRQn,2,3);
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
void RTC_Alarm_IRQHandler(void)
{
HAL_RTC_AlarmIRQHandler(&hrtc);
}
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
printf("闹钟到啦\r\n");
}
void RTC_WKUP_IRQHandler(void)
{
HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc);
}
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
//printf("WakeUP!\r\n");
LED0=!LED0;
LED1=!LED1;
}