0%

12-3读写备份寄存器&实时时钟

常用函数

1
void BKP_DeInit(void);

BKP_DeInit恢复缺省配置,手动清空BKP所有的数据寄存器。

1
void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel);

用于配置TAMPER侵入检测功能,配置TAMPER引脚有效电平,高电平触发还是低电平触发。

1
void BKP_TamperPinCmd(FunctionalState NewState);

用于配置TAMPER侵入检测功能,是否开启侵入检测功能。

1
void BKP_ITConfig(FunctionalState NewState);

中断配置,是否开启中断。

1
void BKP_RTCOutputConfig(uint16_t BKP_RTCOutputSource);

时钟输出功能,可以选择在RTC引脚上输出时钟信号,输出RTC校准时钟,RTC闹钟脉冲或秒脉冲。

1
void BKP_SetRTCCalibrationValue(uint8_t CalibrationValue);

设置RTC校准值,写入RTC校准寄存器。

1
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);

写备份寄存器,第一个参数指定,写在哪个DR里,第二个参数指定要写入的数据。

1
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);

读备份寄存器,参数指定要读哪个DR。

1
FlagStatus BKP_GetFlagStatus(void);

获取BKP状态

1
void BKP_ClearFlag(void);

清除BKP侵入检测寄存器状态。

1
ITStatus BKP_GetITStatus(void);

获取侵入检测的中断状态。

1
void BKP_ClearITPendingBit(void);

清除侵入检测的中断挂起位。

1
void PWR_BackupAccessCmd(FunctionalState NewState);

备份寄存器访问使能。设置PWR_CR的DBP,使能对BKP和RTC的访问。

1
void RCC_LSEConfig(uint8_t RCC_LSE);

配置LSE外部低速时钟

1
void RCC_LSICmd(FunctionalState NewState);

配置LSI内部低速时钟

1
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);

RTCCLK配置,选择RTCCLK时钟源

1
void RCC_RTCCLKCmd(FunctionalState NewState);

RTCCLK使能,调用上面函数选择时钟之后,使能。

1
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);

获取RCC标志位,调用启动时钟函数之后,要等待标志位,LSERDY置1后,才算启动完成。

1
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);

配置RTC中断输出

1
void RTC_EnterConfigMode(void);

进入配置模式,CNF位置1。

1
void RTC_ExitConfigMode(void);

RTC退出配置模式,把CNF位置0。

1
uint32_t  RTC_GetCounter(void);

RTC获取CNT计数器的值。用于读取时钟。

1
void RTC_SetCounter(uint32_t CounterValue);

写入CNT计数器的值。用于设置时间。

1
void RTC_SetPrescaler(uint32_t PrescalerValue);

写入预分频器,写入到预分频的PRL重装寄存器中,配置预分频器的分频系数。

1
void RTC_SetAlarm(uint32_t AlarmValue);

写入闹钟值,用于配置闹钟。

1
uint32_t  RTC_GetDivider(void);

获取预分频器中的DIV余数寄存器。余数寄存器是一个自减计数器,获取这个值,一般是为了获取更细致的时间。

1
void RTC_WaitForLastTask(void);

等待上次操作完成。

1
void RTC_WaitForSynchro(void);

等待同步。清除RSF标志位,然后循环,直到RSF为1。

1
2
3
4
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
void RTC_ClearFlag(uint16_t RTC_FLAG);
ITStatus RTC_GetITStatus(uint16_t RTC_IT);
void RTC_ClearITPendingBit(uint16_t RTC_IT);

RTC标志位相关函数。

读写备份寄存器

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"

uint16_t ArrayWrite[] = {0x1234,0x5678};//存放写入数据的数组
uint16_t ArrayRead[2];//存放读取数据的数组
uint8_t KeyNum;

int main(void)
{
OLED_Init();
KEY_Init();

OLED_ShowString(1,1,"W:");
OLED_ShowString(2,1,"R:");

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启APB1的PWR外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//开启APB1的BKP外设时钟

PWR_BackupAccessCmd(ENABLE);//使能PWR


//BKP_WriteBackupRegister(BKP_DR1,0x1234);//BKP写入,在BKPDR1中写入了0x1234
//OLED_ShowHexNum(1,1,BKP_ReadBackupRegister(BKP_DR1),4);//OLED显示写入的值

while(1)
{
KeyNum = Key_GetNum();//获取按钮状态

if(KeyNum == 1)
{
ArrayWrite[0]++;//写入的数据自增1
ArrayWrite[1]++;

BKP_WriteBackupRegister(BKP_DR1,ArrayWrite[0]);//把ArrayWrite[0]的数据写入到DR1中
BKP_WriteBackupRegister(BKP_DR2,ArrayWrite[1]);//把ArrayWrite[1]的数据写入到DR2中

OLED_ShowHexNum(1,3,ArrayWrite[0],4);
OLED_ShowHexNum(1,8,ArrayWrite[1],4);
}
ArrayRead[0] = BKP_ReadBackupRegister(BKP_DR1);//读取BKPDR1的值,放到ArrayRead[0]中
ArrayRead[1] = BKP_ReadBackupRegister(BKP_DR2);//读取BKPDR2的值,放到ArrayRead[1]中

OLED_ShowHexNum(2,3,ArrayRead[0],4);
OLED_ShowHexNum(2,8,ArrayRead[1],4);
}
}

实时时钟

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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,"Date: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,6,RTC_GetCounter(),10);
OLED_ShowNum(4,6,RTC_GetDivider(),10);
}
}

MyRTC.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "stm32f10x.h"                  // Device header
#include <time.h>

uint16_t MyRTC_Time[] = {2023,1,1,23,59,55};

void MyRTC_SetTime(void)
{
time_t time_cnt;
struct tm time_date;
//把数组指定的时间填充到结构体中
time_date.tm_year = MyRTC_Time[0] - 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;//得到秒数,偏移8小时

RTC_SetCounter(time_cnt);//秒数写入到RTC的CNT中
RTC_WaitForLastTask();//等待写入时间完成
}

void MyRTC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//开启BKP时钟
PWR_BackupAccessCmd(ENABLE);

if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)//判断DR1中的值是否为0xA5A5,用于判断是否完全断电
{
//开启LSE时钟,并等待LSE时钟启动完成
RCC_LSEConfig(RCC_LSE_ON);//LSE振荡器打开
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);//获取标志位,LSE时钟启动完成

//选择RTCCLK时钟源
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//RTCCLK时钟源选择LSE时钟
RCC_RTCCLKCmd(ENABLE);//使能RTCCLK时钟

//等待同步和等待上一次写入操作完成
RTC_WaitForSynchro();//等待同步
RTC_WaitForLastTask();//等待上一次操作完成

//配置预分频器
RTC_SetPrescaler(32768-1);
RTC_WaitForLastTask();//等待写入预分频值完成

//RTC_SetCounter(1672588795);//设置初始时间
//RTC_WaitForLastTask();//等待写入时间完成

MyRTC_SetTime();

BKP_WriteBackupRegister(BKP_DR1,0xA5A5);
}
else
{
//等待同步和等待上一次写入操作完成
RTC_WaitForSynchro();//等待同步
RTC_WaitForLastTask();//等待上一次操作完成
}
}



void MyRTC_ReadTime(void)
{
time_t time_cnt;
struct tm time_date;
//得到秒数
time_cnt = RTC_GetCounter() + 8*60*60;//偏移8小时
time_date = *localtime(&time_cnt);

MyRTC_Time[0] = time_date.tm_year + 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;

}