STM32进阶-RTC时钟应用的详细步骤

RTC时钟详细步骤

一、RTC概述

简介
RTC (Real Time Clock):实时时钟

  • STM32 的 RTC 外设,实质是一个掉电后还继续运行的定时器。RTC是个独立的BCD定时器/计数器。提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。
  • 两个32位寄存器包含二进码十进制格式(BCD)的秒,分钟,小时(12或24小时制),星期几,日期,月份和年份。此外,还可以提供二进制的亚秒值。系统可以自动将月份的天数补偿为28,29(闰年),30,31天。并且还可以进行夏令时补偿。

主要特性

  • 包含亚秒、秒、分钟、小时(12/24 小时制)、星期几、日期、月份和年份的日历。
  • 软件可编程的夏令时补偿。
  • 两个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。
  • 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。
  • 参考时钟检测:可使用更加精确的第二时钟源(50 Hz 或 60 Hz)来提高日历的精确度。
  • 利用亚秒级移位特性与外部时钟实现精确同步。
  • 可屏蔽中断/事件:
    — 闹钟 A
    — 闹钟 B
    — 唤醒中断
    — 时间戳
    — 入侵检测
  • 数字校准电路(周期性计数器调整)
    — 精度为 5 ppm
    — 精度为 0.95 ppm,在数秒钟的校准窗口中获得
  • 用于事件保存的时间戳功能(1 个事件)
  • 入侵检测:
    — 2 个带可配置过滤器和内部上拉的入侵事件
  • 20 个备份寄存器(80 字节)。发生入侵检测事件时,将复位备份寄存器。
     
  • 复用功能输出 (RTC_OUT),可选择以下两个输出之一:
    RTC_CALIB:512 Hz 或 1 Hz 时钟输出(LSE 频率为 32.768 kHz)。
    可通过将 RTC_CR 寄存器中的 COE[23] 位置 1 来使能此输出。该输出可连接到器件 RTC_AF1 功能。
    RTC_ALARM(闹钟 A、闹钟 B 或唤醒)。
    可通过配置 RTC_CR 寄存器的 OSEL[1:0] 位选择此输出。该输出可连接到器件
    RTC_AF1 功能。
  • RTC 复用功能输入:
    RTC_TS:时间戳事件检测。该输入可连接到器件 RTC_AF1 和 RTC_AF2 功能。
    RTC_TAMP1:TAMPER1 事件检测。该输入可连接到器件 RTC_AF1 和RTC_AF2功能。
    RTC_TAMP2:TAMPER2 事件检测。
    RTC_REFIN:参考时钟输入(通常为市电,50 Hz 或 60 Hz)。

在这里插入图片描述

二、RTC相关库函数

  • RTC时钟源和时钟操作函数
 void RCC_RTCCLKConfig(uint32_t  CLKSource);//时钟源选择
 void RCC_RTCCLKCmd(FunctionalState NewState)//时钟使能
  • RTC初始化函数
ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);
typedef struct
{ 
		uint32_t RTC_HourFormat;    //小时格式:24/12
 		uint32_t RTC_AsynchPrediv;  //异步分频 系数
	    uint32_t RTC_SynchPrediv;   //同步分频系数
}RTC_InitTypeDef
  • RTC日历配置相关函数
 //设置时间
 ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
 
//获取时间
 void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);

//设置日期
 ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
 
//获取日期
 void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
 
//获取到亚秒的信息
 uint32_t RTC_GetSubSecond(void);
  • RTC闹钟相关函数
//禁止或使能RTC闹钟。
ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm, FunctionalState NewState);

//RTC闹钟时间配置。
void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct);
 
//获取RTC闹钟的时间配置
void RTC_GetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct);
 
//功能配置RTC AlarmA/B的亚秒
void RTC_AlarmSubSecondConfig(uint32_t RTC_Alarm, uint32_t RTC_AlarmSubSecondValue,  uint32_t RTC_AlarmSubSecondMask);

//得到RTC的亚秒时间。
uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm);
  • RTC周期唤醒相关函数
