1.概念
RTC叫实时时钟,是芯片中用于记录具体时间的硬件
由于计时操作需要一直运行,永不停歇,因此RTC需要独立的供电,独立的时钟源。
stm32f407的RTC是一个独立的定时器,使用BCD码(用十六进制记录十进制数据)的计数器,提供日历时钟(年月日时分秒星期)和闹钟功能。
2.stm32的RTC框图
3.RTC的配置
(1)RTC配置寄存器具有写保护功能,写寄存器之前必须关闭写保护
1.将电源控制寄存器(PWR_CR)的DBP位置1 2.向RTC写保护寄存器(RTC_WPR)写入:0xca 0x53
(2)RTC的初始化
当初始化完成后,RTC开始计时。RTC不需要每次启动都初始化
4.RTC的库函数编程实现
在工程中加入RTC和PWR(电源控制)的库函数源码
(1)开启PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
(2)使能PWR中RTC寄存器的写操作
PWR_BackupAccessCmd(ENABLE);
(3)使能LSE,选择LSE作为RTC时钟源
RCC_LSEConfig(RCC_LSE_ON); //等待LSE就绪 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET); //选择LSE作为RTC时钟源 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
(4)使能RTC时钟
RCC_RTCCLKCmd(ENABLE);
(5)关闭RTC的写保护,等待就绪
RTC_WaitForSynchro();
(6)配置RTC的分频系数和时间格式
ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);
//传入RTC初始化结构 typedef struct
{
uint32_t RTC_HourFormat; /*!< 小时格式 12/24 @ref RTC_Hour_Formats */ uint32_t RTC_AsynchPrediv; /*!< 异步分频系数(尽量大) lower than 0x7F */ uint32_t RTC_SynchPrediv; /*!< 同步分频系数 lower than 0x7FFF */
} RTC_InitTypeDef;
(7)设置初始日期和时间
//设置日期 ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
参数: RTC_Format - 日期格式 RTC_Format_BCD
RTC_DateStruct - 日期结构
typedef struct
{
uint8_t RTC_WeekDay; /*!< 星期 @ref RTC_WeekDay_=Definitions */
uint8_t RTC_Month; /*!< 月 @ref RTC_Month_Date_Definitions */
uint8_t RTC_Date; /*!< 日 1-31 range. */
uint8_t RTC_Year; /*!< 年 0-99 range. */
}RTC_DateTypeDef; //设置时间
ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
参数: RTC_Format - 时间格式 RTC_Format_BCD
RTC_DateStruct - 时间结构
typedef struct
{
uint8_t RTC_Hours; /*!< 小时 */
uint8_t RTC_Minutes; /*!< 分 0-59 range. */
uint8_t RTC_Seconds; /*!< 秒 0-59 range. */
uint8_t RTC_H12; /*!< 上午/下午 @ref RTC_AM_PM_Definitions */
}RTC_TimeTypeDef;
(8)获取日期和时间
void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct); void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
RTC提供了备份寄存器,这些寄存器由备份电源供电,数据掉电不丢失,可以通过这些寄存器实现只初始化RTC一次。
void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data); uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
练习:
测试RTC功能,通过蓝牙命令读取RTC时间到手机
5.RTC的闹钟配置
//关闭RTC寄存器写保护
(1)关闭闹钟
RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
(2)设置闹钟参数
void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct);
参数:
RTC_Format - 时间格式 RTC_Format_BCD
RTC_Alarm - 哪个闹钟 RTC_Alarm_A
RTC_AlarmStruct - 闹钟参数结构体
typedef struct
{
RTC_TimeTypeDef RTC_AlarmTime; /*!< 闹钟时间 */
uint32_t RTC_AlarmMask; /*!< 闹钟时间掩码 @ref RTC_AlarmMask_Definitions */
uint32_t RTC_AlarmDateWeekDaySel;
/*!< 星期/日期选择 @ref RTC_AlarmDateWeekDay_Definitions */
uint8_t RTC_AlarmDateWeekDay;
/*!< 日期 1-31 range.星期 @ref RTC_WeekDay_Definitions */
}RTC_AlarmTypeDef;
(3)清除中断标志
RTC_ClearITPendingBit(RTC_IT_ALRA);
(4)使能闹钟A中断
RTC_ITConfig(RTC_IT_ALRA, ENABLE);
(5)外部中断初始化
EXTI_Init(...);
(6)初始化NVIC
NVIC_Init(...);
(7)启动闹钟
RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
(8)实现RTC闹钟中断处理函数
void RTC_Alarm_IRQHandler(void)
{ //......
//清除闹钟中断标志
RTC_ClearITPendingBit(RTC_IT_ALRA);
//清除外部中断标志
EXTI_ClearITPendingBit(EXTI_Line17);
}
6.RCT编程实现.
#include
#include
#include
void rtc_init(void)
{
RTC_InitTypeDef RTC_InitStruct;
RTC_DateTypeDef RTC_DateStruct;
RTC_TimeTypeDef RTC_TimeStruct;
if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x8888){
//1.开启PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
//2.使能PWR中RTC寄存器的写操作
PWR_BackupAccessCmd(ENABLE);
//3.使能LSE,选择LSE作为RTC时钟源
RCC_LSEConfig(RCC_LSE_ON);
//等待LSE就绪
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET);
//选择LSE作为RTC时钟源
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
//4.使能RTC时钟
RCC_RTCCLKCmd(ENABLE);
//5.关闭RTC的写保护,等待就绪
RTC_WaitForSynchro();
//6.配置RTC的分频系数和时间格式 1Hz
RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;//24小时格式
RTC_InitStruct.RTC_AsynchPrediv = 0x7f;//异步预分频系数,尽量大 128分频
RTC_InitStruct.RTC_SynchPrediv = 0xff;//同步预分频系数 256分频
RTC_Init(&RTC_InitStruct);
//7.设置初始日期和时间
RTC_DateStruct.RTC_Year = 0x22;//年
RTC_DateStruct.RTC_Month = RTC_Month_June;//月
RTC_DateStruct.RTC_Date = 0x26;//日
RTC_DateStruct.RTC_WeekDay = RTC_Weekday_Sunday;//星期日
RTC_SetDate(RTC_Format_BCD,&RTC_DateStruct);
RTC_TimeStruct.RTC_H12 = RTC_H12_PM;
RTC_TimeStruct.RTC_Hours = 0x14;//时
RTC_TimeStruct.RTC_Minutes = 0x42;//分
RTC_TimeStruct.RTC_Seconds = 0x50;//秒
RTC_SetTime(RTC_Format_BCD,&RTC_TimeStruct);
//8.写备份寄存器
RTC_WriteBackupRegister(RTC_BKP_DR0,0x8888);
}
}
void rtc_set_time(u8 hour,u8 min,u8 sec)
{
RTC_TimeTypeDef RTC_TimeStruct;
//1.开启PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
//2.使能PWR中RTC寄存器的写操作
PWR_BackupAccessCmd(ENABLE);
//3.关闭RTC的写保护,等待就绪
RTC_WaitForSynchro();
RTC_TimeStruct.RTC_Hours = TOBCD(hour);//时
RTC_TimeStruct.RTC_Minutes = TOBCD(min);//分
RTC_TimeStruct.RTC_Seconds = TOBCD(sec);//秒
RTC_SetTime(RTC_Format_BCD,&RTC_TimeStruct);
}
//RTC闹钟初始化
void rtc_alarm_init(void)
{
RTC_AlarmTypeDef RTC_AlarmStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//1.关闭寄存器写保护
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
//关闭RTC的写保护,等待就绪
RTC_WaitForSynchro();
//2.关闭闹钟
RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
//3.设置闹钟参数
RTC_AlarmStruct.RTC_AlarmTime.RTC_H12 = RTC_H12_PM;
RTC_AlarmStruct.RTC_AlarmTime.RTC_Hours = 0x15;
RTC_AlarmStruct.RTC_AlarmTime.RTC_Minutes = 0x43;
RTC_AlarmStruct.RTC_AlarmTime.RTC_Seconds = 0x10;
RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;//日期匹配
RTC_AlarmStruct.RTC_AlarmDateWeekDay = 0x27;//日期
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay|RTC_AlarmMask_Hours;//RTC_AlarmMask_None;//不屏蔽任何时间
RTC_SetAlarm(RTC_Format_BCD,RTC_Alarm_A,&RTC_AlarmStruct);
//4.清除中断标志
RTC_ClearITPendingBit(RTC_IT_ALRA);
//5.使能闹钟A中断
RTC_ITConfig(RTC_IT_ALRA, ENABLE);
//6.初始化外部中断和NVIC
EXTI_InitStruct.EXTI_Line = EXTI_Line17;//外部中断线17
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn;//闹钟中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x2;//抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;//响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStruct);
//7.开始闹钟
RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
}
//闹钟中断处理函数
void RTC_Alarm_IRQHandler(void)
{
//......
BEEP = 1;
//清除闹钟中断标志
RTC_ClearITPendingBit(RTC_IT_ALRA);
//清除外部中断标志
EXTI_ClearITPendingBit(EXTI_Line17);
}