目录

stm32-RTC时实时钟

stm32-RTC时实时钟


1. 时间戳的基本概念

  • 定义

    时间戳是一个表示时间的标记,它通常以数字的形式出现,代表某一时刻距离参考时刻的时间差。最常见的是 Unix 时间戳,它表示从1970年1月1日 00:00:00 UTC 到某个时刻所经过的秒数(或毫秒、微秒等)。

  • 表示方式

    • 秒级时间戳 :常见于 Unix 系统中,一个整数表示经过的秒数。
    • 毫秒级或微秒级时间戳 :精度更高,用于需要更精确时间测量的场景,比如事件记录或高频数据采集。

以下是常用的时间戳转换库函数在头文件<time.h>里面

https://i-blog.csdnimg.cn/direct/fbb570fe0ab345f89e1e3cd3ed75085e.png


#include <stdio.h>
#include <time.h>
time_t time_cnt;
struct tm time_data;
int main(void)
{

	 time_cnt=time(NULL);
	printf("%d\n",time_cnt);
	
	time_data=*localtime(&time_cnt);
	printf("%d\n",time_data.tm_year +1900);
	printf("%d\n",time_data.tm_mon +1);
		printf("%d\n",time_data.tm_mday );
  				printf("%d\n",time_data.tm_min);
					printf("%d\n",time_data.tm_sec);
	
	
	return 0;
}

2. 时间戳的用途

  • 事件记录

    在日志系统中,每个事件都会带有一个时间戳,用于记录事件发生的具体时间。这对于调试、监控和安全审计非常重要。

  • 数据同步

    在分布式系统中,时间戳用于协调数据的顺序和版本控制,确保数据一致性。

  • 数据库操作

    数据库中常用时间戳来记录记录的创建时间和更新时间,这有助于数据管理和历史追溯。

  • 通信协议

    在网络通信和数据传输中,时间戳可以用来测量延迟、同步时间以及进行排序处理。

  • 多媒体应用

    在音视频流媒体中,时间戳用于标识帧的顺序和播放时间,确保音视频同步。


3. 时间戳的特点

  • 唯一性和连续性

    时间戳通常是单调递增的,能确保在同一系统中每个事件都有一个唯一的时间标记。

  • 时区独立性

    例如 Unix 时间戳通常使用 UTC 表示,不受时区影响,因此便于跨地域同步和比较。

  • 精度和分辨率

    时间戳的精度可以根据需求调整,从秒到微秒不等。高精度时间戳在需要精确测量时间间隔的应用中非常关键。


4. 时间戳的实现

  • Unix 时间戳

    通常表示为从1970年1月1日 00:00:00 UTC到当前时刻的秒数。例如,时间戳 1610000000 表示某个具体的时间点。

  • 数据库时间戳

    许多数据库系统使用内置的时间戳数据类型,如 SQL Server 的 timestamp (注意,SQL Server 的 timestamp 现已被称为 rowversion ),以及 MySQL 中的 TIMESTAMP 类型,用于记录和跟踪记录变化。

  • 硬件计时器

    在嵌入式系统中,MCU 内部常见定时器模块可以生成时间戳,用于事件捕获和测量时间间隔。


5. 时间戳的转换

  • 从时间戳转换为日期

    开发者可以将时间戳转换为人类可读的日期和时间格式,常用编程语言都提供了相关函数。例如,在 C 语言中可以使用 localtime()strftime() 函数;在 Python 中使用 datetime.fromtimestamp() 等。

  • 从日期转换为时间戳

    同样,也可以将具体的日期和时间转换为对应的时间戳,以便进行计算和存储。


6. 实际应用中的注意点

  • 时钟同步

    在分布式系统中,不同设备的系统时钟可能存在偏差,因此常用 NTP(网络时间协议)来同步各设备的时钟,以确保时间戳的一致性。

  • 精度要求

    根据应用需求选择合适的时间戳精度。对于普通的事件记录,秒级时间戳通常足够;对于高精度测量(如音视频同步、实时数据采集),则需要毫秒甚至微秒级的时间戳。

  • 存储和传输

    时间戳在存储时通常为整数,传输时可以采用 JSON、XML 或二进制格式表示,确保数据在不同系统间一致性。

总结

