RTC学习笔记
全文为 STM32F1 的 RTC 读写学习笔记,这与 F4 与 F7 的存在一定的差异(印象记得是这样的)。
学习笔记
RTC 源码就不放进图片了,上传不了,直接贴出来
rtc.h 文件
#ifndef __RTC_H
#define __RTC_H
#include "sys.h"
#include "delay.h"
#define RTC_NVIC_ENABLE 0
typedef struct time_tpyedef { //时间结构体
u16 year; //年
u8 mouth; //月
u8 day; //日
u8 hour; //时
u8 minute; //分
u8 second; //秒
} rtc_time;
extern rtc_time timer;
u8 rtc_init(void); //RTC初始化函数,通过返回值判断是否初始化成功
void set_time(u16 yy, u8 mm, u8 dd, u8 h, u8 m, u8 s, u8 bkpCmd);
void get_time(void);
#endif //__RTC_H
rtc.c 文件
#include "rtc.h"
rtc_time timer = {0}; //用于存放
u16 temp_yy_base = 1970; //现代计算机飞速发展始于 1971 年,将年代基数设为 1970
u8 mday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
extern NVIC_InitTypeDef NVIC_Initure;
u8 rtc_init() {
u8 temp = 0; //用于判断外部低速时钟开启是否超时
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器的访问
RCC_LSICmd(ENABLE); //防止内部低速时钟 LSI 不稳定,程序卡死,重新使能内部低速时钟 LSI
while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY)); //等待内部低速时钟 LSI 重启完成
if(BKP_ReadBackupRegister(BKP_DR1) != 0x2944) { //从指定的后备寄存器中读出数据
BKP_DeInit(); //重置后备区域
RCC_LSEConfig(RCC_LSE_ON); //开启 LSE 外部低速时钟 32.767K
while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY) && temp ++ > 200) {
delay_ms(10); //以 10ms 为间隔计算外部低速时钟是否开启
}
if(temp > 200) //判断外部低速时钟是否超时,超时则返回 0,否则继续执行后续代码
return 0;
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //将外部低速时钟配置为 RTC 的时钟源
RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟源
RTC_WaitForLastTask(); //等待上一次 RTC 的写操作完成
RTC_WaitForSynchro(); //等待 RTC 时钟与外部低速时钟同步
#if RTC_NVIC_ENABLE
RTC_ITConfig(RTC_IT_SEC, ENABLE); //开启秒中断
RTC_WaitForLastTask(); //等待上一次 RTC 的写操作完成
#endif
RTC_EnterConfigMode(); //允许配置 RTC 时钟
RTC_SetPrescaler(32767);//设置 RTC 的预分频系数
RTC_WaitForLastTask(); //等待上一次 RTC 的写操作完成
set_time(2021, 4, 5, 15, 00, 00, 0); //配置 RTC 时钟
RTC_ExitConfigMode(); //禁止配置 RTC 时钟
BKP_WriteBackupRegister(BKP_DR1, 0x2944); //向指定的后备寄存器中写入用户程序数据
}
else {
RTC_WaitForSynchro(); //等待 RTC 时钟与外部低速时钟同步
#if RTC_NVIC_ENABLE
RTC_ITConfig(RTC_IT_SEC, ENABLE); //开启秒中断
RTC_WaitForLastTask(); //等待上一次 RTC 的写操作完成
#endif
}
#if RTC_NVIC_ENABLE
NVIC_Initure.NVIC_IRQChannel = RTC_IRQn;
NVIC_Initure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Initure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_Initure);
#endif
return 1;
}
void set_time(u16 yy, u8 mm, u8 dd, u8 h, u8 m, u8 s, u8 bkpCmd) {
if(yy < 1970 || yy >2100 || (yy % 4 == 0 && dd == 29)) {
printf("时间设置失败,请检查时间格式或时间年限!\r\n");
return;
}
u32 counter = 0; //总计秒数初始化,若存在误差,此处 counter 值为误差值
u8 temp_yy_run = ((yy - temp_yy_base) % 4 == 0 && mm < 3) ? (yy - temp_yy_base) / 4 - 1 :(yy - temp_yy_base) / 4; //获取闰年数
counter += ((yy - temp_yy_base) * 365 + temp_yy_run); //将年数转换为天数,并记入 counter
for(u8 i = 0; i < mm - 1; i ++) { //将月数转换为天数,并记入 counter
counter += mday[i];
}
counter += dd; //将天数记入 counter
counter *= 86400; //86400 = 24 * 60 * 60 将天数转换为秒数
counter += h * 3600 + m * 60 + s; //将时分秒记入总秒数 counter
if(bkpCmd == 1) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器的访问
}
RTC_SetCounter(counter);//将总秒数写入 RTC 的计数器
RTC_WaitForLastTask(); //等待上一次 RTC 的写操作完成
}
void get_time() {
int temp;
u16 temp_dd;
u8 i = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器的访问
u32 counter = RTC_GetCounter(); //读出 RTC 的计数器的总计秒数
RTC_WaitForLastTask(); //等待上一次 RTC 的写操作完成
temp_dd = (int)(counter / 86400); //将秒数转换为天数
temp = (int)(temp_dd % 1461 < 61 ? temp_dd / 1461 - 1 : temp_dd / 1461); //1461 = 365 * 3 + 366
timer.year = temp * 4 + temp_yy_base + (int)(temp_dd % 1461 < 367 ? 0 : (temp_dd % 1461 - 366) / 365 + 1);
temp = temp_dd % 1461 < 367 ? temp_dd % 1461 : (temp_dd % 1461 - 1) % 365;
mday[1] = temp_dd % 1461 < 367 ? 29 : 28; //如果是润年,临时将 2 月天数调为 29
while(temp > 0) {
temp -= mday[i ++];
}
timer.mouth = i;
temp += mday[i];
timer.day = temp;
mday[1] = 28; //将 2 月天数还原为默认值 28 天
temp = counter % 86400; //获取不满一天的秒数
timer.hour = temp / 3600;
temp %= 3600;
timer.minute = temp /60;
temp %= 60;
timer.second = temp;
printf("当前时间:%d-%d-%d %d:%d:%d\r\n", timer.year, timer.mouth, timer.day, timer.hour, timer.minute, timer.second);
}
void RTC_IRQHandler() {
if(RTC_GetITStatus(RTC_IT_SEC)) {
//get_time();
}
}
试验效果图
实验源码:STM32F103_RTC
内存对比:
学习分享,一起成长!以上为小编的学习分享,若存在不当之处,请批评指正!