stm32f4xx-RTC实时时钟_calendar_alarm

一、RTC

RTC(Real_Time Clock)

实时时钟 (RTC) 是一个独立的 BCD 定时器/计数器。RTC 提供一个日历时钟、两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC 还包含用于管理低功耗模式的自动唤醒单元。

两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时(12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。

系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。并且还可以进行夏令时补偿。

其它 32 位寄存器还包含可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。

此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。

上电复位后,所有 RTC 寄存器都会受到保护,以防止可能的非正常写访问。无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC 便不会停止工作。

原理图

static	uint32_t uwSynchPrediv = 0xFF;//异步分频
static	uint32_t uwAsynchPrediv = 0x7F;//同步分频
/*ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
32.768KHz /128/256 = 1Hz

LSE-RTC_PER–RTC_PER–RTC_WUTR–WUTF唤醒标志

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二、中断配置

《STM32F4xx中文参考手册.pdf》第585页

1、 所有 RTC 中断均与 EXTI 控制器相连。

2、要使能 RTC 闹钟中断,需按照以下顺序操作:

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

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

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

3、要使能 RTC 唤醒中断,需按照以下顺序操作:

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

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

3.配置 RTC 以生成 RTC 唤醒定时器事件。

三、BCD码

​ 二进制编码的十进制数,简称BCD码。这种方式是用4位二进制码的组合代表十进制数的0,1,2,3,4,5,6,7,8,9十个数符,4位 二进制码有16种组合,原则上可任选其中的10种作为代码,分别代表十进制中的0,1,2,3,4,5,6,7,8,9这个 十个数符,最常用的BCD码称为8421BCD码,8421分别是4位二进制的位权值。

在这里插入图片描述

在这里插入图片描述

四、库函数

在这里插入图片描述

1.RTC时钟源和时钟操作函数

 void RCC_RTCCLKConfig(uint32_t CLKSource)//时钟源选择

 void RCC_RTCCLKCmd(FunctionalState NewState)//时钟使能

2.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_InitTypeDe

4.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);

5.RTC闹钟相关函数

ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm, FunctionalState NewState)
void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm,  
                            RTC_AlarmTypeDef* RTC_AlarmStruct);
void RTC_GetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, 
                             RTC_AlarmTypeDef* RTC_AlarmStruct);
void RTC_AlarmSubSecondConfig(uint32_t RTC_Alarm, uint32_t RTC_AlarmSubSecondValue, 
                                uint32_t RTC_AlarmSubSecondMask) 
uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm);

6.RTC 中断配置以及状态相关函数


void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState);
FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);
void RTC_ClearFlag(uint32_t RTC_FLAG);
ITStatus RTC_GetITStatus(uint32_t RTC_IT);
void RTC_ClearITPendingBit(uint32_t RTC_IT);

7. RTC周期唤醒相关函数

void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock);
void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter);
uint32_t RTC_GetWakeUpCounter(void);
RTC_WakeUpCmd(DISABLE);//关闭WAKE UP

8.RTC相关约束函数

 void RTC_WriteProtectionCmd(FunctionalState NewState);//取消写保护
 ErrorStatus RTC_EnterInitMode(void);//进入配置模式,RTC_ISR_INITF位设置为1
 void RTC_ExitInitMode(void)//退出初始化模式。

9.其他相关函数

uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR)void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data)
void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState)

10.RTC日期配置

在这里插入图片描述

11.RTC闹钟配置

在这里插入图片描述

12.RTC周期性自动唤醒配置

在这里插入图片描述

四、test

calendar&alarm

uint8_t G_RTCWakeUp_Status = 0;	//RTC_WakeUp中断flag
uint8_t G_AlarmA_Status = 0;//AlarmA中断flag
static	uint32_t uwSynchPrediv = 0xFF;//异步分频
static	uint32_t uwAsynchPrediv = 0x7F;//同步分频
void RTC_init(void)
{
	RTC_InitTypeDef RTC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR时钟
	PWR_BackupAccessCmd(ENABLE);					 	//使能后备寄存器访问 
    if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x1234)		//是否第一次配置?
	{
		RCC_LSEConfig(RCC_LSE_ON);//LSE 开启    
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
		{
		}
			
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟 

		RTC_InitStructure.RTC_AsynchPrediv = uwSynchPrediv;//RTC异步分频系数(1~0X7F)
		RTC_InitStructure.RTC_SynchPrediv  = uwAsynchPrediv;//RTC同步分频系数(0~7FFF)
		RTC_InitStructure.RTC_HourFormat   = RTC_HourFormat_24;//RTC设置为,24小时格式
		RTC_Init(&RTC_InitStructure);
 
        /* Set the date: Tuesday September 06th 2022 */
		RTC_DateStructure.RTC_Year = 0x22;
		RTC_DateStructure.RTC_Month = RTC_Month_September;
		RTC_DateStructure.RTC_Date = 0x06;
		RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Tuesday;
		RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);
	
		/* Set the time to 14h 30mn 00s PM */
		RTC_TimeStructure.RTC_H12     = RTC_H12_PM;
		RTC_TimeStructure.RTC_Hours   = 0x14;
		RTC_TimeStructure.RTC_Minutes = 0x30;
		RTC_TimeStructure.RTC_Seconds = 0x00; 
		RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);   
        
		RTC_WriteBackupRegister(RTC_BKP_DR0,0x1234);	//标记已经初始化过了
	} 
}


