STM32之RTC实时时钟
一、实时时钟概述
1、实时时钟介绍
英文缩写:RTC。显示年、月、日、时、分、秒、星期,自动计算闰年,能够区分每个月的天数。
RTC特点:能从RTC获取到具体的日期时间,断掉后再开机时间仍然准确(需要纽扣电池)。
RTC模块分为两种,一种集成在芯片内部,另外一种是外接RTC芯片。
2、常用的实时时钟芯片
常见的实时时钟芯片:
常见实时时钟芯片:DS1302、DS1307、PCF8563等。
显示年、月、日、时、分、秒、星期,自动计算闰年,能够区分每个月的天数。
二、STM32内部实时时钟介绍
1、STM32内部实时时钟特点
实时时钟 (RTC) 是一个独立的 BCD 定时器 /计数器。 RTC 提供一个日历时钟、两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。 RTC 还包含用于管理低功耗式的自动唤醒单元。两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时( 12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、 29(闰年)、 30 和 31 天。并且还可以进行夏令时补偿。其它 32 位寄存器还包含可编程的闹钟亚秒、 秒、分钟、小时、星期几和日期。
此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。上电复位后,所有 RTC 寄存器都会受到保护,以防止可能的非正常写访问。无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC 便不会停止工作。
21 -- 0001 0101(平常的十进制转为二进制) -- 0x15
十进制转为BCD码的二进制格式(BCD能表示的范围是 0 - 9)
21 -- 0010 0001 -- 0x21
2、RTC电源部分

RTC断掉主电源以后就会由VBAT供电,所以可以做到断电数据不丢失的效果。
3、STM32内部实时时钟的功能介绍
RTC 单元的主要特性如下(参见图 222: RTC 框图):
● 包含亚秒、秒、分钟、小时( 12/24 小时制)、星期几、日期、月份和年份的日历。
● 软件可编程的夏令时补偿。
● 两个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。
● 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。
● 参考时钟检测:可使用更加精确的第二时钟源(50 Hz 或 60 Hz)来提高日历的精确度。
● 利用亚秒级移位特性与外部时钟实现精确同步。
● 可屏蔽中断 /事件:— 闹钟 A
— 闹钟 B
— 唤醒中断
— 时间戳
— 入侵检测
● 数字校准电路(周期性计数器调整)
— 精度为 5 ppm
— 精度为 0.95 ppm,在数秒钟的校准窗口中获得
● 用于事件保存的时间戳功能( 1 个事件)
● 入侵检测:
— 2 个带可配置过滤器和内部上拉的入侵事件
● 20 个备份寄存器( 80 字节)。发生入侵检测事件时,将复位备份寄存器。
三、STM32内部实时时钟框架

四、RTC基本日历功能框架分析

1、RTC寄存器写保护
系统复位后,可通过 PWR 电源控制寄存器 (PWR_CR) 的 DBP 位保护 RTC 寄存器以防止非正常的写访问。必须将 DBP 位置 1 才能使能 RTC 寄存器的写访问。上电复位后,所有 RTC 寄存器均受到写保护。通过向写保护寄存器 (RTC_WPR) 写入一个密钥来使能对 RTC 寄存器的写操作。要解锁所有 RTC 寄存器(RTC_ISR[13:8]、 RTC_TAFCR 和 RTC_BKPxR 除外)的写保护,
需要执行以下步骤:
1. 将“0xCA”写入 RTC_WPR 寄存器。
2. 将“0x53”写入 RTC_WPR 寄存器。
写入一个错误的关键字会再次激活写保护。
保护机制不受系统复位影响。
2、RTC进入初始化模式(在设置RTC时间和日期要注意的)
要编程包括时间格式和预分频器配置在内的初始时间和日期日历值,需按照以下顺序操作:
1. 将 RTC_ISR 寄存器中的 INIT 位置 1 以进入初始化模式。在此模式下,日历计数器将停止工作并且其值可更新。
2. 轮询 RTC_ISR 寄存器中的 INITF 位。当 INITF 置 1 时进入初始化阶段模式。大约需要2 个 RTCCLK 时钟周期(由于时钟同步)。
3. 要为日历计数器生成 1 Hz 时钟,应首先编程 RTC_PRER 寄存器中的同步预分频系数,然后编程异步分频系数。即使只需要更改这两个字段中之一,也必须对 RTC_PRER寄存器执行两次单独的写访问。
4. 在影子寄存器( RTC_TR 和 RTC_DR)中加载初始时间和日期值,然后通过 RTC_CR寄存器中的 FMT 位配置时间格式( 12 或 24 小时制)。
5. 通过清零 INIT 位退出初始化模式。随后,自动加载实际日历计数器值,在 4 个 RTCCLK时钟周期后重新开始计数。
当初始化序列完成之后,日历开始计数。
系统复位后,应用可读取 RTC_ISR 寄存器中的 INITS 标志,以检查日历是否已初始化。如果该标志为 0,表明日历尚未初始化,因为年份字段设置为其上电复位时的默认值 (0x00)。要在初始化之后读取日历,必须首先用软件检查 RTC_ISR 寄存器的 RSF
3、RTC同步(读取RTC时间和日期时要注意的)
要正确读取 RTC 日历寄存器(RTC_SSR、 RTC_TR 和 RTC_DR), APB1 时钟频率 (fPCLK1 )必须等于或大于 fRTCCLK RTC 时钟频率的七倍。这可以确保同步机制行为的安全性。如果 APB1 时钟频率低于 RTC 时钟频率的七倍,则软件必须分两次读取日历时间寄存器和 日期寄存器。这样,当两次读取的 RTC_TR 结果相同时,才能确保数据正确。否则必须执行第三次读访问。任何情况下, APB1 的时钟频率都不能低于 RTC 的时钟频率。每次将日历寄存器中的值复制到 RTC_SSR、 RTC_TR 和 RTC_DR 影子寄存器时, RTC_ISR
寄存器中的 RSF 位都会置 1 。每两个 TRCCLK 周期执行一次复制。为确保这 3 个值来自同 一时刻点,读取 RTC_SSR 或 RTC_TR 时会锁定高阶日历影子寄存器中的值,直到读取 RTC_DR。为避免软件对日历执行读访问的时间间隔小于 2 个 RTCCLK 周期:第一次读取 日历之后必须通过软件将 RSF 清零,并且软件必等待到 RSF 置 1 之后才可再次读取 RTC_SSR、 RTC_TR 和 RTC_DR 寄存器。
4、STM32内部实时时钟寄存器说明

![]()
RTC 时间寄存器 (RTC_TR)
位 22 PM: AM/PM 符号 (AM/PM notation)
0: AM 或 24 小时制
1: PM
位 21:20 HT[1:0]:小时的十位(BCD 格式) (Hour tens in BCD format)
位 16:16 HU[3:0]:小时的个位(BCD 格式) (Hour units in BCD format)
位 15 保留,必须保持复位值。
位 14:12 MNT[2:0]:分钟的十位(BCD 格式) (Minute tens in BCD format)
位 11:8 MNU[3:0]:分钟的个位(BCD 格式) (Minute units in BCD format)
位 7 保留,必须保持复位值。
位 6:4 ST[2:0]:秒的十位(BCD 格式) (Second tens in BCD format)
位 3:0 SU[3:0]:秒的个位(BCD 格式) (Second units in BCD format)
RTC 日期寄存器 (RTC_DR)
RTC_DR 是日历日期影子寄存器。只能在初始化模式下对该寄存器执行写操作
位 23:20 YT[3:0]:年份的十位(BCD 格式) (Year tens in BCD format)
位 19:16 YU[3:0]:年份的个位(BCD 格式) (Year units in BCD format)
位 15:13 WDU[2:0]:星期几的个位 (Week day units)
000:禁止
001:星期一
...
111:星期日
位 12 MT:月份的十位(BCD 格式) (Month tens in BCD format)
位 11:8 MU:月份的个位(BCD 格式) (Month units in BCD format)
位 7:6 保留,必须保持复位值。
位 5:4 DT[1:0]:日期的十位(BCD 格式) (Date tens in BCD format)
位 3:0 DU[3:0]:日期的个位(BCD 格式) (Date units in BCD format)
RTC 控制寄存器 (RTC_CR)
位 6 FMT:小时格式 (Hour format)
0: 24 小时/天格式
1: AM/PM 小时格式
位 5 BYPSHAD:旁路影子寄存器 (Bypass the shadow registers)
0:日历值(从 RTC_SSR、 RTC_TR 和 RTC_DR 读取时)取自影子寄存器,该影子寄存器
每两个 RTCCLK 周期更新一次。
1:日历值(从 RTC_SSR、 RTC_TR 和 RTC_DR 读取时)直接取自日历计数器。
注意:如果 APB1 时钟的频率低于 7 倍的 RTCCLK 频率,则必须将 BYPSHAD 置“1”。
RTC 初始化和状态寄存器 (RTC_ISR)
位 7 INIT:初始化模式 (Initialization mode)
0:自由运行模式。
1:初始化模式,用于编程时间和日期寄存器(RTC_TR 和 RTC_DR)以及预分频器寄存器
(RTC_PRER)。计数器停止计数,当 INIT 被复位后,计数器从新值开始计数。
位 6 INITF:初始化标志 (Initialization flag)
当此位置 1 时, RTC 处于初始化状态,此时可更新事件、日期和预分频器寄存器。
0:不允许更新日历寄存器。
1:允许更新日历寄存器。位 5 RSF:寄存器同步标志 (Registers synchronization flag)
每次将日历寄存器的值复制到影子寄存器(RTC_SSRx、 RTC_TRx 和 RTC_DRx)时,都
会由硬件将此位置 1。在初始化模式下、平移操作挂起时 (SHPF=1) 或在旁路影子寄存器模
式 (BYPSHAD=1) 下,该位由硬件清零。该位还可由软件清零。
0:日历影子寄存器尚未同步
1:日历影子寄存器已同步
RTC 预分频器寄存器 (RTC_PRER)
位 22:16 PREDIV_A[6:0]:异步预分频系数 (Asynchronous prescaler factor)
下面是异步分频系数的公式:
ck_apre 频率 = RTCCLK 频率/(PREDIV_A+1)
注意: PREDIV_A [6:0]= 000000 为禁用值。
位 15 保留,必须保持复位值。
位 14:0 PREDIV_S[14:0]:同步预分频系数 (Synchronous prescaler factor)
下面是同步分频系数的公式:
ck_spre 频率 = ck_apre 频率/(PREDIV_S+1)
RTC 写保护寄存器 (RTC_WPR)
位 7:0 KEY:写保护关键字 (Write protection key)
可通过软件对该字节执行写操作。
读取该字节时,始终返回 0x00。
有关如何解锁 RTC 寄存器写保护的介绍,请参见RTC 寄存器写保护。


五、RTC自动唤醒功能
通过设定一个时间周期,当时间到了的时候,就会产生一些标志/中断,通过IO口将当前标志输出出去,产生外部中断。一般自动唤醒都是设定一秒产生一次中断,在中断中获取RTC时间/日期。
1、RTC自动唤醒功能相关寄存器
RTC 控制寄存器 (RTC_CR)
位 14 WUTIE:使能唤醒定时器使能 (Wakeup timer interrupt enable)
0:禁止唤醒定时器中断
1:使能唤醒定时器中断位 10 WUTE:唤醒定时器使能 (Wakeup timer enable)
0:禁止唤醒定时器
1:使能唤醒定时器位 2:0 WUCKSEL[2:0]:唤醒时钟选择 (Wakeup clock selection)
000:选择 RTC/16 时钟
001:选择 RTC/8 时钟
010:选择 RTC/4 时钟
011:选择 RTC/2 时钟
10x:选择 ck_spre 时钟(通常为 1 Hz)
11x:选择 ck_spre 时钟(通常为 1 Hz)并将 WUT 计数器值增加 216(见下面的注释)
RTC 初始化和状态寄存器 (RTC_ISR)
位 10 WUTF:唤醒定时器标志 (Wakeup timer flag)
当唤醒自动重载计数器计数到 0 时,由硬件将此标志置 1。
该标志由软件写零清除。
软件必须在 WUTF 再次置 1 的 1.5 个 RTCCLK 周期之前将该标志清零。位2 WUTWF:唤醒定时器写标志 (Wakeup timer write flag)
在 RTC_CR 寄存器中的 WUTE 位置 0 后,当唤醒定时器值可更改时,由硬件将该位置 1。
0:不允许更新唤醒定时器配置
1:允许更新唤醒定时器配置
RTC 唤醒定时器寄存器 (RTC_WUTR)
六、RTC闹钟功能
1、RTC闹钟功能框图分析

2、RTC闹钟功能相关寄存器
RTC 控制寄存器 (RTC_CR)
位 13 ALRBIE: 闹钟 B 中断使能 (Alarm B interrupt enable)
0:闹钟 B 中断禁止
1:闹钟 B 中断使能
位 12 ALRAIE:闹钟 A 中断使能 (Alarm A interrupt enable)
0:禁止闹钟 A 中断
1:使能闹钟 A 中断位 9 ALRBE: 闹钟 B 使能 (Alarm B enable)
0:禁止闹钟 B
1:使能闹钟 B位 8 ALRAE: 闹钟 A 使能 (Alarm A enable)
0:禁止闹钟 A
1:使能闹钟 A
RTC 初始化和状态寄存器 (RTC_ISR)
位 9 ALRBF:闹钟 B 标志 (Alarm B flag)
当时间/日期寄存器(RTC_TR 和 RTC_DR)与闹钟 B 寄存器 (RTC_ALRMBR) 匹配时,由
硬件将该标志置 1。
该标志由软件写零清除。
位 8 ALRAF:闹钟 A 标志 (Alarm A flag)
当时间/日期寄存器(RTC_TR 和 RTC_DR)与闹钟 A 寄存器 (RTC_ALRMAR) 匹配时,由
硬件将该标志置 1。
该标志由软件写零清除。位 1 ALRBWF:闹钟 B 写标志 (Alarm B write flag)
在 RTC_CR 寄存器中的 ALRBIE 位置 0 之后,当闹钟 B 的值可更改时,由硬件将该位置 1。
该位在初始化模式下由硬件清零。
0:不允许更新闹钟 B
1:允许更新闹钟 B
位 0 ALRAWF:闹钟 A 写标志 (Alarm A write flag)
在 RTC_CR 寄存器中的 ALRAE 位置 0 后,当闹钟 A 的值可更改时,由硬件将该位置 1。
该位在初始化模式下由硬件清零。
0:不允许更新闹钟 A
1:允许更新闹钟 A
RTC 闹钟 A 寄存器 (RTC_ALRMAR)
RTC 闹钟 B 寄存器 (RTC_ALRMBR)
RTC基本日历功能
软件设计
1. 打开PWR的时钟
2. 选择PWR寄存器中的CR寄存器的DBP 位置 1
3. 选择时钟源
4.开启相应的时钟源
5.判断开启成功没有
6. 选择相应的时钟源到RTC里
7.使能RTC的时钟
8.解除写保护
将“0xCA”写入 RTC_WPR 寄存器。
将“0x53”写入 RTC_WPR 寄存器。
9.将 RTC_ISR 寄存器中的 INIT 位置 1 以进入初始化模式。在此模式下,日历计数器将停止工作并且其值可更新。
10.轮询 RTC_ISR 寄存器中的 INITF 位。当 INITF 置 1 时进入初始化阶段模式。大约需要2 个 RTCCLK 时钟周期(由于时钟同步)。
11. 要为日历计数器生成 1 Hz 时钟,应首先编程 RTC_PRER 寄存器中的同步预分频系数,然后编程异步分频系数。即使只需要更改这两个字段中之一,也必须对 RTC_PRER寄存器执行两次单独的写访问。
12.在影子寄存器( RTC_TR 和 RTC_DR)中加载初始时间和日期值,然后通过 RTC_CR寄存器中的 FMT 位配置时间格式( 12 或 24 小时制)。
13.通过清零 INIT 位退出初始化模式。随后,自动加载实际日历计数器值,在 4 个 RTCCLK时钟周期后重新开始计数。
当初始化序列完成之后,日历开始计数。
14.读取相应的时间出来
#include "rtc.h"const char *pt = __TIME__;
const char *pd = __DATE__;
TIME_DATA time_data;
u8 month[12][5] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
/***********************************************************
函数功能:判断闰年函数
函数形参:年
函数返回值:0平年 1闰年
************************************************************/
u8 Pd_Rn(u16 year)
{if( (year%4==0 && year%100!= 0) || (year%400 == 0) ){return 1;}return 0;
}/***********************************************************
函数功能:1990年1月1日到今天的天数函数
函数形参:年 月 日
函数返回值:星期几
************************************************************/
u8 Statistics_Days(u16 year, u8 mon, u8 day)
{u32 buf = 0;//存储天数u16 i;//0-66535u8 week = 0;for(i = 1990; i < year; i++){if( Pd_Rn(i) ){buf += 366;}else{buf += 365;}}switch(mon)//7{case 12: buf += 30; case 11: buf += 31; case 10: buf += 30; case 9: buf += 31; case 8: buf += 31; case 7: buf += 30; case 6: buf += 31; case 5: buf += 30; case 4: buf += 31; case 3: buf += 28; buf += Pd_Rn(year); case 2: buf += 31; case 1: buf += 0; }//统计从这个1日 到 今天的天数buf += day;//1990年1月1日 到 今天的天数switch(buf % 7){case 1: week = 1; break;case 2: week = 2; break;case 3: week = 3; break;case 4: week = 4; break;case 5: week = 5; break;case 6: week = 6; break;case 0: week = 7; break;}return week;//将星期几返回出去了
}//设置时间
ErrorStatus RTC_Set_Time(void)
{/*****************解析时间**********************/time_data.hour = (pt[0]-'0')*10 + (pt[1]-'0');//、得到小时time_data.minute = (pt[3]-'0')*10 + (pt[4]-'0');//得到分钟time_data.second = (pt[6]-'0')*10 + (pt[7]-'0');//得到秒RTC_TimeTypeDef RTC_TimeTypeInitStructure;RTC_TimeTypeInitStructure.RTC_Hours = time_data.hour;RTC_TimeTypeInitStructure.RTC_Minutes = time_data.minute;RTC_TimeTypeInitStructure.RTC_Seconds = time_data.second;RTC_TimeTypeInitStructure.RTC_H12 = RTC_H12_AM;return RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
}//设置日期
ErrorStatus RTC_Setime_dataate()
{u8 str[4] = {0};u8 i;/*****************解析日期**********************/for(i = 0; i < 3; i++){str[i] = pd[i];//May}str[i] = '\0';for(i = 0; i < 12; i++){if(strcmp((char *)str, (char *)month[i]) == 0 ){i += 1;break;//找到月份了}}time_data.month = i;//得到月if( pd[4] == ' ' ){time_data.day = pd[5]-'0';//得到日}else{time_data.day = (pd[4]-'0')*10 + (pd[5]-'0');//得到日}time_data.year = (pd[9]-'0')*10 + (pd[10]-'0');//得到年/*****************解析星期**********************/time_data.week = Statistics_Days(time_data.year+2000, time_data.month, time_data.day);//得到星期几RTC_DateTypeDef RTC_DateTypeInitStructure;RTC_DateTypeInitStructure.RTC_Year = time_data.year;RTC_DateTypeInitStructure.RTC_Month = time_data.month;RTC_DateTypeInitStructure.RTC_Date = time_data.day;RTC_DateTypeInitStructure.RTC_WeekDay = time_data.week;return RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
}/************************
函数功能:RTC初始化
形参:无
返回值:成功返回0,失败返回1
说明:24小时制
************************/
u8 My_Rtc_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能PWR时钟PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 RTC_WriteProtectionCmd(DISABLE); u16 retry= 0; //RCC_LSEConfig(RCC_LSE_ON);//LSE 开启 RCC_LSICmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪{retry++;delay_ms(10);if(retry == 200){ return 1; //LSE 开启失败. }}RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟 RCC_RTCCLKCmd(ENABLE); //使能RTC时钟 RTC_InitTypeDef RTC_InitStructure;RTC_InitStructure.RTC_AsynchPrediv = 0x7F;//RTC异步分频系数(1~0X7F)RTC_InitStructure.RTC_SynchPrediv = 0xF9;//RTC同步分频系数(0~7FFF)RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;//RTC设置为,24小时格式RTC_Init(&RTC_InitStructure);if(RTC_ReadBackupRegister(RTC_BKP_DR1) != 0xbbbb){RTC_Set_Time(); //设置时间RTC_Setime_dataate(); //设置日期RTC_WriteBackupRegister(RTC_BKP_DR1, 0xbbbb); }return 0;
}//RTC唤醒功能初始化
void Rtc_Wakeup_Init(void)
{EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line22;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_Init(&EXTI_InitStructure);//配置RTC_WakeUpCmd(DISABLE);//关闭WAKE UPRTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);//唤醒时钟选择RTC_SetWakeUpCounter(0);//设置WAKE UP自动重装载寄存器RTC_ClearITPendingBit(RTC_IT_WUT); //清除RTC WAKE UP的标志EXTI_ClearITPendingBit(EXTI_Line22);//清除LINE22上的中断标志位RTC_ITConfig(RTC_IT_WUT,ENABLE);//开启WAKE UP 定时器中断//设置中断NVIC_SetPriority(RTC_WKUP_IRQn,NVIC_EncodePriority(7-2,1,1));NVIC_EnableIRQ(RTC_WKUP_IRQn);RTC_WakeUpCmd(ENABLE);//开启WAKE UP 定时器
}//WAKE UP中断函数
void RTC_WKUP_IRQHandler(void)
{u8 data[256];u8 time[256];RTC_TimeTypeDef RTC_TimeStruct;RTC_DateTypeDef RTC_DateStruct;RTC_ClearFlag(RTC_FLAG_WUTF); //清除中断标志EXTI_ClearITPendingBit(EXTI_Line22);//清除中断线22的中断标志 RTC_GetTime(RTC_Format_BIN,&RTC_TimeStruct);RTC_GetDate(RTC_Format_BIN,&RTC_DateStruct);sprintf((char*)data,"20%02d-%02d-%02d-%01d",RTC_DateStruct.RTC_Year,RTC_DateStruct.RTC_Month,RTC_DateStruct.RTC_Date,RTC_DateStruct.RTC_WeekDay);sprintf((char*)time,"%02d:%02d:%02d",RTC_TimeStruct.RTC_Hours,RTC_TimeStruct.RTC_Minutes,RTC_TimeStruct.RTC_Seconds);
}//RTC闹钟功能初始化,周几的闹钟
void Rtc_Alarm(u8 week,u8 hour, u8 minute, u8 second)
{EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line17;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_Init(&EXTI_InitStructure);//配置外部中断线RTC_AlarmTypeDef RTC_AlarmAStruct;RTC_AlarmCmd(RTC_Alarm_A,DISABLE); //先关闭闹钟ARTC_TimeTypeDef RTC_TimeTypeInitStructure;RTC_TimeTypeInitStructure.RTC_Hours = hour;RTC_TimeTypeInitStructure.RTC_Minutes = minute;RTC_TimeTypeInitStructure.RTC_Seconds = second;RTC_TimeTypeInitStructure.RTC_H12 = RTC_H12_AM;RTC_AlarmAStruct.RTC_AlarmDateWeekDay = week;RTC_AlarmAStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay;//按星期闹钟RTC_AlarmAStruct.RTC_AlarmMask = RTC_AlarmMask_None;//不屏蔽 RTC_AlarmAStruct.RTC_AlarmTime = RTC_TimeTypeInitStructure; RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmAStruct);//设置中断NVIC_SetPriority(RTC_Alarm_IRQn,NVIC_EncodePriority(7-2,1,1));NVIC_EnableIRQ(RTC_Alarm_IRQn); //使能闹钟A的中断RTC_ITConfig(RTC_IT_ALRA,ENABLE); //开启闹钟ARTC_AlarmCmd(RTC_Alarm_A,ENABLE); }//闹钟A中断服务函数
void RTC_Alarm_IRQHandler()
{//判断中断是否发生if(RTC_GetITStatus(RTC_IT_ALRA)==SET){RTC_ClearITPendingBit(RTC_IT_ALRA);//清中断标志位}EXTI_ClearITPendingBit(EXTI_Line17);
} TIME_DATA dateAndTime;//获取当前时间
TIME_DATA *RTC_getDateAndTime(void)
{RTC_DateTypeDef RTC_Date;//定义结构体,用于保存获取的日期和时间RTC_TimeTypeDef RTC_Time;RTC_GetDate(RTC_Format_BIN,&RTC_Date);RTC_GetTime(RTC_Format_BIN,&RTC_Time); dateAndTime.year = RTC_Date.RTC_Year;dateAndTime.month = RTC_Date.RTC_Month;dateAndTime.day = RTC_Date.RTC_Date;dateAndTime.week = RTC_Date.RTC_WeekDay;dateAndTime.hour = RTC_Time.RTC_Hours;dateAndTime.minute = RTC_Time.RTC_Minutes;dateAndTime.second = RTC_Time.RTC_Seconds;dateAndTime.ampm = RTC_Time.RTC_H12;return &dateAndTime;
}
#ifndef RTC_H_
#define RTC_H_
#include "stm32f4xx.h"
#include "stdio.h"
#include "string.h"
typedef struct
{u8 hour;u8 minute;u8 second;u8 year;u8 month;u8 day;u8 week;u8 ampm;
}TIME_DATA;typedef struct
{u8 twentyMsCount;u8 hour;u8 minute;u8 second;
}timeStamp_t;u8 My_Rtc_Init(void);
void Rtc_Wakeup_Init(void);
void Rtc_Alarm(u8 week,u8 hour, u8 minute, u8 second);
TIME_DATA *RTC_getDateAndTime(void);
#endif
相关文章:
STM32之RTC实时时钟
一、实时时钟概述 1、实时时钟介绍 英文缩写:RTC。显示年、月、日、时、分、秒、星期,自动计算闰年,能够区分每个月的天数。 RTC特点:能从RTC获取到具体的日期时间,断掉后再开机时间仍然准确(需要纽扣电池ÿ…...
Java JVM 堆、栈、方法区详解
目录 1. 栈 2. 堆 3. 方法区 4. 本地方法栈 5. 程序计数器 首先来看一下JVM运行时数据区有哪些。 1. 栈 在介绍JVM栈之前,先了解一下 栈帧 概念。 栈帧:一个栈帧随着一个方法的调用开始而创建,这个方法调用完成而销毁。栈帧内存放者方…...
Oracle篇—分区表和分区索引的介绍和分类(第一篇,总共五篇)
☘️博主介绍☘️: ✨又是一天没白过,我是奈斯,DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux,也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章,并且也会默默的点赞收藏加关注❣…...
Vue中的模式和环境变量
文章目录 一、介绍二、配置1、环境文件2、变量使用 三、读取环境文件 一、介绍 vue官网:https://cli.vuejs.org/zh/guide/mode-and-env.html模式是 Vue CLI 项目中一个重要的概念。默认情况下,一个 Vue CLI 项目有三个模式 开发环境:develop…...
用ChatGPT教学、科研!亚利桑那州立大学与OpenAI合作
亚利桑那州立大学(简称“ASU”)在官网宣布与OpenAI达成技术合作。从2024年2月份开始,为所有学生提供ChatGPT企业版访问权限,主要用于学习、课程作业和学术研究等。 为了帮助学生更好地学习ChatGPT和大语言模型产品,AS…...
问题解决:django模型查询报错,找不到数据库表
django项目,使用的postgresql数据库,建了多个模式,模型查询时一直默认查public的表 1. 问题: django.db.utils.ProgrammingError: relation "ip_management_app.table" does not exist 2. 代码: class …...
持续集成工具Jenkins的使用之安装篇(一)
Jenkins是一个基于Java开发的开源的一种持续集成工具,主要用于环境部署,监控重复性的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成。要想使用它,你就必须的先安装,接下来我们就介绍下J…...
【JavaScript】面向后端快速学习 笔记
文章目录 JS是什么?一、JS导入二、数据类型 变量 运算符三、流程控制四、函数五、对象 与 JSON5.1 对象5.2 JSON5.3 常见对象1. 数组2. Boolean对象3. Date对象4. Math5. Number6. String 六、事件6.1 常用方法1. 鼠标事件2. 键盘事件3. 表单事件 6.2 事件的绑定**1…...
笨蛋学设计模式行为型模式-命令模式【19】
行为型模式-命令模式 8.6命令模式8.6.1概念8.6.2场景8.6.3优势 / 劣势8.6.4命令模式可分为8.6.5命令模式8.6.6实战8.6.6.1题目描述8.6.6.2输入描述8.6.6.3输出描述8.6.6.4代码 8.6.7总结 8.6命令模式 8.6.1概念 命令模式允许将请求封装成一个对象(命令对象,包含…...
windows用msvc编译opencv、opencv-python、opencv_contrib、cuda
如要用mingw编译opencv,参考我另外一篇文章https://blog.csdn.net/weixin_44733606/article/details/135741806。 如要用Ubuntu编译opencv,参考我另外一篇文章https://blog.csdn.net/weixin_44733606/article/details/131720128。 一、安装VS2022&…...
JVM实战篇:GC调优
目录 一.GC调优的核心指标 1.1吞吐量(Throughput) 1.2延迟(Latency) 1.3内存使用量 二.GC调优的方法 2.1监控工具 Jstat工具 VisualVm插件 Prometheus Grafana 2.2诊断原因 GC日志 GC Viewer GCeasy 2.3常见的GC模…...
C# 获取QQ会话聊天信息
目录 利用UIAutomation获取QQ会话聊天信息 效果 代码 目前遇到一个问题 其他解决办法 利用UIAutomation获取QQ会话聊天信息 效果 代码 AutomationElement window AutomationElement.FromHandle(get.WindowHwnd); AutomationElement QQMsgList window.FindFirst(Tr…...
Java中的内存溢出与内存泄漏深度解析
目录 引言 一. 内存溢出(Memory Overflow) 1.1 堆内存溢出 1.2 栈内存溢出 1.3 内存溢出的解决策略 1.3.1 优化对象的创建和销毁 1.3.2 调整堆内存大小 1.3.3 使用内存分析工具 1.3.4 避免创建过大的对象 1.3.5 定期清理不再使用的对象 二、…...
计算机网络安全——密码学入门
网络安全是指在网络领域、专业领域的网络安全包括在基础计算机网络基础设施中所做的规定,网络管理员采取的策略来保护网络及网络可访问资源免受未经授权的访问,以及对其有效性(或缺乏)的持续不断的监控和测量的结合。 1. 密码学的…...
go语言(八)---- map
map的声明方式有以下三种。 package mainimport "fmt"func main() {//第一种声明方式//声明map1是一个map类型,key是String,value是Stringvar myMap1 map[string] stringif myMap1 nil {fmt.Println("myMap1 是一个空map")}//在使…...
Flutter:跨平台移动应用开发的未来
Flutter:跨平台移动应用开发的未来 引言 Flutter的背景和概述 Flutter是由Google开发的一个开源UI工具包,用于构建漂亮、快速且高度可定制的移动应用程序。它于2017年首次发布,并迅速引起了开发者们的关注。Flutter采用了一种全新的方法来…...
二维码地址门牌管理系统:智慧城市新篇章
文章目录 前言一、轮播广告位:全面信息传达二、智能化管理:应对挑战三、安全保障:市民隐私优先四、广泛应用:助力城市建设 前言 随着科技的飞速发展,城市的智能化已成不可逆转的趋势。二维码地址门牌管理系统作为新一…...
学习JavaEE的日子 day14 继承,super(),this(),重写
Day14 1.继承的使用 理解:子类继承父类所有的属性和方法 使用场景:多个类似的类,有相同的属性和方法,就可以把相同属性和方法抽取到父类 优点:减少代码的冗余; 使类与类之间产生了关系(多态的前提) 缺点&a…...
一文梳理Windows自启动位置
不同版本的Windows开机自启动的位置略有出入,一般来说,Windows自启动的位置有:自启动文件夹、注册表子键、自动批处理文件、系统配置文件等。如果计算机感染了木马,很有可能就潜伏于其中!本文将说明这些常见的Windows开…...
【Java 设计模式】行为型之策略模式
文章目录 1. 定义2. 应用场景3. 代码实现结语 策略模式(Strategy Pattern)是一种行为型设计模式,定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式允许客户端在运行时选择算法的具体实现ÿ…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...













