STM32——RTC实时时钟

RTC简介
STM32F4的RTC,是一个独立的BCD 定时器/计数器。STM32F4的RTC 提供一个日历时钟(包含年月日时分秒信息)、两个可编程闹钟(ALARM A和ALARM B)中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC 还包含用于管理低功耗模式的自动唤醒单元。STM32F4的实时时钟(RTC)相对于STM32F1来说,改进了不少,自带了日历功能,让软件编程更加简单。
两个32位寄存器(TR和DR)包含二进码十进数格式(BCD) 的秒、分钟、小时(12或24小时制)、星期、日期、月份和年份。此外,还可提供二进制格式的亚秒值。
RTC可以自动将月份的天数补偿为 28 、29(闰年)、30 和 31 天,并且还可以进行夏令时补偿。
RTC结构框图
在这里插入图片描述
(1)标号1:时钟源
RTC 时钟源(RTCCLK)可通过时钟控制器从 LSE 时钟、LSI 振荡器钟以及 HSE时钟三者中选择。其中使用最多的是LSE,即外部低速时钟,通常选择一个大小为32.768KHZ的晶振提供(配合2个谐振电容)。LSI是芯片内部的30KHZ晶体,精度比较低,对于时钟精度要求高的场合不建议使用。HSE_RTC由HSE分频得到,最高是4M。
(2)标号2:预分频器
预分频器PRER由7位的异步预分频器APRE和15位的同步预分频器SPRE组成。为最大程度地降低功耗,预分频器分为 2 个可编程的预分频器。一个通过 RTC_PRER 寄存器的 PREDIV_A 位配置的 7 位异步预分频器,另一个通过 RTC_PRER 寄存器的 PREDIV_S 位配置的 15 位同步预分频器。
异步预分频器时钟计算公式为:
fCK_APRE=fRTC_CLK/(PREDIV_A+1)
ck_apre时钟用于为RTC亚秒递减计数器(RTC_SSR)提供时钟。当该计数器计数到 0 时,会使用 PREDIV_S 的内容重载 RTC_SSR 。而PREDIV_S一般为255,这样,我们得到亚秒时间的精度是:1/256秒,即3.9ms左右,有了这个亚秒寄存器RTC_SSR,就可以得到更加精确的时间数据。
同步预分频器时钟计算公式为:
fCK_SPRE=fRTC_CLK/[(PREDIV_S+1)*(PREDIV_A+1)]
ck_spre 时钟既可以用于更新日历,也可以用作 16 位唤醒自动重载定时器的时基。通常的情况下,我们会选择LSE作为RTC的时钟源,即fRTC_CLK==32.768KHZ。然后经过预分频器PRER分频生成1HZ的时钟用于更新日历。使用两个预分频器分频的时候,为了最大程度的降低功耗,我们一般把异步预分频器(PREDIV_A)设置成较大的值,为了生成1HZ的同步预分频器时钟CK_SPRE,通常我们设置:PREDIV_A=0X7F,即128分频;PREDIV_S=0XFF,即256分频,代入上述同步预分频器时钟计算公式即可得到fCK_SPRE=1Hz。
(3)标号3:实时时钟和日历
STM32F4的RTC时间信息是存放在日历时间( RTC_TR) 和日期( RTC_DR)寄存器中,可以读取也可以写入。亚秒值存放在RTC亚秒寄存器(RTC_SSR)中,只能读取不能写入。这些寄存器都具有写保护,所以需要使能后备寄存器访问功能才能读取或写入时间。
STM32F4 的 RTC 日历时间( RTC_TR) 和日期( RTC_DR)寄存器可通过与 PCLK1( APB1 时钟)同步的影子寄存器来访问,这些时间和日期寄存器也可以直接访问,这样可避免等待同步的持续时间。
每隔两个 RTC_CLK 周期,当前日历值便会复制到影子寄存器,并将 RTC_ISR 寄存器的 RSF位置 1。在停机和待机模式下不会执行复制操作。退出这两种模式 时,影子寄存器会在最长 2 个 RTCCLK 周期后进行更新。
(4)标号4:可编程闹钟
RTC 单元提供两个可编程闹钟,即闹钟 A 和闹钟 B。可通过将 RTC_CR 寄存器中的 ALRAE 和 ALRBE 位置 1 来使能可编程闹钟功能。
如果日历亚秒、秒、分钟、小时、日期或日分别与闹钟寄存器 RTC_ALRMASSR/RTC_ALRMAR 和RTC_ALRMBSSR/RTC_ALRMBR 中编程的值相匹配,则 ALRAF 和 ALRBF 标志会被置为1。可通过 RTC_ALRMAR 和 RTC_ALRMBR 寄存器的 MSKx 位以及 RTC_ALRMASSR 和 RTC_ALRMBSSR 寄存器的 MASKSSx 位单独选择各日历字段。可通过 RTC_CR 寄存器中的 ALRAIE 和 ALRBIE 位使能闹钟中断。闹钟 A 和闹钟 B(如果已通过 RTC_CR 寄存器中的位 OSEL[0:1] 使能)可连接到 RTC_ALARM输出,RTC_ALARM 最终连接到 RTC 的外部引脚 RTC_AF1(即 PC13)。可通过 RTC_CR 寄存器的 POL 位配置 RTC_ALARM 极性,可以为输出高电平或低电平。本章我们就用闹钟A产生闹铃。
(5)标号5:周期性自动唤醒
STM32F4 的 RTC 不带秒钟中断了,但是多了一个周期性自动唤醒功能。周期性唤醒功能由 16 位可编程自动重载递减计数器生成,唤醒定时器范围可扩展至 17 位,可用于周期性中断/唤醒。可通过 RTC_CR 寄存器中的 WUTE 位来使能此唤醒功能。唤醒定时器的时钟输入可以是:
● 2、 4、 8 或 16 分频的 RTC 时钟 (RTCCLK)。
当 RTCCLK 为 LSE (32.768 kHz) 时,可配置的唤醒中断周期介于 122 μs 和 32 s 之间,且分辨率低至 61 μs。
● ck_spre(通常为 1 Hz 内部时钟)
当 ck_spre 频率为 1 Hz 时,可得到的唤醒时间为 1s 到 36h 左右,分辨率为 1 秒。这一较大的可编程时间范围分为两部分:
— WUCKSEL [2:1] = 10 时为 1s 到 18h。
— WUCKSEL [2:1] = 11 时约为 18h 到 36h。
在后一种情况下,会将 2^16 添加到 16 位计数器当前值(即扩展到 17 位,相当于最高位用WUCKSEL [1]代替)。
完成初始化序列后,定时器开始递减计数。在低功耗模式下使能唤醒功能时,递减计数保持有效。此外,当计数器计数到 0 时, RTC_ISR
寄存器的 WUTF 标志会置 1,并且唤醒寄存器会使用其重载值( RTC_WUTR 寄存器值)自动重载。之后必须用软件清零 WUTF 标志。通过将 RTC_CR2 寄存器中的 WUTIE 位置 1 来使能周期性唤醒中断时,它会使器件退出低功耗模式。如果已通过 RTC_CR 寄存器中的位 OSEL[0:1] 使能周期性唤醒标志,则该标志可连接到RTC_ALARM 输出。可通过 RTC_CR 寄存器的 POL 位配置 RTC_ALARM 极性。系统复位以及低功耗模式(睡眠、停机和待机)对唤醒定时器没有任何影响,所以唤醒定时器,可以用于周期性唤醒STM32F4。
(6)标号5:时间戳
时间戳即时间点的意思,就是某一个时刻的时间。 将 RTC_CR 寄存器的 TSE 位置 1 可使能时间戳。当在 TIMESTAMP 备用功能映射到的引脚上检测到时间戳事件时,日历会保存到时间戳寄存器( RTC_TSSSR、 RTC_TSTR 和 RTC_TSDR)中。发生时间戳事件时, RTC_ISR 寄存器中的时间戳标志位 (TSF) 将置 1。通过将 RTC_CR 寄存器中的 TSIE 位置 1
,可在发生时间戳事件时生成中断。
时间戳复用功能 (RTC_TS) 可映射到 RTC_AF1 或 RTC_AF2,具体取决于 RTC_TAFCR 寄存器中 TSINSEL 位的值。
时间戳往往用来记录危及时刻的时间,以供事后排查问题时查询。
(7)标号6:入侵检测
STM32F4的RTC有两个入侵检测输入引脚可用,分别是RTC_AF1( PC13)和 RTC_AF2( PI8)。这两个输入既可配置为边沿检测,也可配置为带过滤的电平检测。
备份寄存器 (RTC_BKPxR) 包括20 个 32 位寄存器,用于存储 80 字节的用户应用数据。这些寄存器在备份域中实现,可在 VDD 电源关闭时通过 VBAT 保持上电状态。备份寄存器不会在系统复位或电源复位时复位,也不会在器件从待机模式唤醒时复位。只有当发生入侵检测事件时,备份寄存器将复位。通过将 RTC_TAFCR 寄存器中的 TAMPIE 位置 1,可在发生入侵检测事件时生成中断。
STM32F4 RTC配置步骤
(1)使能电源时钟,开启RTC后备寄存器写访问

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);//打开后备寄存器访问