//周期性唤醒定时器设置  
/*wksel:  @ref RTC_Wakeup_Timer_Definitions
#define RTC_WakeUpClock_RTCCLK_Div16        ((uint32_t)0x00000000)
#define RTC_WakeUpClock_RTCCLK_Div8         ((uint32_t)0x00000001)
#define RTC_WakeUpClock_RTCCLK_Div4         ((uint32_t)0x00000002)
#define RTC_WakeUpClock_RTCCLK_Div2         ((uint32_t)0x00000003)
#define RTC_WakeUpClock_CK_SPRE_16bits      ((uint32_t)0x00000004)
#define RTC_WakeUpClock_CK_SPRE_17bits      ((uint32_t)0x00000006)
*/
//cnt:自动重装载值.减到0,产生中断.
void RTC_Set_WakeUp(uint32_t wksel,uint16_t cnt)
{ 
	EXTI_InitTypeDef   EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RTC_WakeUpCmd(DISABLE);//关闭WAKE UP
	RTC_WakeUpClockConfig(wksel);//唤醒时钟选择
	RTC_SetWakeUpCounter(cnt);//设置WAKE UP自动重装载寄存器
	
	RTC_ClearITPendingBit(RTC_IT_WUT); //清除RTC WAKE UP的标志
    EXTI_ClearITPendingBit(EXTI_Line22);//清除LINE22上的中断标志位 
	RTC_ITConfig(RTC_IT_WUT,ENABLE);//开启WAKE UP 定时器中断
	RTC_WakeUpCmd( ENABLE);//开启WAKE UP 定时器 
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line22;//LINE22
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE22
	EXTI_Init(&EXTI_InitStructure);//配置
 
	NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
	NVIC_Init(&NVIC_InitStructure);//配置
}
//#define RTC_AlarmDateWeekDaySel_Date      ((uint32_t)0x00000000)	每天    闹
//#define RTC_AlarmDateWeekDaySel_WeekDay   ((uint32_t)0x40000000)  每星期	  闹
//设置闹钟时间(按星期闹铃,24小时制)
//week:星期几(1~7) @ref  RTC_Alarm_Definitions
//hour,min,sec:小时,分钟,秒钟
void RTC_Set_AlarmA(uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
{ 
	EXTI_InitTypeDef   EXTI_InitStructure;
	RTC_AlarmTypeDef RTC_AlarmTypeInitStructure;
	RTC_TimeTypeDef RTC_TimeTypeInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RTC_AlarmCmd(RTC_Alarm_A,DISABLE);//关闭闹钟A 
	
    RTC_TimeTypeInitStructure.RTC_Hours=hour;//小时
	RTC_TimeTypeInitStructure.RTC_Minutes=min;//分钟
	RTC_TimeTypeInitStructure.RTC_Seconds=sec;//秒
	RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
  
	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDay=week;//星期
	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;//按星期闹
	RTC_AlarmTypeInitStructure.RTC_AlarmMask=RTC_AlarmMask_None;//精确匹配星期,时分秒
	RTC_AlarmTypeInitStructure.RTC_AlarmTime=RTC_TimeTypeInitStructure;
    RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmTypeInitStructure);
 
	
	RTC_ClearITPendingBit(RTC_IT_ALRA);//清除RTC闹钟A的标志
	EXTI_ClearITPendingBit(EXTI_Line17);//清除LINE17上的中断标志位 
	
	RTC_ITConfig(RTC_IT_ALRA,ENABLE);//开启闹钟A中断
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);//开启闹钟A 
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line17;//LINE17
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE17
	EXTI_Init(&EXTI_InitStructure);//配置

	NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
	NVIC_Init(&NVIC_InitStructure);//配置
}