//配置RTC唤醒时钟源
void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock);

//配置RTC唤醒计数
void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter);

//得到唤醒定时器的计数值
uint32_t RTC_GetWakeUpCounter(void);

 //关闭WAKE UP
RTC_WakeUpCmd(DISABLE);	       
  • RTC 中断配置以及状态相关函数
//使能或禁止RTC中断
void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState);

//查询RTC标志,主要用于非中断函数
FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);

//清除RTC标志,主要用于非中断函数
void RTC_ClearFlag(uint32_t RTC_FLAG);

//查询RTC中断标志
ITStatus RTC_GetITStatus(uint32_t RTC_IT);

//清除RTC中断标志
void RTC_ClearITPendingBit(uint32_t RTC_IT);
  • RTC相关约束函数
//取消写保护
void RTC_WriteProtectionCmd(FunctionalState NewState);

//进入配置模式,RTC_ISR_INITF位设置为1
 ErrorStatus RTC_EnterInitMode(void);
 
//退出初始化模式。
 void RTC_ExitInitMode(void)
  • 其他相关函数
//从备份数据寄存器读出数据。
uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);

//写数据到RTC备份数据寄存器
void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data);

//使能或禁止RTC中断
void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState);

 

三、RTC日历配置步骤

  • 使能PWR时钟:RCC_APB1PeriphClockCmd();
  • 使能后备寄存器访问: PWR_BackupAccessCmd();
  • 配置RTC时钟源,使能RTC时钟:
            RCC_RTCCLKConfig();
            RCC_RTCCLKCmd();
            如果使用LSE,要打开LSE:RCC_LSEConfig(RCC_LSE_ON);
  • 初始化RTC(同步/异步分频系数和时钟格式):RTC_Init ();
  • 设置时间:RTC_SetTime ();
  • 设置日期:RTC_SetDate();
#define RTC_BKP_VALE 0x2021

void Rtc_Init(void)
{
	RTC_InitTypeDef  RTC_InitStruct;
	RTC_TimeTypeDef  RTC_TimeStruct;
	RTC_DateTypeDef  RTC_DateStruct;
	
	//1、使能PWR时钟:
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	//2、使能后备寄存器访问: 这类寄存器是掉电保存数据的   
	PWR_BackupAccessCmd(ENABLE);
	
	if(RTC_ReadBackupRegister(RTC_BKP_DR0) != RTC_BKP_VALE)
	{
		//3、配置RTC时钟源,使能RTC时钟:
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		//要打开LSE:
		RCC_LSEConfig(RCC_LSE_ON);
		
		delay_ms(50);  //延时等待时钟稳定
	
		RTC_InitStruct.RTC_HourFormat	= RTC_HourFormat_24;  //时间格式
		RTC_InitStruct.RTC_AsynchPrediv	= 0x7F;               //异步分频器
		RTC_InitStruct.RTC_SynchPrediv	= 0xFF;               //同步分频器
		//4、 初始化RTC(同步/异步分频系数和时钟格式):
		RTC_Init(&RTC_InitStruct);
	
		RTC_TimeStruct.RTC_H12		= RTC_H12_PM;  //对于24小时格式,这个参数可以不用
		RTC_TimeStruct.RTC_Hours	= 16; //时
		RTC_TimeStruct.RTC_Minutes	= 36; //分
		RTC_TimeStruct.RTC_Seconds	= 00; //秒
		//5、 设置时间:
		RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
		
		RTC_DateStruct.RTC_Year		= 20; 	//20年,前年20要自己补
		RTC_DateStruct.RTC_Month    = 8;    //月
		RTC_DateStruct.RTC_Date		= 19;	//日
		RTC_DateStruct.RTC_WeekDay  = 3;	//星期
		//6、设置日期:
		RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
		
		//写后备寄存器
		RTC_WriteBackupRegister(RTC_BKP_DR0, RTC_BKP_VALE);
	}
}