时间戳是用于标识特定时间点的重要工具,广泛应用于日志记录、数据同步、数据库管理和实时系统中。它的主要特点包括唯一性、时区独立性和可调精度。正确理解和使用时间戳对于设计和实现各种时间敏感的应用非常重要。

STM32 BKP(Backup Registers)详解:备份寄存器的原理与应用

1. 什么是BKP寄存器? BKP(Backup Registers)是STM32微控制器中的一组特殊寄存器,位于备份域(Backup Domain)。这些寄存器的特点是即使在主电源(VDD)掉电的情况下,只要备用电池(VBAT)存在,寄存器中的数据仍然可以保留。因此,BKP寄存器通常用于存储关键数据,如RTC校准值、系统配置参数或状态标志。

https://i-blog.csdnimg.cn/direct/4a11ea6ac9e543d4a23a6e3861ef1c83.png

https://i-blog.csdnimg.cn/direct/bdaccbbdb6e84d4fb2b33638b036b56d.png

**1.1 BKP寄存器的主要特点

数据保持:在VDD掉电时,只要VBAT存在,数据不会丢失。

16位宽度:每个BKP寄存器为16位,可以存储任意数据。

数量有限:不同型号的STM32芯片,BKP寄存器的数量不同(通常为10~20个)。

-独立时钟域:BKP寄存器位于备份域,与主电源域分离。**

2. BKP寄存器的硬件结构

**2.1 备份域(Backup Domain)

备份域是STM32中一个独立的电源域,包括以下部分:

BKP寄存器:用于存储用户数据。

RTC(实时时钟):提供时间和日期功能。

Tamper检测:用于检测外部篡改事件(部分型号支持)。

电源控制寄存器(PWR_CR):通过DBP位控制对备份域的写访问。**

**2.2 电源管理

备份域的电源由以下两种电源提供:

VDD:主电源,正常运行时使用。

VBAT:备用电池,当VDD掉电时,VBAT为备份域供电。**

**2.3 写保护机制

为了防止误操作,STM32对BKP寄存器进行了写保护。要写入BKP寄存器,必须先使能PWR_CR寄存器中的DBP(Disable Backup Protection)位。**

3. BKP寄存器的应用场景

**3.1 RTC校准

BKP寄存器可以存储RTC的校准值,确保在系统复位或掉电后,RTC仍然能够保持准确的时间。**

**3.2 系统配置存储

在系统启动时,可以从BKP寄存器中读取配置参数(如工作模式、用户设置等),从而实现配置的持久化。**

**3.3 状态标志存储

BKP寄存器可以用于存储系统状态标志,例如:

  • 系统是否经历了异常复位。

  • 用户是否进行了某些操作(如按下某个按钮)。**

**3.4 数据备份

在关键应用中,BKP寄存器可以用于备份重要数据,确保在意外掉电时数据不会丢失。**

这里的中小产品为20字节是在1-10的数据寄存器中每个数据寄存器占2个字节,另外大容量产品同样每个数据寄存器占2字节

4. BKP寄存器的使用方法

**4.1 初始化步骤

在使用BKP寄存器之前,需要进行以下初始化操作:

  1. 使能PWR和BKP外设时钟。

  2. 使能备份域的写访问(设置DBP位)。

  3. 配置BKP寄存器(可选:配置Tamper检测或RTC)。**

**4.2 代码示例

以下是一个完整的代码示例,展示如何初始化BKP寄存器并读写数据:**