(2)开启LSE时钟,选择和使能RTC时钟源

RCC_LSEConfig(RCC_LSE_ON);//开启外部32.768K RTC时钟
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择LSE作为RTC时钟
RCC_RTCCLKCmd(ENABLE);//使能RTC时钟

(3)初始化RTC,包括RTC分频、时间格式等

ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);
typedef struct
{
  uint32_t RTC_HourFormat;   //指定RTC小时格式
  uint32_t RTC_AsynchPrediv; //配置RTC_CLK的异步分频因子 
  uint32_t RTC_SynchPrediv;  //配置RTC_CLK的同步分频因子
}RTC_InitTypeDef;

RTC_HourFormat:用来设置RTC小时格式,由 RTC_CR寄存器的 FMT 位进行配置。RTC含有24小时(RTC_HourFormat_24)和12小时制(RTC_HourFormat_12)格式。本章实验使用的是24小时制,所以参数配置为RTC_HourFormat_24。
RTC_AsynchPrediv:用来设置RTC异步分频系数,由 RTC 预分频器寄存器 RTC_PRER 的 PREDIV_A[6:0]位配置。由于是7位有效,所以最大不能超过0X7F。
RTC_SynchPrediv:用来设置RTC同步分频系数,由 RTC 预分频器寄存器 RTC_PRER 的 PREDIV_S[14:0]位配置。由于是15位有效,所以最大不能超过0X7FFF。
(4)设置RTC时间

ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
typedef struct
{
  uint8_t RTC_Hours;    //小时设置
  uint8_t RTC_Minutes;  //分钟设置
  uint8_t RTC_Seconds;  //秒设置
  uint8_t RTC_H12;      //AM/PM符号设置
}RTC_TimeTypeDef;

