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
//初始化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);
}
}