四、RTC闹钟配置步骤

 所有 RTC 中断均与 EXTI 控制器相连。要使能 RTC 闹钟中断,需按照以下顺序操作:

  1. 将 EXTI 线 17 配置为中断模式并将其使能,然后选择上升沿有效

  2. 配置 NVIC 中的 RTC_Alarm IRQ 通道并将其使能

  3. 配置 RTC 以生成 RTC 闹钟(闹钟 A 或闹钟 B)。

    ①:RTC已经初始化好相关参数。
    ②:关闭闹钟:RTC_AlarmCmd(RTC_Alarm_A,DISABLE);
    ③:配置闹钟参数:RTC_SetAlarm();3
    ④:开启闹钟:RTC_AlarmCmd(RTC_Alarm_A,EABLE);
    ⑤:开启配置闹钟中断:
            RTC_ITConfig();
            EXTI_Init();
            NVIC_Init();

    ⑥:编写中断服务函数:RTC_Alarm_IRQHandler();

//闹钟A
void RTC_Alarm_AInit(void)
{
	RTC_TimeTypeDef RTC_AlarmTime;
	RTC_AlarmTypeDef RTC_AlarmStruct;
	EXTI_InitTypeDef  EXTI_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	//2、关闭闹钟:
	RTC_AlarmCmd(RTC_Alarm_A,DISABLE); 
	
	//闹钟时间设置
	RTC_AlarmTime.RTC_H12		= RTC_H12_PM;  //对于24小时格式,这个参数可以不用
	RTC_AlarmTime.RTC_Hours		= 16; //时
	RTC_AlarmTime.RTC_Minutes	= 36; //分
	RTC_AlarmTime.RTC_Seconds	= 30; //秒
	
	RTC_AlarmStruct.RTC_AlarmTime 			= RTC_AlarmTime;  		//时间设置
	RTC_AlarmStruct.RTC_AlarmMask			= RTC_AlarmMask_None;	//无掩码位 按实际时间来响应闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel	= RTC_AlarmDateWeekDaySel_WeekDay; //按星期来闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDay	= RTC_Weekday_Wednesday;  //星期3
	
	//3、配置闹钟参数:
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStruct);
		
	//4、开启闹钟:
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);
	//5、开启配置闹钟中断:	
	RTC_ITConfig(RTC_IT_ALRA,ENABLE);
	
	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通道,在stm32f4xx.h可查看通道 (可变)
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 0x01;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 0x01;			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//使能
	//配置中断分组(NVIC),并使能中断。
    NVIC_Init(&NVIC_InitStruct);	
}

void RTC_Alarm_IRQHandler(void)
{
	//判断中断标志是否为1
	if(EXTI_GetITStatus(EXTI_Line17) == SET)
	{
		//判断是否为闹钟A
		if(RTC_GetFlagStatus(RTC_FLAG_ALRAF) == SET)
		{
			//闹钟响应事件
			PFout(9) = 0;	
			RTC_ClearFlag(RTC_FLAG_ALRAF);
		}			
		//清空标志位
		EXTI_ClearITPendingBit(EXTI_Line17);
	}
}
//闹钟B
void RTC_Alarm_BInit(void)
{
	RTC_TimeTypeDef   RTC_AlarmTime;
	RTC_AlarmTypeDef  RTC_AlarmStruct;
	EXTI_InitTypeDef  EXTI_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	//2、关闭闹钟:
	RTC_AlarmCmd(RTC_Alarm_B,DISABLE); 
	
	
	//闹钟时间设置
	RTC_AlarmTime.RTC_H12		= RTC_H12_PM;  //对于24小时格式,这个参数可以不用
	RTC_AlarmTime.RTC_Hours		= 16; //时
	RTC_AlarmTime.RTC_Minutes	= 36; //分
	RTC_AlarmTime.RTC_Seconds	= 35; //秒
	
	RTC_AlarmStruct.RTC_AlarmTime 			= RTC_AlarmTime;  		//时间设置
	RTC_AlarmStruct.RTC_AlarmMask			= RTC_AlarmMask_None;	//无掩码位 按实际时间来响应闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel	= RTC_AlarmDateWeekDaySel_Date; //按日期来闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDay	= 19;  //19日
	

	//3、配置闹钟参数:
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B, &RTC_AlarmStruct);
		
	//4、开启闹钟:
	RTC_AlarmCmd(RTC_Alarm_B,ENABLE);
	//5、开启配置闹钟中断:
	
	RTC_ITConfig(RTC_IT_ALRB,ENABLE);
	
	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通道,在stm32f4xx.h可查看通道 (可变)
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 0x01;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 0x01;			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//使能
	//配置中断分组(NVIC),并使能中断。
    NVIC_Init(&NVIC_InitStruct);	


}