RTC_Hours:用于设置小时,如果是12小时制,取值范围是0-11,;24小时制取值范围是0-23。
RTC_Minutes:用于设置分钟,取值范围是0-59。
RTC_Seconds:用于设置秒,取值范围是0-59。
RTC_H12:用于设置AM/PM,可选参数值为RTC_H12_AM和RTC_H12_PM。
选择RTC_H12_AM即为24小时制,选择RTC_H12_PM则为12小时制
例如我们要设置RTC初始时间是16:30:50,则配置如下:
RTC_TimeTypeDef RTC_TimeTypeInitStructure;
RTC_TimeTypeInitStructure.RTC_Hours=16;
RTC_TimeTypeInitStructure.RTC_Minutes=30;
RTC_TimeTypeInitStructure.RTC_Seconds=50;
RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
(5)设置RTC日期

ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
typedef struct
{
  uint8_t RTC_WeekDay; //星期几设置
  uint8_t RTC_Month;   //月份设置
  uint8_t RTC_Date;    //日期设置  
  uint8_t RTC_Year;    //年份设置
}RTC_DateTypeDef;

RTC_WeekDay:用来设置星期几,取值范围是1-7,对应的是星期一到星期日。
RTC_Month:用来设置月份,取值范围是1-12。
RTC_Date:用来设置日期,取值范围是1-31。
RTC_Year:用来设置年份,取值范围是0-99。
例如我们要设置RTC初始日期是16年9月14日星期三,则配置如下:
RTC_DateTypeDef RTC_DateTypeInitStructure;
RTC_DateTypeInitStructure.RTC_Date=14;
RTC_DateTypeInitStructure.RTC_Month=9;
RTC_DateTypeInitStructure.RTC_WeekDay=3;
RTC_DateTypeInitStructure.RTC_Year=16;
RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);

