RTC实时时钟
1、时间戳
c
#include <stdio.h>
#include <time.h>
time_t ourtime; // time_t = int64_t;
struct tm day;
struct tm day1;
struct tm day2;
int main(void)
{
//t = time(NULL);//获取伦敦的时间戳的秒数,
time(&ourtime);
printf("伦敦的时间戳:%d\n",ourtime);
long long int d = ourtime + 28800;
printf("本地的时间戳:%d\n",d);
day = *gmtime(&ourtime);//转换为伦敦的年月日时分秒
printf("伦敦时间:%d-%d-%d %d:%d:%d。\n",day.tm_year+1900,day.tm_mon+1,day.tm_mday
,day.tm_hour,day.tm_min,day.tm_sec);
day1 = *gmtime(&d);//转换为本地的年月日时分秒
printf("本地时间:%d-%d-%d %d:%d:%d。\n",day1.tm_year+1900,day1.tm_mon+1,day1.tm_mday
,day1.tm_hour,day1.tm_min,day1.tm_sec);
day2 = *localtime(&ourtime);//转换为当地的年月日时分秒
printf("本地时间:%d-%d-%d %d:%d:%d。\n",day2.tm_year+1900,day2.tm_mon+1,day2.tm_mday
,day2.tm_hour,day2.tm_min,day2.tm_sec);
ourtime = mktime(&day2);//将本地的日期转换为伦敦的时间戳
printf("伦敦的时间戳:%d\n",ourtime);
char t[50];
strftime(t,50,"%Y-%m-%d %H:%M:%S",&day1);//打印自定义的时间格式
printf("本地时间:%s\n",t);
return 0;
}
伦敦的时间戳:1725763707
本地的时间戳:1725792507
伦敦时间:2024-9-8 2:48:27。
本地时间:2024-9-8 10:48:27。
本地时间:2024-9-8 10:48:27。
伦敦的时间戳:1725763707
本地时间:2024-09-08 10:48:27
2、BKP备份寄存器
2.1:简介
1、备份寄存器,用于存储数据,当VDD电源被切断时,这个备份寄存器由VBAT维持供电。如果VBAT电源也被切断,那么里面的数据就会被清除。当系统在待机模式下被唤醒,或系统复位或电源复位时,也不会被复位。
2、TAMPER引脚产生的侵入事件将所有备份寄存器内容清除
3、用户数据存储容量:
20字节r(中容量和小容量)/84字节(大容量和互联型)
2.2:基本结构
由上图所示:一个数据寄存器DR只能存储2个字节,而中容量和小容量只能存储20个字节,所以BKP中的数据寄存器DR只有10个。除了由数据寄存器,还有RTC的控制寄存器和状态寄存器和RTC时钟校准寄存器。
3、RTC时钟
RTC是一个独立的定时器,本质就是一个计时器。RTC和时钟配置系统处于后备区域,VDD(2.0~3.6V)断电后可借助VBAT (1.8~3.6V)供电继续走时。但是如果系统复位或电源复位时,秒计数器里面会从初始值开始计数
1、32位的可编程计数器,可对应Unix时间戳的秒计数器
2、20位的可编程预分频器,可适配不同频率的输入时钟
3、可选择三种RTC时钟源:
HSE时钟除以128(通常为8MHz/128)
LSE振荡器时钟(通常为32.768KHz)
LSI振荡器时钟(40KHz)
时钟来源:
如上图所示:RTC的时钟来源一般是LSE32.768KHz,而20位RTC预分频器设置为2^15,则正好为1Hz。而且只有这一路的时钟由备用电池VBAT供电。
注意事项:
4、读写备份寄存器BKP
标准库的编程接口:
c
/*
BKP(备份寄存器)数据的写入与读取测试
*/
#include "stm32f10x.h"
#include "OLED.h"
uint16_t Data;
int main(void)
{
OLED_Init();
//1、开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//使能BKP
//2、使能对BKP的访问
PWR_BackupAccessCmd(ENABLE);//使能对BKP和RTC的访问
//3、写入数据
BKP_WriteBackupRegister(BKP_DR1,0x1234);//写入数据寄存器DR1
//4、读取数据
Data = BKP_ReadBackupRegister(BKP_DR1);//读取数据寄存器DR1的数据
OLED_ShowHexNum(1,1,Data,4);
while(1)
{
}
}
5、RTC实时时钟
标准库的编程接口:
RTC.c文件的代码如下:
c
#include "stm32f10x.h" // Device header
#include <time.h>
uint16_t MyRTC_Time[] = {2024,9,10,21,10,55};//设置时间:年月日时分秒
void MyRTC_SetTime(void);//设置时间的函数
void MyRTC_Init(void)
{
//1、开启PWR和BKP的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
//2、使能BKP和RTC的访问
PWR_BackupAccessCmd(ENABLE);
if(BKP_ReadBackupRegister(BKP_DR1) != 0x1111)//按下复位按钮,BKP中DR1不清除,则不用重装计数器里面的时间戳
{
///3、配置时钟源
RCC_LSEConfig(RCC_LSE_ON);//打开LSE
//4、等待LSE启动完成
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
//5、选择RTC时钟源
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择LSE为时钟源
RCC_RTCCLKCmd(ENABLE);
//6、等待同步和操作完成
RTC_WaitForSynchro();//等待同步
RTC_WaitForLastTask();//等待操作完成
//7、配置预分频器
RTC_SetPrescaler(32768 - 1);//设置分频系数为32768
RTC_WaitForLastTask();//等待操作完成
MyRTC_SetTime();
BKP_WriteBackupRegister(BKP_DR1,0x1111);
}
else
{
RTC_WaitForSynchro();//等待同步
RTC_WaitForLastTask();//等待操作完成
}
}
void MyRTC_SetTime(void)//设置时间的函数
{
time_t ourtime;
struct tm day;
day.tm_year = MyRTC_Time[0]-1900;
day.tm_mon = MyRTC_Time[1]-1;
day.tm_mday = MyRTC_Time[2];
day.tm_hour = MyRTC_Time[3];
day.tm_min = MyRTC_Time[4];
day.tm_sec = MyRTC_Time[5];
ourtime = mktime(&day);//将日期转换为时间戳秒
RTC_SetCounter(ourtime);
RTC_WaitForLastTask();//等待操作完成
}
void MyRTC_ReadTime(void)
{
time_t ourtime;
struct tm day;
ourtime = RTC_GetCounter();//获取RTC计数器的值
day = *localtime(&ourtime);//将时间戳转换为本地的年月日时分秒
MyRTC_Time[0] = day.tm_year + 1900;//将转换的数据保存在数组中
MyRTC_Time[1] = day.tm_mon + 1;
MyRTC_Time[2] = day.tm_mday;
MyRTC_Time[3] = day.tm_hour;
MyRTC_Time[4] = day.tm_min;
MyRTC_Time[5] = day.tm_sec;
}
主程序的代码如下:
c
/*
RTC实时时钟的使用
*/
#include "stm32f10x.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:");
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);
}
}