```c
#include "stm32f10x.h"

void BKP_Init(void) {
    // 1. 使能PWR和BKP外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    // 2. 使能备份域的写访问
    PWR_BackupAccessCmd(ENABLE);

    // 3. 配置BKP寄存器(可选)
    // 例如:写入一个初始值到BKP_DR1
    BKP_WriteBackupRegister(BKP_DR1, 0x1234);
}

uint16_t BKP_ReadData(void) {
    // 读取BKP寄存器的值
    return BKP_ReadBackupRegister(BKP_DR1);
}

void BKP_WriteData(uint16_t data) {
    // 写入数据到BKP寄存器
    BKP_WriteBackupRegister(BKP_DR1, data);
}

int main(void) {
    // 初始化BKP
    BKP_Init();

    // 写入数据
    BKP_WriteData(0x5678);

    // 读取数据
    uint16_t data = BKP_ReadData();

    while (1) {
        // 主循环
    }
}

4.3 代码解析

  • RCC_APB1PeriphClockCmd:使能PWR和BKP外设的时钟。
  • PWR_BackupAccessCmd:使能备份域的写访问。
  • BKP_WriteBackupRegister:向BKP寄存器写入数据。
  • BKP_ReadBackupRegister:从BKP寄存器读取数据。


**5. 注意事项**

**5.1 电源管理
  
- 确保VBAT引脚连接了备用电池,否则在VDD掉电时,BKP寄存器的数据会丢失。
  
- 如果不需要备份功能,可以将VBAT接地。**

**5.2 写保护
  
- 在写入BKP寄存器之前,必须使能DBP位。
  
- 写入完成后,可以禁用DBP位以防止误操作。**

**5.3 寄存器数量
  
- 不同型号的STM32芯片,BKP寄存器的数量可能不同。请参考具体型号的数据手册。**

**5.4 温度检测(Tamper)
  
- 部分STM32型号支持Tamper检测功能,可以用于检测外部篡改事件。如果使用此功能,需要额外配置。**

**6. 总结
  
STM32的BKP寄存器是备份域的重要组成部分,能够在系统复位或掉电时保存关键数据。通过合理使用BKP寄存器,可以实现RTC校准、系统配置存储、状态标志备份等功能。在实际应用中,需要注意电源管理、写保护机制以及寄存器数量的限制。BKP本质上还是RAM,是数据已丢失的内存,在没有VBAT备用电源供电后数据仍然会进行丢失.但是如果有VBAT供电的情况下,VCC上电复位都不会造成BKP数据存储的丢失.**

### 

### 

## **STM32 RTC 详细资料**

## **1. RTC 概述**

**RTC(Real-Time Clock) 是 STM32 微控制器中的一个专用外设,用于提供准确的时间和日期功能。RTC 能够在系统断电(通过备用电池供电)时继续运行,因此适用于需要长时间持续计时的场合,如日历、定时器、闹钟等应用。**

![](https://i-blog.csdnimg.cn/direct/02b5c1c0181f476b97edb3dee07fe53f.png)

#### 

#### **2. RTC 的特点**

* **低功耗**
  :RTC 通常工作在低功耗模式下,并且由独立的低速晶振(LSE)或内部低速时钟(LSI)驱动,功耗非常低。
* **独立备份域**
  :RTC 通常属于备份域(Backup Domain),即使主系统断电,RTC 及其相关寄存器依然能够通过备用电池保持运行。
* **丰富的寄存器**
  :RTC 提供多组寄存器来存储时间、日期、闹钟、定时器和校准信息,如 RTC_DR(日期寄存器)、RTC_TR(时间寄存器)、RTC_CR(控制寄存器)、RTC_ALRM(闹钟寄存器)等。
* **校准功能**
  :RTC 可以进行校准,修正由于晶振误差引起的时间偏差。
* **多种唤醒源**
  :RTC 可以配置多种唤醒方式,比如闹钟中断、周期性唤醒等,为低功耗应用提供灵活支持。

#### **3. RTC 的工作原理**

1. **时钟源**
   :

   * RTC 的时钟源通常有两种选择:外部低速晶振(LSE,一般为 32.768 kHz)和内部低速振荡器(LSI,约 40 kHz)。
   * **LSE**
     优点是精度高,适用于需要高精度计时的应用,作为主流RTC时钟源,在VDD断电后能够通过VBAT备用供电 ,
     **LSI**
     虽然精度较低,但成本低、集成度高,适用于对时间要求不那么严格的场合一般作为备用时钟源,频率为40kh,而且不存在备用电源VBAT供电,VDD断电后不能备用供电
2. **计数方式**
   :

   * RTC 通过内部计数器不断累加时钟脉冲来计时。计数器通常分为
     **秒计数器**
     和
     **分秒、小时、日期、月份和年份寄存器**
     。
   * 当计数器达到预设值时,会自动进位,例如 59 秒进 1 分,23 小时进 1 天等。
3. **备份域**
   :

   * RTC 与其他备份寄存器在同一电源域内,通常由备用电池供电。这样即使主系统电源断电,RTC 仍能持续运行,保持时间信息。
4. **中断与唤醒**
   :

   * RTC 可配置定时唤醒中断、闹钟中断等。比如,当设置的闹钟时间到达时,RTC 会触发中断,使系统从低功耗模式中唤醒,执行相应任务。
   * ### 1. RTC概述

     RTC是STM32中用于计时和日历功能的模块,具有以下特点:
   * **独立供电**
     :由VBAT引脚供电,即使主电源(VDD)掉电,RTC仍可继续运行。
   * **低功耗**
     :在低功耗模式下仍能正常工作。
   * **日历功能**
     :支持年、月、日、星期、时、分、秒的计时。
   * **闹钟功能**
     :可以设置闹钟,在特定时间触发中断。
   * **周期性唤醒**
     :可以配置周期性唤醒定时器,用于低功耗应用。
   * ---

     ### 2. RTC寄存器详解

     RTC的功能通过一组寄存器实现,以下是主要寄存器的功能说明:

     #### 2.1 RTC控制寄存器(RTC_CR)
   * **功能**
     :配置RTC的工作模式和控制功能。
   * **重要位**
     :

     + **BYPSHAD**
       :绕过影子寄存器(直接访问计数器)。
     + **FMT**
       :时间格式(0:24小时制,1:12小时制)。
     + **OSEL**
       :输出选择(选择RTC输出信号)。
     + **ALRAE**
       :闹钟A使能。
     + **ALRBE**
       :闹钟B使能。
   * #### 2.2 RTC预分频器寄存器(RTC_PRER)
   * **功能**
     :配置RTC的时钟分频器。
   * **重要位**
     :

     + **PREDIV_A**
       :异步预分频器(通常设置为127)。
     + **PREDIV_S**
       :同步预分频器(通常设置为255)。
   * #### 2.3 RTC时间寄存器(RTC_TR)
   * **功能**
     :存储当前时间(时、分、秒)。
   * **重要位**
     :

     + **HT/HT[1:0]**
       :小时的十位。
     + **HU/HU[3:0]**
       :小时的个位。
     + **MNT/MNT[2:0]**
       :分钟的十位。
     + **MNU/MNU[3:0]**
       :分钟的个位。
     + **ST/ST[2:0]**
       :秒的十位。
     + **SU/SU[3:0]**
       :秒的个位。
     + **PM**
       :12小时制下的上午/下午标志。
   * #### 2.4 RTC日期寄存器(RTC_DR)
   * **功能**
     :存储当前日期(年、月、日、星期)。
   * **重要位**
     :

     + **YT/YT[1:0]**
       :年的十位。
     + **YU/YU[3:0]**
       :年的个位。
     + **MT**
       :月的十位。
     + **MU**
       :月的个位。
     + **DT/DT[1:0]**
       :日的十位。
     + **DU/DU[3:0]**
       :日的个位。
     + **WDU[2:0]**
       :星期几。
   * #### 2.5 RTC闹钟寄存器(RTC_ALRMAR/RTC_ALRMBR)
   * **功能**
     :设置闹钟时间。
   * **重要位**
     :

     + **MSKx**
       :屏蔽位(用于选择闹钟比较的字段)。
     + **ST/SU**
       :秒。
     + **MNT/MNU**
       :分钟。
     + **HT/HU**
       :小时。
     + **DT/DU**
       :日期。
   * #### 2.6 RTC状态寄存器(RTC_ISR)
   * **功能**
     :指示RTC的状态。
   * **重要位**
     :

     + **ALRAF**
       :闹钟A标志。
     + **ALRBF**
       :闹钟B标志。
     + **RSF**
       :寄存器同步标志。
     + **INITS**
       :初始化状态标志。
     + **SHPF**
       :移位操作标志。
   * #### 2.7 RTC写保护寄存器(RTC_WPR)
   * **功能**
     :用于解除RTC寄存器的写保护。
   * **用法**
     :写入特定的密钥(0xCA,0x53)以解除写保护。

     ### 4. RTC的常见应用

     #### 4.1 闹钟功能

     通过配置RTC_ALRMAR或RTC_ALRMBR寄存器,可以设置闹钟时间,并在闹钟触发时产生中断。

     #### 4.2 周期性唤醒

     通过配置RTC_WUTR寄存器,可以设置周期性唤醒定时器,用于低功耗应用。

     #### 4.3 时间戳功能

     部分STM32型号支持时间戳功能,可以记录外部事件的发生时间。
   * **在STM32微控制器中,实时时钟(RTC)通常有三个主要的中断,分别是秒中断(Second interrupt)、闹钟中断(Alarm interrupt)和唤醒中断(Wakeup interrupt)。以下是对这三个中断的详细介绍:**
   * **秒中断(Second interrupt)**
       
     **功能描述:**
     秒中断是RTC最基本的中断之一,它以秒为周期触发。当RTC的计数器每秒钟更新一次时,如果秒中断使能,就会产生一个中断信号,通知微控制器时间过去了一秒。
       
     **应用场景**
     :常用于需要精确到秒的定时任务,例如实时数据记录,以每秒为间隔记录传感器数据;也可用于实现简单的秒表功能,或者作为系统中其他定时操作的基本时间参考,如每隔一定秒数进行一次系统状态检查等。
   * **闹钟中断(Alarm interrupt)**
       
     **功能描述:**
     闹钟中断允许用户设置一个特定的时间点,当RTC的时间计数到达这个设定的时间时,就会触发闹钟中断。用户可以通过配置RTC的闹钟寄存器来设置年、月、日、时、分、秒等时间参数,当RTC时间与设置的闹钟时间匹配时,产生中断信号。
       
     **应用场景:**
     广泛应用于定时提醒功能,比如在智能手表中设置定时提醒事件,在工业控制系统中设置定时报警,提醒工作人员进行设备维护或处理特定任务等。还可用于定时启动或停止某些设备或任务,如定时启动数据采集、定时关闭显示屏以节省能源等。
   * **唤醒中断(Wakeup interrupt)**
       
     **能描述:**
     唤醒中断主要用于将微控制器从低功耗模式中唤醒。RTC可以设置一个唤醒周期,每隔一定的时间间隔产生一个唤醒中断信号,使微控制器从低功耗睡眠状态恢复到正常运行状态。唤醒周期可以通过配置RTC的唤醒寄存器来设置,通常可以设置为几毫秒到数小时不等。
       
     **应用场景:**
     在电池供电的设备中,为了节省电能,微控制器经常会进入低功耗模式。唤醒中断可以让设备在需要的时候定时唤醒,进行数据处理、通信等操作,然后再进入低功耗模式,从而有效降低设备的整体功耗,延长电池使用寿命。例如,在物联网传感器节点中,传感器可以定期唤醒进行数据采集和发送,然后继续进入低功耗状态等待下一次唤醒。

     ---

     ### 5. 注意事项
   * **时钟源选择**
     :RTC的时钟源可以是LSE(外部低速晶振)、LSI(内部低速振荡器)或HSE(外部高速晶振)先择完时钟信号后要等待时钟信号标志位RCC_IT_HSIRDY置1才能进行后续的RTC时钟选择
   * **写保护**
     :在修改RTC寄存器之前,必须解除写保护。
   * **寄存器同步**
     :在读取RTC寄存器之前,需要等待同步完成也就是需要调用时钟同步等待函数,同时还要调用等待函数等待上一步操作完成,防止出现数据同步的BUG.
   * ![](https://i-blog.csdnimg.cn/direct/d7fe59d41bf8455c9342dce2b5bc97de.png)

#### **4. RTC 配置及使用方法**

##### **4.1 使用 STM32 标准库(HAL 或 StdPeriph)的基本流程**

![](https://i-blog.csdnimg.cn/direct/d804c7e13dd74a45a8da4666583bc914.png)

1. **使能 RTC 时钟**
   :

   * 通过 RCC 相关函数使能 RTC 及其备用域时钟。通常需要先使能 PWR 和 BKP 时钟,然后解除备份域的写保护。
2. **配置时钟源**
   :

   * 选择 LSE 或 LSI 作为 RTC 的时钟源,并等待时钟稳定。
3. **初始化 RTC**
   :

   * 配置 RTC 的时间、日期、闹钟和校准参数。使用对应的库函数初始化 RTC 模块以以及配置PRL(重装载计数器),DIV(余数计数器),CNT(32位计数器),ALR(32闹钟计数器)等相关参数
4. **配置中断或唤醒**
   :

   * 根据应用需求,配置 RTC 的唤醒中断或闹钟中断。

##### **4.2 示例代码(基于 STM32 标准外设库)**

**下面是一个简单的 RTC 初始化示例代码,展示如何配置 RTC,设置时间并使能闹钟中断。注意:不同的 STM32 系列可能在 RTC 配置上略有不同,具体请参考相应的数据手册和库文件。**

#include “stm32f10x.h”

void RTC_Config(void) { RTC_InitTypeDef RTC_InitStructure; RTC_TimeTypeDef RTC_TimeStructure; RTC_DateTypeDef RTC_DateStructure;

// 使能 PWR 时钟并允许访问备份寄存器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);

// 使能 LSE 时钟
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);

// 将 RTC 时钟源设置为 LSE
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

// 使能 RTC 时钟
RCC_RTCCLKCmd(ENABLE);

// 等待 RTC 寄存器同步
RTC_WaitForSynchro();

// 配置 RTC 时钟
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStructure.RTC_AsynchPrediv = 0x7F;   // 异步预分频值
RTC_InitStructure.RTC_SynchPrediv = 0x00FF;    // 同步预分频值,根据LSE 32.768kHz来计算
if (RTC_Init(&RTC_InitStructure) == ERROR) {
    // 初始化失败处理
    while (1);
}

// 设置时间:例如 12:34:56
RTC_TimeStructure.RTC_Hours = 12;
RTC_TimeStructure.RTC_Minutes = 34;
RTC_TimeStructure.RTC_Seconds = 56;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure);

// 设置日期:例如 2025-03-02,星期一
RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Monday;
RTC_DateStructure.RTC_Month = RTC_Month_March;
RTC_DateStructure.RTC_Date = 2;
RTC_DateStructure.RTC_Year = 25;
RTC_SetDate(RTC_Format_BIN, &RTC_DateStructure);

}

int main(void) { SystemInit(); RTC_Config();

while(1) {
    // 在这里可以添加代码读取 RTC 时间、日期,并显示或其他操作
}

}


#### **5. RTC 在低功耗模式下的应用**

* **待机模式(Standby Mode)**
  :在待机模式下,RTC 是唯一保持运行的外设,用于计时、闹钟唤醒等。
* **唤醒中断**
  :RTC 可以配置为在特定时间触发唤醒中断,从低功耗模式中唤醒系统继续运行。

#### **6. 参考与扩展**

* **参考 STM32 数据手册**
  :详细了解 RTC 模块的寄存器配置、时钟分频值、闹钟设置等。
* **STM32 HAL 库**
  :新版 STM32 的 HAL 库也提供了 RTC 配置函数,可以参考 HAL_RTC_Init()、HAL_RTC_SetTime()、HAL_RTC_SetDate() 等函数进行配置。

---

#### **总结**

* **RTC 模块**
  提供准确的时间和日期管理,并能在低功耗模式下持续运行。
* RTC 使用
  **外部低速晶振(LSE)**
  或
  **内部低速振荡器(LSI)**
  作为时钟源,并具有备份域,能在系统断电时保持时间信息。
* 通过配置预分频器和同步预分频器,可以根据所选时钟源实现准确的时间计数。
* RTC 可以配置闹钟和唤醒中断,适用于定时任务和低功耗系统唤醒。

**项目1:使用BKP外设进行数据读写操作,以及在VCC掉电后由VBTA提供备用电源防止数据不丢失**

**操作:1使能BKP和PWR的时钟**

**2使能PWR_CR 的DPB位开启BKP的数据读写**

**3对BKP内部备份数据寄存器进行写入数据并读取数据**

**4分别观察在VCC掉电后BKP的数据情况以及BVAT掉电后的数据情况**

int main(void){

 OLED_Init();
   key_Init();
  OLED_ShowString (1,1,"w:");
	OLED_ShowString (2,1,"R:");  
 //开启pwr和bkp的时钟APB1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR| RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
 //BKP_WriteBackupRegister(BKP_DR1,0x1234);

OLED_ShowHexNum (1,1,BKP_ReadBackupRegister(BKP_DR1),4);


通过按键来优先实现BKP对数据的读写操作

//开启pwr和bkp的时钟APB1 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR| RCC_APB1Periph_BKP,ENABLE); PWR_BackupAccessCmd(ENABLE);

	while(1)
	{
	keynumber = Get_keynum();
		if(keynumber==1)
		{
			arrayWrite[0]++;
		  arrayWrite[1]++;
			BKP_WriteBackupRegister(BKP_DR1,arrayWrite[0]);
			BKP_WriteBackupRegister(BKP_DR2, arrayWrite[1]);
			
			
			OLED_ShowHexNum (1,3,arrayWrite[0],4);
		  OLED_ShowHexNum (1,8,arrayWrite[1],4);
		}
    arrayRead[0]= BKP_ReadBackupRegister(BKP_DR1);
		arrayRead[1]= BKP_ReadBackupRegister(BKP_DR2);
		
		OLED_ShowHexNum (2,3,arrayRead[0],4);
		OLED_ShowHexNum (2,8,arrayRead[1],4);
}
}

**项目二:利用RTC外设进行时间计时**

**操作:1开启PWR和BKP的时钟并同时设置PWR_CR的DBP寄存器开启对BKP对RTC的访问**

**2开启时钟源(主要是外部低速时钟LSE,有时作为备用也可调用内部低速时钟LSI)最后还需要等待RCC_LSERDY标志位置1即时钟启动完成**

**3进行RTC时钟选择,并进行时钟使能,**

**4等待时钟同步和上次一次操作完成**

**5 设置分频值(分频系数是32768-1)自动进入计数配置模式和闹钟配置模式**

**6设置CNT的初始值**

**7设置日次传入参数计算秒数最终读取数组中的日期**

int main(void){

 OLED_Init();
   Rtc_Config();
OLED_ShowString (1,1,"Data:xxxx-xx-xx");
OLED_ShowString (2,1,"Time:xxxx-xx-xx");
OLED_ShowString (3,1,"Cnt:xxxx-xx-xx");
	while(1)
	{
   myRTC_ReadTime();
		OLED_ShowNum (1,6,MyRtc_Time [0],4);
	OLED_ShowNum (1,6,MyRtc_Time [1],2);
	OLED_ShowNum (1,6,MyRtc_Time [2],2);
	OLED_ShowNum (1,6,MyRtc_Time [3],2);
	OLED_ShowNum (1,6,MyRtc_Time [4],2);
	OLED_ShowNum (1,6,MyRtc_Time [5],2);
		
OLED_ShowNum (3,6,RTC_GetCounter (),10);
}

}

#include “stm32f10x.h” // Device head #include “rtc.h” #include <time.h> uint16_t MyRtc_Time[]={2023,1,1,23,59,55}; void Rtc_Config() { //开启pwr和bkp的时钟APB1 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR| RCC_APB1Periph_BKP,ENABLE); PWR_BackupAccessCmd(ENABLE);//开启BKP和RTC的访问 RCC_LSEConfig(RCC_LSE_ON); while( RCC_GetITStatus(RCC_IT_HSIRDY)!=SET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE ); RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_SetPrescaler(32768-1); RTC_WaitForLastTask(); RTC_SetCounter(1672588795);//设置初始时间也就是CNT的值

}

void RTC_Set_time() { time_t time_cnt; struct tm time_data; time_data.tm_year =MyRtc_Time [0]-1900; time_data.tm_mon =MyRtc_Time [1]-1; time_data.tm_mday =MyRtc_Time[2]; time_data.tm_hour =MyRtc_Time [3]; time_data.tm_min =MyRtc_Time [4]; time_data.tm_sec =MyRtc_Time [5];

 time_cnt=mktime (&time_data);
RTC_SetCounter (time_cnt );
	RTC_WaitForLastTask();

} void myRTC_ReadTime() { time_t time_cnt; struct tm time_data; time_cnt= RTC_GetCounter(); time_data=*localtime (&time_cnt); MyRtc_Time [0]= time_data.tm_year+1900; MyRtc_Time[1]= time_data.tm_mon+1; MyRtc_Time[2]= time_data.tm_mday; MyRtc_Time [3]= time_data.tm_hour; MyRtc_Time [4]= time_data.tm_min; MyRtc_Time [5]= time_data.tm_sec;

}