(6)获取RTC当前日期和时间

void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);

void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);

(7)开启唤醒中断,包括设置唤醒时钟、唤醒自动重装载值、NIVC等
RTC_ITConfig(RTC_IT_WUT,ENABLE);
RTC_WakeUpCmd( ENABLE);
由于周期性唤醒中断是连接在外部中断线22上,所以还需要使能EXTI_Line22外部中断功能
EXTI_Init()
NVIC_Init()
void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock);
void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter);

例如设置1秒钟自动唤醒周期配置如下:
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);//唤醒时钟选择
RTC_SetWakeUpCounter(0);
(8)设置RTC闹钟,开启闹钟中断并设置NVIC

void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef*RTC_AlarmStruct);

typedef struct
{
RTC_TimeTypeDef RTC_AlarmTime; //闹钟时间设置
uint32_t RTC_AlarmMask; //闹钟时间掩码设置
uint32_t RTC_AlarmDateWeekDaySel; //闹钟日期/星期选择
uint8_t RTC_AlarmDateWeekDay; //指定闹钟日期/星期
}RTC_AlarmTypeDef;

RTC_AlarmTime:此变量为RTC_TimeTypeDef结构体类型
RTC_AlarmMask:用来设置闹钟时间掩码,即选择闹钟时间哪些时间无效。取值可为:RTC_AlarmMask_None(全部有效)、
RTC_AlarmMask_DateWeekDay(日期或者星期无效)、 RTC_AlarmMask_Hours(小时无效)、 RTC_AlarmMask_Minutes(分钟无
效)、RTC_AlarmMask_Seconds(秒钟无效)、 RTC_AlarmMask_All(全部无效)。比如选择 RTC_AlarmMask_None,那么就是当所有的时分秒以及星期几/(或者每月哪一天)都要精确匹配成功后才能产生闹钟。
RTC_AlarmDateWeekDaySel:用来选择闹钟是按日期还是按星期。可选参数为:RTC_AlarmDateWeekDaySel_Date和RTC_AlarmDateWeekDaySel_WeekDay。要想这个配置有效,则 RTC_AlarmMask 不能配置为 RTC_AlarmMask_DateWeekDay,否则会被屏蔽掉。
RTC_AlarmDateWeekDay:用来设置闹钟的日期或者星期,当闹钟选择按日期时即RTC_AlarmDateWeekDaySel配置为
RTC_AlarmDateWeekDaySel_Date,则此参数可配置为0-31,如果RTC_AlarmDateWeekDaySel配置为RTC_AlarmDateWeekDaySel_WeekDay,则此参数可配置为1-7,即星期一到星期天。

void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState);
RTC_ITConfig(RTC_IT_ALRA,ENABLE);//开启闹钟A中断
RTC_AlarmCmd(RTC_Alarm_A,ENABLE);//开启闹钟A

RTC闹钟中断是连接在外部中断线17上,所以还需要初始化外部中断EXTI_Line17。
(9)编写RTC中断服务函数
RTC_WKUP_IRQHandler
RTC_Alarm_IRQHandler
FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);
RTC_ClearFlag(RTC_FLAG_WUTF);
RTC_ClearFlag(RTC_FLAG_ALRAF);
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_ClearITPendingBit(EXTI_Line22);在这里插入图片描述
rtc.c

#include "rtc.h"
#include "SysTick.h"
#include "led.h"
#include <stdio.h>

//初始化RTC中设置时间函数
ErrorStatus  RTC_SET_Time(u8 hour,u8 min,u8 sec,u8 ampm)
{
		RTC_TimeTypeDef  RTC_TimeStructure;
	  RTC_TimeStructure.RTC_H12 = ampm;
	  RTC_TimeStructure.RTC_Hours = hour;
	  RTC_TimeStructure.RTC_Minutes = min;
	  RTC_TimeStructure.RTC_Seconds = sec;
	  
                
	  return	RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure); //使用RTC_Format_BIN会自动转换为BCD格式

}


