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:

#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:

#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:

#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余数寄存器
	}
}

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

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
STM32F105系列微控制器是基于ARM Cortex-M3内核的微处理器,它具有一个复杂的时钟管理系统,称为时钟树(Clock Tree)。时钟树的主要作用是为芯片的不同功能模块提供稳定和精确的时钟信号,以便于控制和数据处理。 STM32F105的时钟树包括以下几个关键部分: 1. 主时钟(HCLK):也称为系统时钟,通常由内部振荡器(如HSI或LSI)或外部时钟源(如 crystals 或外部时钟输入)产生。它是整个系统的基础时钟。 2. 通用定时器时钟(PCLK1):这通常是HCLK的一半或两倍,用于驱动通用定时器和一些外围设备。 3. 闪存接口时钟(PCLK2):可能与PCLK1相同或独立,专用于Flash的读写操作。 4. 专门时钟(如ADC, DAC, USB等):这些外设有自己的专用时钟,确保它们的高速操作。 5. 分频器( PLLs):提供更高精度或频率可调的时钟,比如用于USB、UART、SPI等高速外设时钟。 6. 低功耗时钟(LSE):一个低速外部振荡器,用于备用模式下唤醒微控制器。 7. 内部定时器和计数器:这些都有自己的时钟源,如RTC实时时钟)和TIMx(定时器)。 在配置时钟树时,开发人员可以通过寄存器设置来选择合适的时钟源、时钟分频以及时钟的激活状态,以适应特定的应用需求。配置过程中可能涉及CLK相关的中断管理以及时钟安全策略,以确保系统在任何情况下都能稳定运行。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

尚久龙

你的鼓励是我最大的动力!谢谢!

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

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

打赏作者

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

抵扣说明:

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

余额充值