STM32读写RTC内部时钟外设,设置和显示时钟

今天学习了STM32单片机的内部时钟外设,学会了更改内部时钟和提取时钟数值的操作,只要后备电池有电,该时钟就会一直走,时间不会复位,哪怕没有给单片机供电。好了,直接记录步骤吧:

首先初始化流程,和BKP一样,在使用RTC外设之前,同样得执行注意事项的的第一点:

第一步:开启PWR和BKP的时钟,使能PWR和BKP的访问

如果读后备寄存器不是写入的值(证明包括电池断过电)需要重写时间

第二步:启动RTC的时钟,使用RCC模块里的RCC_LSEConfig函数,开启LSE的时 钟。LSE 需要手动开启,不然用不了。

第三步:配置RTCCLK数据选择器,指定LSE为RTCCLK(这个函数也在RCC模块里面)

第四步:调用等待的函数(RTC模块里等待同步,等待上一次操作完成)

第五步:配置预分频器(RTC里给PRL重装寄存器一个分频值,确保输出频率是1Hz)

第六步:配置CNT的值(给RTC一个初始时间)需要闹钟的话,配置个闹钟;需要中断的 话, 配置中断。

否则是不需要重新写时间的:

第四步:调用等待的函数(等待同步,等待上一次操作完成)

写两个函数:

一个是设置时间,

一个是读取时间。

设置时间的函数:

声明存放时间戳的变量time_CNT

创建时间结构体的变量time_data

第一步:把我们数组指定的时间,填充到struct tm结构体里

向结构体赋值年份 减去偏移

向结构体赋值月份 减去偏移

向结构体赋值日份

向结构体赋值小时

向结构体赋值分钟

向结构体赋值秒钟

第二步:把结构体中的时间转换成时间戳

把结构体中的时间转换成时间戳

第三步:把时间戳写入到RTC中当做初始时间

把时间戳写入到RTC中当做初始时间

等待写入操作完成

读取时间的函数:

声明存放时间戳的变量time_CNT

创建时间结构体的变量time_data

第一步:读取时间戳放到时间戳变量中

第二步:把时间戳转换成时间,存放到结构体中

第三步:把结构体中的时间存放到我们指定的全局变量数组中。

取结构体赋值年份 +偏移

取结构体赋值月份 +偏移

取结构体赋值日份

取结构体赋值小时

取结构体赋值分钟

取结构体赋值秒钟

好了,写的我都有点恶心了,还是直接看源文件吧:

MyRTC.c:

cs 复制代码
#include "stm32f10x.h"                  // Device header
#include "MyRTC.h"   
#include <time.h>

uint16_t MyRTC_Time[] = {2024, 4, 24, 9, 33, 59};  //存储时间的数组


/*
首先初始化流程,和BKP一样,在使用RTC外设之前,同样得执行注意事项的的第一点:
第一步:开启PWR和BKP的时钟,使能PWR和BKP的访问
第二步:启动RTC的时钟,使用RCC模块里的RCC_LSEConfig函数,开启LSE的时钟。LSE需要手动开启,不然用不了。
第三步:配置RTCCLK数据选择器,指定LSE为RTCCLK(这个函数也在RCC模块里面)
第四步:调用等待的函数(RTC模块里等待同步,等待上一次操作完成)
第五步:配置预分频器(RTC里给PRL重装寄存器一个分频值,确保输出频率是1Hz)
第六步:配置CNT的值(给RTC一个初始时间)需要闹钟的话,配置个闹钟;需要中断的话,配置中断。
*/

void MyRTC_Init(void)
{
	//第一步:开启PWR和BKP的时钟,使能PWR和BKP的访问
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	
	if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)  //如果读后备寄存器不是写入的值(证明包括电池断过电)需要重写时间
	{
		//第二步:启动RTC的时钟,使用RCC模块里的RCC_LSEConfig函数,开启LSE的时钟。LSE需要手动开启,不然用不了。
		RCC_LSEConfig(RCC_LSE_ON);
		//等待LSE时钟启动完成
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		//第三步:配置RTCCLK数据选择器,指定LSE为RTCCLK(这个函数也在RCC模块里面)
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);   // 使能LSE的时钟
		
		//第四步:调用等待的函数(等待同步,等待上一次操作完成)
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		//第五步:配置预分频器(RTC里给PRL重装寄存器一个分频值,确保输出频率是1Hz)
		RTC_SetPrescaler(32768 - 1);  // 32768Hz除以32768正好等于1
		RTC_WaitForLastTask();  //等待写入操作完成
		
		//第六步:配置CNT的值(给RTC一个初始时间)需要闹钟的话,配置个闹钟;需要中断的话,配置中断。
		//下面两条在其他函数内执行,这里就不用执行了。
	//	RTC_SetCounter(1672588795);
	//	RTC_WaitForLastTask();  //等待写入操作完成
		MyRTC_SetTime();   //设置时间
		
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);  //BKP1后备寄存器写入0xA5A5
	}
	
	else  //否则是不需要重新写时间的
	{
		//第四步:调用等待的函数(等待同步,等待上一次操作完成)
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
	}
}

/*
写两个函数:
一个是设置时间,
一个是读取时间。
*/

