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/28)
                             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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值