RTC定时时钟

一.RTC基本信息

1.Unix时间戳

Unix时间戳定义: 从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒。

时间戳存储在一个秒计数器中,秒计数器为32位/64位的整形变量,32位到2038年就装不下了

世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间
GMT格林尼治标准时间 是一种以地球自转为基础的时间计量系统。他将地球自转一周的时间间隔等分为24小时,以此确定计数标准
UTC协调世界时以原子钟为基础的事件计量系统

2.RTC定义

RTC 是一个独立的定时器,可谓系统提供时钟和日历功能
RTC和时钟配置系统 处于后备区域,系统复位时数据不清零,VDD断电后可借助VBAT供电继续走时间,如果没有备用电源主电源掉电数据维持不了
32位的可编程计数器: 可对应Unix时间戳的秒计数器
20位的可编程预分频器: 可配置不同频率的输入时钟
三种RTC时钟源: HSE时钟除以128(通常为8MHz/128)

LSE振荡器时钟(通常为32.768KHz)

LSI振荡器时钟(40KHz)
HSE =高速外部时钟信号
HSI =高速内部时钟信号
LSE =低速外部时钟信号
LSI=低速内部时钟信号

3.操作注意事项

对BKP和RTC访问时: 设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟

设置PWR_CR的DBP,使能对BKP和RTC的访问
若在读取RTC寄存器时: RTC的APB1接口处于禁止状态,软件必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被置1
设置RTC_CRL寄存器中的CNF位: 使RTC进入配置模式后,才能写

RTC_PRL,RTC_CNT,RTC_ALR寄存器
**对RTC任何寄存器的写操作:**必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器的RTOFF状态位,判断寄存器是否为更新状态。当RTOFF状态为是1时,才可以写入RTC寄存器

二.RTC基本流程

开启PWR,BKP时钟

PWR_BackupAccessCmd();//使能PWR

RCC_LSEConfig();//配置LSE(低速时钟),并使用RCC_LSE_ON打开

RCC_GetFlagStatus(RCC_FLAG_LSERDY);//等待LSE标志位置1

RCC_RTCCLKConfig();//配置RTC时钟源,选择LSE低速时钟源

RCC_RTCCLKCmd();//使能RTC时钟

RTC_WaitForSynchro();//RTC等待同步函数

RTC_WaitForLastTask();//等待上一步完成函数

RTC_SetPrescaler(32768 - 1);//配置预分频器满程-1

RTC_WaitForLastTask();//等待上一步完成函数

RTC_SetCount();//设置秒寄存器时间

RTC_WaitForLastTask();//等待上一步完成函数

三.代码实现

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init ();
	MyRTC_Init();
	
	OLED_ShowString (1,1,"Data:xxxx-xx-xx");
	OLED_ShowString (2,1,"Time:xx:xx:xx");
	OLED_ShowString (3,1,"CNT:");
	OLED_ShowString (4,1,"DIV:");
	
	while(1)
	{
		MyRTC_ReadTime();
		
		OLED_ShowNum(1,6,MyRTC_Time[0],4);//显示年
		OLED_ShowNum(1,11,MyRTC_Time[1],2);//显示月
		OLED_ShowNum(1,14,MyRTC_Time[2],2);//显示日
		OLED_ShowNum(2,6,MyRTC_Time[3],2);//显示小时
		OLED_ShowNum(2,9,MyRTC_Time[4],2);//显示分钟
		OLED_ShowNum(2,12,MyRTC_Time[5],2);//显示秒
		OLED_ShowNum(3,5,RTC_GetCounter(),10);//显示秒计数器
		OLED_ShowNum(4,1,RTC_GetDivider(),10);//显示余数计数器
    }
}

MyRTC.c

#include "stm32f10x.h"                  // Device header
#include <time.h>
#include "MyRTC.h"

uint16_t MyRTC_Time[] = {2023,1,1,23,59,55};//定义一个年月日数组

void MyRTC_Init (void)
{
	//开启时钟
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR ,ENABLE);//开启PWR时钟
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_BKP ,ENABLE);//开启BKP时钟
	
	//使能PWR
	PWR_BackupAccessCmd (ENABLE);//开启PWR访问备份配置寄存器
	
	if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)//判断读取备份寄存器标志位
	//开启LSE低速外部时钟
	{
	RCC_LSEConfig (RCC_LSE_ON);//打开低速外部时钟
	while(RCC_GetFlagStatus (RCC_FLAG_LSERDY) != SET);//等待LSE低速外部时钟置1
	
	//配置RTC时钟源
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//时钟源选择LSE低速外部时钟源
	RCC_RTCCLKCmd(ENABLE);//开启时钟源
	
	//等待同步函数
	RTC_WaitForSynchro();//同步函数等待
	RTC_WaitForLastTask ();//等待上一个操作完成
	
	//配置预分频器
	RTC_SetPrescaler (32768 - 1);//预分频1KHz
	RTC_WaitForLastTask ();//等待上一个操作完成
	
	MyRTC_SetTime();//将不断刷新秒计数器
		
	BKP_WriteBackupRegister(BKP_DR1,0xA5A5);//写入备份寄存器
	}
	else
	{
	RTC_WaitForSynchro();//同步函数等待
	RTC_WaitForLastTask ();//等待上一个操作完成
	}
}

//设置时间戳
void MyRTC_SetTime(void)
{
	time_t time_cnt;//定义秒计数器
	struct tm time_date;//定义一个年月日结构体
	
	time_date.tm_year = MyRTC_Time[0] - 1900;//年,从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) - 8 * 60 * 60;//将time_date结构体年月日数值转换成秒计数器
	
	RTC_SetCounter(time_cnt);//将时间戳存入主机
	RTC_WaitForLastTask ();//等待上一个操作完成
}

//读取年月日时间
void MyRTC_ReadTime(void)
{
	time_t time_cnt;//定义秒计数器
	struct tm time_date;//定义一个年月日结构体
	
	time_cnt = RTC_GetCounter() + 8 * 60 * 60;//获取当前秒计数器时间
	
	time_date = *localtime(&time_cnt);//将秒计数器时间转化成年月日
	
	MyRTC_Time[0] = time_date.tm_year + 1900 ;//年,从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
相关推荐
小林熬夜学编程1 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
Jackey_Song_Odd1 小时前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
A懿轩A3 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
半盏茶香3 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
字节高级特工4 小时前
【C++】深入剖析默认成员函数3:拷贝构造函数
c语言·c++
计算机学长大白5 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
yutian06068 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
XH华10 小时前
初识C语言之二维数组(下)
c语言·算法
析木不会编程11 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
Uu_05kkq13 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法