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
相关推荐
黎明smaly2 小时前
从零学编程-C语言-第17天
c语言·数据结构·c++·算法·visual studio
zhouzhurong3 小时前
C语言scanf用%d读入字符型变量,通过输入字符的ASCII码输入字符
c语言·开发语言·算法
疑惑的杰瑞4 小时前
[数据结构]带头双向循环链表的实现与应用
c语言·数据结构·算法·链表
DdddJMs__1355 小时前
C语言 | Leetcode C语言题解之第454题四数相加II
c语言·leetcode·题解
黎明smaly6 小时前
【数据结构与算法初阶】前言介绍
c语言·开发语言·数据结构·算法
LaoWaiHang6 小时前
C语言从头学67——学习头文件stddef.h和stdbool.h
c语言
昵称p7 小时前
RTC -
单片机·mcu·rtc
running thunderbolt7 小时前
算法:双指针系列(一)
c语言·c++·算法·leetcode
山顶风景独好8 小时前
【Leecode 随笔】C语言版看了不后悔系列持续更新中。。。
c语言·开发语言·数据结构·算法·leecode