main.c

int main(void)
{
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_DateTypeDef RTC_DateStruct;

	//NVIC分组(一个工程当中只能配置一次分组)抢占优先级2位,值范围:0~3;响应优先级2位,值范围:0~3;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Delay_Init();
	Led_Init();
	Usart1_Init();
	Rtc_Init();
	RTC_Alarm_AInit();
	
	while(1)
	{
		RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
		RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
		printf("时间:%d:%d:%d\r\n", RTC_TimeStruct.RTC_Hours, RTC_TimeStruct.RTC_Minutes, 
																	RTC_TimeStruct.RTC_Seconds);
		printf("日期:20%d年%d月%d日,星期%d\r\n\r\n",RTC_DateStruct.RTC_Year, 
								RTC_DateStruct.RTC_Month, RTC_DateStruct.RTC_Date, RTC_DateStruct.RTC_WeekDay);
		delay_s(1);
	}
	return 0;
}

五、RTC周期性自动唤醒配置一般步骤

  • RTC已经初始化好相关参数。
  • 关闭WakeUp:RTC_WakeUpCmd(DISABLE);
  • 配置WakeUp时钟分频系数/来源: RTC_WakeUpClockConfig();
  • 设置WakeUp自动装载寄存器:RTC_SetWakeUpCounter();
  • 使能WakeUp : RTC_WakeUpCmd( ENABLE);
  • 开启配置闹钟中断:
            RTC_ITConfig();
            EXTI_Init();
            NVIC_Init();
  • 编写中断服务函数: RTC_WKUP_IRQHandler();
ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
函数功能:时间设置
uint32_t RTC_Format:存储格式
RTC_Format_BIN:二进制存储
RTC_Format_BCD:BCD码格式

typedef struct
{
    uint8_t RTC_Hours; //时
    uint8_t RTC_Minutes; //分
    uint8_t RTC_Seconds; //秒
    uint8_t RTC_H12; //上下午
}RTC_TimeTypeDef;
  ↩︎

ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct)
函数功能:日期设置
uint32_t RTC_Format:存储格式
RTC_Format_BIN:二进制存储
typedef struct
{
    uint8_t RTC_WeekDay; //星期
    uint8_t RTC_Month; //月
    uint8_t RTC_Date; //日
    uint8_t RTC_Year; //年
}RTC_DateTypeDef;
  ↩︎

void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct);
函数功能:设置闹钟
uint32_t RTC_Format:存储格式
RTC_Format_BIN:二进制存储
RTC_Format_BCD:BCD码格式
uint32_t RTC_Alarm:选择哪个闹钟

typedef struct
{
    RTC_TimeTypeDef RTC_AlarmTime; //时间设置结构体
    uint32_t RTC_AlarmMask; //掩码位
    uint32_t RTC_AlarmDateWeekDaySel; //选择闹钟响应方式(日期,星期)
    uint8_t RTC_AlarmDateWeekDay; //日期或者星期的设置
} RTC_AlarmTypeDef;


typedef struct
{
    uint8_t RTC_Hours; //时
    uint8_t RTC_Minutes; //分
    uint8_t RTC_Seconds; //秒
    uint8_t RTC_H12; //上下午
}RTC_TimeTypeDef; 

 https://blog.csdn.net/wprpr/article/details/108183825?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

猜你喜欢

转载自blog.csdn.net/ba_wang_mao/article/details/113695623