//RTC中断服务函数
void RTC_WKUP_IRQHandler(void)
{
	if(RTC_GetITStatus(RTC_IT_WUT) == SET)
	{
		printf("RTC_WKUP_IRQHandler\r\n");
		G_RTCWakeUp_Status = 1;
		
		//清空标志位
		RTC_ClearITPendingBit(RTC_IT_WUT);
		EXTI_ClearITPendingBit(EXTI_Line22);
	}
}
//RTC_AlarmA中断服务函数
void RTC_Alarm_IRQHandler(void)
{
	if(RTC_GetITStatus(RTC_IT_ALRA) == SET)
	{
		printf("RTC_Alarm_IRQHandler\r\n");
		G_AlarmA_Status = 1;
		
		//清空标志位
		RTC_ClearITPendingBit(RTC_IT_ALRA);
		EXTI_ClearITPendingBit(EXTI_Line17);
	}
}

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    RTC_TimeTypeDef RTC_TimeStructure;
	RTC_DateTypeDef RTC_DateStructure;
    USART1_init(115200);
    RTC_Init();
    RTC_Set_AlarmA(2,15,30,30);
    while(1)
	{
//		if(G_RTCWakeUp_Status)//中断唤醒方式
//		{
			//获取时间
			RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure);
			printf("%02x:%02x:%02x\r\n", RTC_TimeStructure.RTC_Hours, 
										 RTC_TimeStructure.RTC_Minutes, 
										 RTC_TimeStructure.RTC_Seconds);
			
			//获取日期
			RTC_GetDate(RTC_Format_BCD, &RTC_DateStructure);
			printf("20%02x/%02x/%02x Week:%x\r\n", RTC_DateStructure.RTC_Year, 
												  RTC_DateStructure.RTC_Month, 
												  RTC_DateStructure.RTC_Date, 
												  RTC_DateStructure.RTC_WeekDay);
			delay_ms(1000);
//			G_RTCWakeUp_Status = 0;
//		}
		if(G_AlarmA_Status)
		{
			printf("Wake up the alarm clock is ringing\r\n");
			break;

			//G_AlarmA_Status = 0;
		}
	}
}
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是基于STM32F4xxRTC实时时钟代码,包括初始化和设置时间的函数: ```c #include "stm32f4xx.h" void RTC_Init(void) { /* 使能PWR和BKP的时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); /* 解锁BKP区域 */ PWR_BackupAccessCmd(ENABLE); /* 复位BKP区域 */ BKP_DeInit(); /* 使能LSE时钟 */ RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) { } /* 选择LSE作为RTC时钟源 */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); /* 使能RTC时钟 */ RCC_RTCCLKCmd(ENABLE); /* 等待RTC同步 */ RTC_WaitForSynchro(); /* 设置RTC预分频器 */ RTC_SetPrescaler(32767); /* 等待RTC同步 */ RTC_WaitForSynchro(); } void RTC_SetTime(uint8_t hour, uint8_t minute, uint8_t second) { RTC_TimeTypeDef RTC_TimeStructure; /* 等待RTC同步 */ RTC_WaitForSynchro(); /* 设置RTC时间 */ RTC_TimeStructure.RTC_Hours = hour; RTC_TimeStructure.RTC_Minutes = minute; RTC_TimeStructure.RTC_Seconds = second; RTC_TimeStructure.RTC_H12 = RTC_H12_AM; RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure); /* 等待RTC同步 */ RTC_WaitForSynchro(); } ``` 在主函数中,可以先调用RTC初始化函数,然后再调用RTC设置时间函数,例如: ```c int main(void) { /* 初始化RTC */ RTC_Init(); /* 设置RTC时间为12:34:56 */ RTC_SetTime(12, 34, 56); while (1) { } } ``` 需要注意的是,RTC模块需要连接外部低速晶振(LSE),并且需要在STM32的RCC寄存器中设置LSE作为RTC时钟源。同时,还需要在PWR寄存器中解锁BKP区域,才能够使用RTC模块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yengi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值