STM32入门:RTC学习笔记(内附主要源代码)

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
内存对比:
在这里插入图片描述

学习分享,一起成长!以上为小编的学习分享,若存在不当之处,请批评指正!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是混子我怕谁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值