24:RTC实时时钟
RTC实时时钟
- 1、时间戳
- 2、BKP备份寄存器
- 2.1:简介
- 2.2:基本结构
- 3、RTC时钟
- 4、读写备份寄存器BKP
- 5、RTC实时时钟
1、时间戳
#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
标准库的编程接口:
/*BKP(备份寄存器)数据的写入与读取测试
*/#include "stm32f10x.h"
#include "OLED.h"uint16_t Data;int main(void)
{OLED_Init();//1、开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWRRCC_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文件的代码如下:
#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);//设置分频系数为32768RTC_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;
}
主程序的代码如下:
/*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);}
}