//设置日期函数
ErrorStatus RTC_SET_Date(u8 year, u8 month, u8 date, u8 weekday)
{
		RTC_DateTypeDef   RTC_DateStructure;
		RTC_DateStructure.RTC_Date = date;
	  RTC_DateStructure.RTC_Month = month;
		RTC_DateStructure.RTC_WeekDay = weekday;
		RTC_DateStructure.RTC_Year = year;
	
 		return RTC_SetDate(RTC_Format_BIN, &RTC_DateStructure);

}


u8 RTC_Config(void)
{
	  u8 i;
		RTC_InitTypeDef   RTC_InitStructu;
	
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
		PWR_BackupAccessCmd(ENABLE);//打开后备寄存器访问

		if(RTC_ReadBackupRegister(RTC_BKP_DR0)!= 0x5050){         //防止反复设置时间。后备寄存器初始没有设置,该条件肯定成立
				RCC_LSEConfig(RCC_LSE_ON);  ///开启外部32.768K时钟
			  while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == 0){    //判断LSE是否就绪
						 i++;
						 myDelay_ms(10);
				}
				if(i == 0){
						return 1;              //LSE 开启失败
				}
				
				RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择LSE作为RTC时钟 在stmf4xx_rcc.h中
				RCC_RTCCLKCmd(ENABLE);//使能RTC时钟

				RTC_InitStructu.RTC_AsynchPrediv = 0x7F;    //配置RTC_CLK的异步分频因子 
				RTC_InitStructu.RTC_HourFormat = RTC_HourFormat_24;//指定RTC24小时格式
				RTC_InitStructu.RTC_SynchPrediv = 0xff;   //配置RTC_CLK的同步分频因子

				RTC_Init(&RTC_InitStructu);    //初始化RTC,包括RTC分频、时间格式等
				
				RTC_SET_Time(16,35,50,RTC_H12_AM); //设置RTC时间,RTC_H12_AM为24小时制,RTC_H12_PM为12小时制

				RTC_SET_Date(16,9,14,3); //设置日期
				
				RTC_WriteBackupRegister(RCC_RTCCLKSource_LSE,0x5050); //向后备寄存器写入初始if条件的值让其之后不进入该if防止时间重复设置
		}
			
		return 0;
}


//唤醒中断函数
void  RTC_Set_WakeUp(u32 wksel,u16 cnt)
{
			EXTI_InitTypeDef  EXTI_InitStructure; //外部中断结构体
			NVIC_InitTypeDef NVIC_InitStructure; //NVIC结构体
	
			RTC_WakeUpCmd(DISABLE);  //先关闭wakeup
			RTC_WakeUpClockConfig(wksel); //设置唤醒时钟源
			RTC_SetWakeUpCounter(cnt);   //设置周期性唤醒自动重装载值

			EXTI_ClearITPendingBit(EXTI_Line22);  //开启中断前清除中断线
	    RTC_ClearITPendingBit(RTC_IT_WUT);   //开启RTC前清除RTC唤醒中断标志位
	
			RTC_ITConfig(RTC_IT_WUT,ENABLE);  //RTC中断配置
      RTC_WakeUpCmd( ENABLE);           //开启wakeup
	

			EXTI_InitStructure.EXTI_Line=EXTI_Line22;   //外部中断线22
			EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
			EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   //上升沿触发
			EXTI_InitStructure.EXTI_LineCmd=ENABLE;
			EXTI_Init(&EXTI_InitStructure);
	
			NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn;//RTC_WKUP中断通道
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
			NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		//子优先级
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
			NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
}

RTC_TimeTypeDef  RTC_TimeStructure;  //读取到的时间存储的结构体
RTC_DateTypeDef  RTC_DateStructure;  //读取到的日期存储的结构体
u8  buf[40];

