当前位置: 首页 > news >正文

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、实时时钟介绍 英文缩写&#xff1a;RTC。显示年、月、日、时、分、秒、星期,自动计算闰年&#xff0c;能够区分每个月的天数。 RTC特点&#xff1a;能从RTC获取到具体的日期时间&#xff0c;断掉后再开机时间仍然准确&#xff08;需要纽扣电池&#xff…...

Java JVM 堆、栈、方法区详解

目录 1. 栈 2. 堆 3. 方法区 4. 本地方法栈 5. 程序计数器 首先来看一下JVM运行时数据区有哪些。 1. 栈 在介绍JVM栈之前&#xff0c;先了解一下 栈帧 概念。 栈帧&#xff1a;一个栈帧随着一个方法的调用开始而创建&#xff0c;这个方法调用完成而销毁。栈帧内存放者方…...

Oracle篇—分区表和分区索引的介绍和分类(第一篇,总共五篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…...

Vue中的模式和环境变量

文章目录 一、介绍二、配置1、环境文件2、变量使用 三、读取环境文件 一、介绍 vue官网&#xff1a;https://cli.vuejs.org/zh/guide/mode-and-env.html模式是 Vue CLI 项目中一个重要的概念。默认情况下&#xff0c;一个 Vue CLI 项目有三个模式 开发环境&#xff1a;develop…...

用ChatGPT教学、科研!亚利桑那州立大学与OpenAI合作

亚利桑那州立大学&#xff08;简称“ASU”&#xff09;在官网宣布与OpenAI达成技术合作。从2024年2月份开始&#xff0c;为所有学生提供ChatGPT企业版访问权限&#xff0c;主要用于学习、课程作业和学术研究等。 为了帮助学生更好地学习ChatGPT和大语言模型产品&#xff0c;AS…...

问题解决:django模型查询报错,找不到数据库表

django项目&#xff0c;使用的postgresql数据库&#xff0c;建了多个模式&#xff0c;模型查询时一直默认查public的表 1. 问题&#xff1a; django.db.utils.ProgrammingError: relation "ip_management_app.table" does not exist 2. 代码&#xff1a; class …...

持续集成工具Jenkins的使用之安装篇(一)

Jenkins是一个基于Java开发的开源的一种持续集成工具&#xff0c;主要用于环境部署&#xff0c;监控重复性的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成。要想使用它&#xff0c;你就必须的先安装&#xff0c;接下来我们就介绍下J…...

【JavaScript】面向后端快速学习 笔记

文章目录 JS是什么&#xff1f;一、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概念 ​ 命令模式允许将请求封装成一个对象(命令对象&#xff0c;包含…...

windows用msvc编译opencv、opencv-python、opencv_contrib、cuda

如要用mingw编译opencv&#xff0c;参考我另外一篇文章https://blog.csdn.net/weixin_44733606/article/details/135741806。 如要用Ubuntu编译opencv&#xff0c;参考我另外一篇文章https://blog.csdn.net/weixin_44733606/article/details/131720128。 一、安装VS2022&…...

JVM实战篇:GC调优

目录 一.GC调优的核心指标 1.1吞吐量&#xff08;Throughput&#xff09; 1.2延迟&#xff08;Latency&#xff09; 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中的内存溢出与内存泄漏深度解析

目录 引言 一. 内存溢出&#xff08;Memory Overflow&#xff09; 1.1 堆内存溢出 1.2 栈内存溢出 1.3 内存溢出的解决策略 1.3.1 优化对象的创建和销毁 1.3.2 调整堆内存大小 1.3.3 使用内存分析工具 1.3.4 避免创建过大的对象 1.3.5 定期清理不再使用的对象 二、…...

计算机网络安全——密码学入门

网络安全是指在网络领域、专业领域的网络安全包括在基础计算机网络基础设施中所做的规定&#xff0c;网络管理员采取的策略来保护网络及网络可访问资源免受未经授权的访问&#xff0c;以及对其有效性&#xff08;或缺乏&#xff09;的持续不断的监控和测量的结合。 1. 密码学的…...

go语言(八)---- map

map的声明方式有以下三种。 package mainimport "fmt"func main() {//第一种声明方式//声明map1是一个map类型&#xff0c;key是String&#xff0c;value是Stringvar myMap1 map[string] stringif myMap1 nil {fmt.Println("myMap1 是一个空map")}//在使…...

Flutter:跨平台移动应用开发的未来

Flutter&#xff1a;跨平台移动应用开发的未来 引言 Flutter的背景和概述 Flutter是由Google开发的一个开源UI工具包&#xff0c;用于构建漂亮、快速且高度可定制的移动应用程序。它于2017年首次发布&#xff0c;并迅速引起了开发者们的关注。Flutter采用了一种全新的方法来…...

二维码地址门牌管理系统:智慧城市新篇章

文章目录 前言一、轮播广告位&#xff1a;全面信息传达二、智能化管理&#xff1a;应对挑战三、安全保障&#xff1a;市民隐私优先四、广泛应用&#xff1a;助力城市建设 前言 随着科技的飞速发展&#xff0c;城市的智能化已成不可逆转的趋势。二维码地址门牌管理系统作为新一…...

学习JavaEE的日子 day14 继承,super(),this(),重写

Day14 1.继承的使用 理解&#xff1a;子类继承父类所有的属性和方法 使用场景&#xff1a;多个类似的类&#xff0c;有相同的属性和方法&#xff0c;就可以把相同属性和方法抽取到父类 优点&#xff1a;减少代码的冗余&#xff1b; 使类与类之间产生了关系(多态的前提) 缺点&a…...

一文梳理Windows自启动位置

不同版本的Windows开机自启动的位置略有出入&#xff0c;一般来说&#xff0c;Windows自启动的位置有&#xff1a;自启动文件夹、注册表子键、自动批处理文件、系统配置文件等。如果计算机感染了木马&#xff0c;很有可能就潜伏于其中&#xff01;本文将说明这些常见的Windows开…...

【Java 设计模式】行为型之策略模式

文章目录 1. 定义2. 应用场景3. 代码实现结语 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以互相替换。策略模式允许客户端在运行时选择算法的具体实现&#xff…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

Linux安全加固:从攻防视角构建系统免疫

Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...