// 设置时间的函数
void MyRTC_SetTime(void)
{
	time_t time_CNT;      //声明存放时间戳的变量time_CNT
	struct tm time_date;     //创建时间结构体的变量time_data
	
	//第一步:把我们数组指定的时间,填充到struct tm结构体里
	time_date.tm_year = MyRTC_Time[0] - 1900;   //向结构体赋值年份  减去偏移
	time_date.tm_mon = MyRTC_Time[1] - 1;    //向结构体赋值月份 减去偏移
	time_date.tm_mday = MyRTC_Time[2];   //向结构体赋值日份
	time_date.tm_hour = MyRTC_Time[3];   //向结构体赋值小时
	time_date.tm_min = MyRTC_Time[4];    //向结构体赋值分钟
	time_date.tm_sec = MyRTC_Time[5];    //向结构体赋值秒钟
	
	//第二步:把结构体中的时间转换成时间戳
	time_CNT = mktime(&time_date);    //把结构体中的时间转换成时间戳
	
	//第三步:把时间戳写入到RTC中当做初始时间
	RTC_SetCounter(time_CNT);      //把时间戳写入到RTC中当做初始时间
	
	RTC_WaitForLastTask();  //等待写入操作完成
}


//读取时间的函数
void MyRTC_ReadTime(void)
{
	time_t time_CNT;      //声明存放时间戳的变量time_CNT
	struct tm time_date;     //创建时间结构体的变量time_data
	//第一步:读取时间戳放到时间戳变量中
	time_CNT = RTC_GetCounter();
	
	//第二步:把时间戳转换成时间,存放到结构体中
	time_date = *localtime(&time_CNT);
	
	//第三步:把结构体中的时间存放到我们指定的全局变量数组中。
	MyRTC_Time[0] = time_date.tm_year + 1900 ;   //取结构体赋值年份  +偏移
	MyRTC_Time[1] = time_date.tm_mon + 1;    //取结构体赋值月份 +偏移
	MyRTC_Time[2] = time_date.tm_mday;   //取结构体赋值日份
	MyRTC_Time[3] = time_date.tm_hour;   //取结构体赋值小时
	MyRTC_Time[4] = time_date.tm_min;    //取结构体赋值分钟
	MyRTC_Time[5] = time_date.tm_sec;    //取结构体赋值秒钟
}

MyRTC.h:

cs 复制代码
#ifndef __MYRTC_H

#define __MYRTC_H

extern uint16_t MyRTC_Time[];  //存储时间的数组

void MyRTC_Init(void);

// 设置时间的函数
void MyRTC_SetTime(void);


//读取时间的函数
void MyRTC_ReadTime(void);




#endif

主函数main.c:

cs 复制代码
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init();       //oled  屏幕初始化
	
	MyRTC_Init();    //RTC初始化
	
	OLED_ShowString(1,1,"Data:xxxx-xx-xx");  //1行1列显示日期
	OLED_ShowString(2,1,"Time:xx:xx:xx");    //2行1列显示时间
	OLED_ShowString(3,1,"CNT:");             //3行1列显示:CNT
	OLED_ShowString(4,1,"DIV:");             //4行1列显示:DIV余数寄存器
	while(1)
	{
		MyRTC_ReadTime();                      //读取时间
		OLED_ShowNum(1,6, MyRTC_Time[0],4);    //1行6列显示:年份
		OLED_ShowNum(1,11, MyRTC_Time[1],2);   //1行11列显示:月份
		OLED_ShowNum(1,14, MyRTC_Time[2],2);   //1行14列显示:日子
		OLED_ShowNum(2,6, MyRTC_Time[3],2);    //2行6列显示:小时
		OLED_ShowNum(2,9, MyRTC_Time[4],2);    //2行9列显示:分钟
		OLED_ShowNum(2,12, MyRTC_Time[5],2);    //2行12列显示:秒钟
		OLED_ShowNum(3,5, RTC_GetCounter(),10);  //3行5列显示:CNT
		OLED_ShowNum(4,5, RTC_GetDivider(),10);  //4行5列显示:DIV余数寄存器
	}
}

编译下载后,就能看到本次的实验结果了:

相关推荐
时空自由民.41 分钟前
无人机系统耗电,低功耗管理问题解决方法(chatgpt)
单片机·嵌入式硬件·无人机
时空自由民.1 小时前
无人机系统耗电,低功耗管理问题解决方法(腾讯元宝)
单片机·嵌入式硬件·无人机
清风6666662 小时前
基于单片机的双档输出数字直流电压源设计
单片机·mongodb·毕业设计·nosql·课程设计
牛马大师兄2 小时前
STM32独立看门狗IWDG与窗口看门狗WWDG知识梳理笔记
笔记·stm32·单片机·嵌入式硬件·嵌入式·看门狗
夜月yeyue2 小时前
STM32 Flash 访问加速器详解(ART Accelerator)
linux·单片机·嵌入式硬件·uboot·bootloard
A9better3 小时前
嵌入式开发学习日志37——stm32之USART
stm32·嵌入式硬件·学习
国科安芯6 小时前
ASP4644芯片低功耗设计思路解析
网络·单片机·嵌入式硬件·安全
充哥单片机设计7 小时前
【STM32项目开源】基于STM32的智能厨房火灾燃气监控
stm32·单片机·嵌入式硬件
CiLerLinux14 小时前
第四十九章 ESP32S3 WiFi 路由实验
网络·人工智能·单片机·嵌入式硬件
时光の尘14 小时前
【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
单片机·嵌入式硬件·pcb·二极管·电感·三极管·场效应管