void RTC_WKUP_IRQHandler()   //唤醒中断处理函数
{
			if(RTC_GetFlagStatus(RTC_FLAG_WUTF) == SET){   //获取唤醒状态标志
						  RTC_ClearFlag(RTC_FLAG_WUTF);   //清除唤醒状态标志
							led2 = !led2;
							RTC_GetTime(RTC_Format_BIN,&RTC_TimeStructure);  //读取时间
							sprintf((char *)buf,"Time :%.2d:%.2d:%.2d",RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
				      printf("%s\r\n",buf);
							
							RTC_GetDate(RTC_Format_BIN,&RTC_DateStructure);  //读取日期
				      sprintf((char *)buf,"Date :20%d:%.2d:%.2d:%d",RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,RTC_DateStructure.RTC_WeekDay);
				      printf("%s\r\n",buf);
								
			}
			EXTI_ClearITPendingBit(EXTI_Line22);  //清除中断线标志位
}


void RTC_Set_Alarm(u8 hour,u8 min,u8 sec,u8 ampm,u8 week)    //闹钟中断(外部中断17)
{
	    	EXTI_InitTypeDef  EXTI_InitStructure; //外部中断结构体
			NVIC_InitTypeDef NVIC_InitStructure; //NVIC结构体
	   
	    RTC_TimeTypeDef   RTC_TimeStructure; // 闹钟时间结构体
	    RTC_AlarmTypeDef   RTC_AlarmStructure; //闹钟结构体 
		
     	RTC_AlarmCmd(RTC_Alarm_A,DISABLE);    //关闭闹钟功能
			
	    RTC_TimeStructure.RTC_Hours = hour;
	    RTC_TimeStructure.RTC_Minutes = min;
	    RTC_TimeStructure.RTC_Seconds = sec;
	    RTC_TimeStructure.RTC_H12 = ampm;
	
	    RTC_AlarmStructure.RTC_AlarmDateWeekDay = week;   //指定日期和星期
	    RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay; //闹铃为日期还是星期选择
			RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_None;      //闹钟时间掩码设置
			RTC_AlarmStructure.RTC_AlarmTime = RTC_TimeStructure;   //闹钟时间设定
	
			RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmStructure);  //设置闹钟
	    
	    EXTI_ClearITPendingBit(EXTI_Line17);  //开启中断前清除中断线,alarm挂接在17上
	    RTC_ClearITPendingBit(RTC_IT_ALRA);   //开启RTC前清除alarm中断标志位    
	
			RTC_ITConfig(RTC_IT_ALRA,ENABLE);    //开启中断
	    RTC_AlarmCmd(RTC_Alarm_A,ENABLE);    //开启闹钟功能
			
			
			EXTI_InitStructure.EXTI_Line=EXTI_Line17;   //外部中断线22
			EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
			EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   //上升沿触发
			EXTI_InitStructure.EXTI_LineCmd=ENABLE;
			EXTI_Init(&EXTI_InitStructure);
	
			NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;//RTC_WKUP中断通道
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
			NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
			NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	    
}

void  RTC_Alarm_IRQHandler(void) //闹钟中断
	
{
          if(RTC_GetFlagStatus(RTC_FLAG_ALRAF) == SET){  //获取闹钟中断标志
								 RTC_ClearFlag(RTC_FLAG_ALRAF);   //清除闹钟状态标志
								 led1 = 0;
						     myDelay_ms(2000);
						     led1 = 1;						
					}
					EXTI_ClearITPendingBit(EXTI_Line17);  //清除中断线标志位
}

main.c

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "key.h"
#include "dma.h"
#include "rtc.h"

int main()
{	
	u8 i=0;
	

	
	SysTick_Init(168);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	LED_Init();
	USART1_Init(9600);
	KEY_Init();
	adcx_Init();
	TIM11_CH1_PWM_Init(255,0); //APB2总线,最大时钟168M,168/256 = 656.25KHz
	RTC_Config();
	RTC_Set_WakeUp(RTC_WakeUpClock_CK_SPRE_16bits,0);
	RTC_Set_Alarm(16,37,50,RTC_H12_AM,3);
	
	
	while(1)
	{
	
		i++;
		
		if(i%20==0){

			led1=!led1;
		}
		
		
		myDelay_ms(10);
	}
}

		 


  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值