当前位置: 首页 > news >正文

stm32之BKP备份寄存器和RTC时钟

目录

  • 1.时间戳
    • 1.1 Unix时间戳
    • 1.2 UTC/GMT
    • 1.3 时间戳转换
      • **1.** `time_t time(time_t*)`
      • **2.** `struct tm* gmtime(const time_t*)`
      • **3.** `struct tm* localtime(const time_t*)`
      • **4.** `time_t mktime(struct tm*)`
      • **5.** `char* ctime(const time_t*)`
      • **6.** `char* asctime(const struct tm*)`
      • **7.** `size_t strftime(char*, size_t, const char*, const struct tm*)`
  • 2.BKP
    • 2.1 简介
        • **寄存器资源**
        • **PC13 引脚功能**
    • 2.2 基本结构
  • 3.RTC时钟
    • 3.1 简介
      • **3.1.1 RTC 的主要特性**
      • **3.1.2 访问 RTC 的流程**
      • **3.1.3 RTC 的典型应用**
      • **3.1.4 RTC 的优势**
    • 3.2 框图(详细结构)
    • 3.3 RTC 的基本结构
    • 3.4 硬件电路
    • 3.5 使用注意事项
      • **3.5.1 使能对 BKP 和 RTC 的访问**
      • **3.5.2 同步寄存器(RSF)状态**
      • **3.5.3 进入 RTC 配置模式**
      • **3.5.4 写操作完成前必须等待**
      • **3.5.5 概括**
        • **关键操作流程**
        • **可能的错误操作**
        • **优化建议**
  • 4.实验
  • 5.扩展

img

1.时间戳

1.1 Unix时间戳

Unix 时间戳定义为从 UTC 时间的 1970 年 1 月 1 日 0 点 0 分 0 秒(称为 Unix 纪元时间,Epoch Time)开始,所经过的总秒数,不考虑闰秒的影响。

时间戳是通过一个整数型变量存储的,常见的位宽是 32 位 或 64 位:

  • 32 位整数:能够记录约 136 年(正负 68 年)。
  • 64 位整数:可记录的时间范围非常宽,基本可以覆盖所有时间需求。

秒计数器记录的是 UTC 时间,与不同的时区无关。

全世界所有地区的秒计数器值相同,但通过添加偏移量(时区)可以换算成当地时间。

  • UTC 的 1970 年 1 月 1 日 0:0:0 对应秒计数器为 0。
  • 北京时间(UTC+8)的 1970 年 1 月 1 日 8:0:0 对应的秒计数器值仍为 0。

img

  • 计数器值为 0 时:

    • UTC 时间:1970-1-1 0:0:0
    • 北京时间:1970-1-1 8:0:0
  • 秒计数器值为 10,000,000,000

    • UTC 时间:2001-9-9 1:46:40
    • 北京时间:2001-9-9 9:46:40
  • 秒计数器值为 1,672,588,795

    • UTC 时间:2023-1-1 15:59:55
    • 北京时间:2023-1-1 23:59:55

1.2 UTC/GMT

  1. GMT(Greenwich Mean Time,格林尼治标准时间)
    • GMT 是一种基于地球自转的时间计量系统。
    • 地球每自转一周被划分为 24 小时,时间间隔是均匀的,用来作为时间标准。
    • GMT 主要用于历史上的时间定义,现代已经逐渐被更精准的 UTC 替代。
  1. UTC(Universal Time Coordinated,协调世界时)
    • UTC 是一种基于原子钟的时间计量系统,是目前全球通用的时间标准。
    • UTC 的定义:
      • 1 秒被精确定义为:铯 133 原子基态的两个超精细能级间在零磁场下辐射 9,192,631,770 周持续的时间。
    • UTC 的调整机制:
      • 地球自转的时间并非完全均匀,地球自转一天的时间与 UTC 之间的差异可能会超过 0.9 秒。
      • 为了保持协调一致,UTC 会通过闰秒来调整时间,使其与地球自转周期保持同步。
  1. 两者的区别
    • GMT 基于地球自转,时间间隔固定,但相对不够精确。
    • UTC 基于原子钟,精准度更高,可以通过调整闰秒与地球自转周期保持一致。

1.3 时间戳转换

语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换

函数作用
time_t time(time_t*);获取系统时钟
struct tm* gmtime(const time_t*);秒计数器转换为日期时间(格林尼治时间)
struct tm* localtime(const time_t*);秒计数器转换为日期时间(当地时间)
time_t mktime(struct tm*);日期时间转换为秒计数器(当地时间)
char* ctime(const time_t*);秒计数器转换为字符串(默认格式)
char* asctime(const struct tm*);日期时间转换为字符串(默认格式)
size_t strftime(char*, size_t, const char*, const struct tm*);日期时间转换为字符串(自定义格式)

img

1. time_t time(time_t*)

获取系统当前时间的秒计数器值(Unix 时间戳)。

#include <stdio.h>
#include <time.h>int main() {time_t current_time;current_time = time(NULL); // 获取当前时间戳printf("当前时间的时间戳是:%ld\n", current_time);return 0;
}

输出示例:

当前时间的时间戳是:1672588795

2. struct tm* gmtime(const time_t*)

将秒计数器转换为 UTC 格式的日期时间。

#include <stdio.h>
#include <time.h>int main() {time_t current_time = time(NULL); // 获取当前时间戳struct tm *utc_time = gmtime(&current_time); // 转换为 UTC 时间printf("UTC 时间是:%d-%02d-%02d %02d:%02d:%02d\n",utc_time->tm_year + 1900, // 年从 1900 开始utc_time->tm_mon + 1,     // 月从 0 开始utc_time->tm_mday,utc_time->tm_hour,utc_time->tm_min,utc_time->tm_sec);return 0;
}

输出示例:

UTC 时间是:2023-01-01 16:59:55

3. struct tm* localtime(const time_t*)

将秒计数器转换为本地时间(根据时区调整)。

#include <stdio.h>
#include <time.h>int main() {time_t current_time = time(NULL); // 获取当前时间戳struct tm *local_time = localtime(&current_time); // 转换为本地时间printf("本地时间是:%d-%02d-%02d %02d:%02d:%02d\n",local_time->tm_year + 1900,local_time->tm_mon + 1,local_time->tm_mday,local_time->tm_hour,local_time->tm_min,local_time->tm_sec);return 0;
}

输出示例:

本地时间是:2023-01-01 23:59:55

4. time_t mktime(struct tm*)

将本地时间结构转换为秒计数器。

#include <stdio.h>
#include <time.h>int main() {struct tm time_info = {0};// 设置一个本地时间:2023-01-01 12:00:00time_info.tm_year = 2023 - 1900; // 年份从 1900 开始time_info.tm_mon = 0;            // 月份从 0 开始time_info.tm_mday = 1;time_info.tm_hour = 12;time_info.tm_min = 0;time_info.tm_sec = 0;time_t timestamp = mktime(&time_info); // 转换为时间戳printf("2023-01-01 12:00:00 的时间戳是:%ld\n", timestamp);return 0;
}

输出示例:

2023-01-01 12:00:00 的时间戳是:1672545600

5. char* ctime(const time_t*)

将时间戳转换为默认格式的字符串(含换行符)。

#include <stdio.h>
#include <time.h>int main() {time_t current_time = time(NULL); // 获取当前时间戳char *time_string = ctime(&current_time); // 转换为字符串printf("当前时间是:%s", time_string); // 输出字符串(带换行符)return 0;
}

输出示例:

当前时间是:Sun Jan  1 23:59:55 2023

6. char* asctime(const struct tm*)

将日期时间结构转换为默认格式的字符串(含换行符)。

#include <stdio.h>
#include <time.h>int main() {struct tm time_info = {0};// 设置一个时间结构time_info.tm_year = 2023 - 1900;time_info.tm_mon = 0;time_info.tm_mday = 1;time_info.tm_hour = 12;time_info.tm_min = 0;time_info.tm_sec = 0;char *time_string = asctime(&time_info); // 转换为字符串printf("时间是:%s", time_string); // 输出字符串(带换行符)return 0;
}

输出示例:

时间是:Sun Jan  1 12:00:00 2023

7. size_t strftime(char*, size_t, const char*, const struct tm*)

将日期时间结构转换为自定义格式的字符串。

#include <stdio.h>
#include <time.h>int main() {time_t current_time = time(NULL); // 获取当前时间戳struct tm *local_time = localtime(&current_time); // 转换为本地时间char buffer[100];// 自定义格式化:年-月-日 小时:分钟:秒strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local_time);printf("当前本地时间是:%s\n", buffer);return 0;
}

输出示例:

当前本地时间是:2023-01-01 23:59:55

2.BKP

2.1 简介

BKP 的基本功能:

  1. 存储用户数据
    • BKP 提供了一组独立的寄存器,能够存储应用程序的重要数据,例如系统状态、传感器校准参数等。
    • 在大容量和互联型产品中,BKP 提供了 42 个 16 位寄存器,可存储 84 字节数据
    • 在中容量和小容量产品中,BKP 仅提供 20 字节数据寄存器
  1. 掉电保护
    • BKP 工作在备份域(Backup Domain)中,由 VBAT 供电。
    • 即使主电源 VDD 被切断,BKP 寄存器的数据仍然不会丢失。
    • 这种特性非常适合存储掉电后仍需保存的数据,例如:
      • 实时时钟(RTC)配置。
      • 防篡改事件标志。
      • 系统重要的用户数据。
  1. 复位保护
    • 当系统处于待机模式被唤醒时,或者发生 系统复位电源复位 时,备份寄存器的数据仍然保持不变。
    • 只有特定的备份域复位操作(通过设置 RCC_BDCR 寄存器的 BDRST 位)才能清除 BKP 数据。

BKP 控制寄存器:

备份寄存器的控制寄存器(BKP_CR)用于管理以下功能:

  1. 防篡改检测
    • BKP 控制寄存器支持 防篡改检测(Tamper Detection) 功能。
    • 当检测到未授权的访问或数据篡改时,可以触发中断以通知系统。
    • 具体防篡改功能包括:
      • 数据被篡改时产生中断。
      • 清除备份寄存器数据。
  1. RTC 校准功能
    • BKP 控制寄存器可以配合 RTC 校准功能使用。
    • 用于存储 RTC 校验值、调节 RTC 校准值,并提供时钟输出到 PC13 引脚。
  1. 支持多种输出功能
    • BKP 控制寄存器能够控制在 PC13 引脚上输出不同信号:
      • RTC 校准时钟。
      • RTC 闹钟脉冲。
      • RTC 秒脉冲。

如何访问 BKP 寄存器:

默认情况下,备份域和备份寄存器被保护,无法直接访问。以下是访问流程:

  1. 使能时钟
    • 设置 RCC_APB1ENR 寄存器的 PWREN 位BKPEN 位,打开电源和后备接口的时钟。
  1. 解除写保护
    • 设置电源控制寄存器(PWR_CR)的 DBP 位(Disable Backup Domain Write Protection)。
    • 只有在该位被置位后,才能对备份寄存器和 RTC 进行写操作。
  1. 备份域复位(可选):
    • 如果需要清空备份域的数据(包括 RTC 和 BKP 寄存器),可以设置 RCC_BDCR 寄存器的 BDRST 位

BKP 的应用场景:

BKP 寄存器的主要应用场景如下:

  1. 存储关键数据
    • 可以存储掉电后需要保留的重要数据,例如:
      • RTC 时间。
      • 校准参数。
      • 加密密钥。
      • 系统配置。
  1. 防篡改检测
    • 用于检测是否存在未授权的数据访问或修改。
    • 一旦检测到篡改,可以通过中断通知系统,同时清除备份寄存器中的数据。
  1. RTC 校准
    • 配合 RTC 使用,用于存储 RTC 校验值,并在 PC13 引脚输出校准信号、闹钟脉冲或秒脉冲。
  1. 数据备份
    • 当系统进入低功耗或待机模式时,BKP 是一种可靠的数据存储方案。

BKP 的硬件资源:

寄存器资源

在大容量和互联型产品中,BKP 包括:

  • 42 个 16 位的备份寄存器(BKP_DR1 到 BKP_DR42),每个寄存器可以存储 2 字节,共计 84 字节。
  • BKP 控制寄存器,用于配置防篡改检测和 RTC 校准功能。
PC13 引脚功能

PC13 引脚在 BKP 配置中支持输出以下信号:

  • RTC 校准时钟(RTC_CALIB_CLK)
  • RTC 闹钟脉冲(RTC_ALARM)
  • RTC 秒脉冲(RTC_SECOND)

使用 BKP 的注意事项

  1. 写保护机制
    • 默认情况下,备份域和 BKP 寄存器是受保护的,必须按照正确的流程解锁才能进行写操作。
    • 避免意外写入或修改。
  1. VBAT 电源支持
    • 确保在主电源断电时,VBAT 能够正常供电,以保证 BKP 数据不会丢失。
  1. 防篡改检测的正确配置
    • 如果使用防篡改检测功能,应正确设置中断处理程序,以防止误报或数据丢失。
  1. 低功耗模式的应用
    • 在进入待机或低功耗模式时,可以将重要数据写入 BKP,以便唤醒后能够快速恢复状态。

2.2 基本结构

img

3.RTC时钟

3.1 简介

RTC(Real Time Clock,实时时钟)是一种独立的定时器模块,用于提供时间和日历功能。它包含一个连续计数的计数器,在适当的软件配置下,能够提供精确的时间跟踪和日期维护功能。RTC 模块特别适合需要低功耗、掉电保护的嵌入式应用场景。

RTC 是嵌入式系统(如 STM32 微控制器)中非常重要的功能模块之一,其设计允许在系统复位或待机模式唤醒后保持时间和设置不变。它在后备域(Backup Domain)内工作,利用备用电池(VBAT)维持供电,即使主电源关闭,RTC 的计时功能仍然能正常运行。


3.1.1 RTC 的主要特性

\1. 灵活的计时功能

  • RTC 模块提供一个 32 位的连续计数器,用于测量较长的时间段。
  • 通过软件可以设置和修改计数器的值,以重新定义当前的时间和日期。

\2. 可编程的预分频器

  • RTC 允许配置一个可编程的预分频系数,最高可以分频到 2^20
  • 通过调整分频系数,可以精确地设置 RTC 的时钟频率,以满足不同的时间基准需求。

\3. 独立的时钟源

RTC 模块支持以下三种时钟源,具体选择由硬件设计和应用需求决定:

  1. HSE(High-Speed External)时钟
    • 高速外部振荡器时钟(HSE)可以通过除以 128 的方式作为 RTC 时钟源。
    • 高速时钟一般供内部的应用程序和主要外设使用
  1. LSE(Low-Speed External)振荡器
    • 低速外部振荡器时钟(通常为 32.768 kHz 晶体),提供高稳定性,非常适合 RTC。
    • 低速时钟主要给看门狗和RTC时钟使用
  1. LSI(Low-Speed Internal)振荡器
    • 低速内部振荡器(内部 40 kHz 振荡器),功耗较低,但精度略逊于 LSE。

注意:RTC 的时钟频率必须低于 APB1 接口时钟(PCLK1)的四分之一。

\4. 多种复位类型

RTC 支持两种不同类型的复位:

  1. 系统复位
    • APB1 接口由系统复位控制。
  1. 后备域复位
    • RTC 核心(包括预分频器、闹钟、计数器和分频器)仅受后备域复位的影响。通过设置 RCC_BDCR 寄存器的 BDRST 位,可以复位 RTC 核心。

\5. 多种中断功能

RTC 提供 3 种专门的中断功能,能够实现丰富的时间事件管理:

  1. 闹钟中断
    • RTC 可以配置一个软件可编程的闹钟,触发闹钟中断,常用于定时唤醒或事件提醒。
  1. 秒中断
    • 可产生一个周期性中断信号,周期最长为 1 秒,适合用于定时任务。
  1. 溢出中断
    • 当 RTC 的 32 位计数器溢出(从最大值回滚到 0)时触发,指示计数器循环完成。

\6. 持久性

  • RTC 位于备份域中,由备用电池(VBAT)供电。
  • 即使主电源 VDD 断开,RTC 的计数器和设置仍能正常运行。
  • 系统复位或待机模式唤醒后,RTC 的配置和时间数据保持不变。

img

4-16 MHz HSE OSC:外部的4-16MHz高速石英晶体振荡器,也就是晶振,一般都是接8MHz。

  • 需要先进性128的分频,后续的分频器在进行适当的分频,就可以输出1Hz的频率信号给计数器

LSE OSC 32.768 kHz:外部的 32.768 kHz(215)的低速晶振,一般是给RTC使用的(最常用

LSI RC 40 KHz:内部的40 KHz低速RC晶振,可以提供给RTC,但一般是备用方案,给看门狗提供时钟的情况比较多

3.1.2 访问 RTC 的流程

默认情况下,RTC 和后备寄存器的访问被禁止,这是为了防止意外的写操作对关键数据造成破坏。以下步骤可以解锁 RTC 和后备寄存器的访问权限:

\1. 使能电源和后备接口时钟

通过设置 RCC_APB1ENR 寄存器的以下两位:

  • PWREN 位:使能电源模块。
  • BKPEN 位:使能后备接口时钟。

\2. 解除写保护

设置 PWR_CR 寄存器的 DBP 位(Disable Backup Domain Write Protection)

  • 解除写保护后,可以对 RTC 和后备寄存器进行读写操作。

\3. 配置 RTC 时钟源

在 RCC_BDCR 寄存器中选择 RTC 的时钟源,常见配置为:

  • 设置 RTCSEL 位 选择时钟源(LSE、LSI 或 HSE)。
  • 通过设置 RTCEN 位 启用 RTC。

\4. 后备域复位(可选)

如果需要重置 RTC 的配置,可以通过设置 RCC_BDCR 寄存器的 BDRST 位 触发后备域复位。


3.1.3 RTC 的典型应用

\1. 时间和日历功能

RTC 的主要应用是提供精确的时间和日期跟踪功能。结合 32 位计数器和软件支持,可以实现年、月、日、时、分、秒等信息的完整计算和管理。

\2. 闹钟功能

RTC 支持配置闹钟时间,当达到设定时间时,触发闹钟中断。常用于:

  • 定时唤醒嵌入式系统。
  • 提供定时提醒功能。

\3. 周期性事件管理

RTC 的秒中断功能可以生成周期性信号,适合用于:

  • 定时任务。
  • 数据采集的时间基准。

\4. 超低功耗场景

RTC 模块在主电源关闭或进入待机模式时,依然可以通过备用电池工作,适合需要长时间低功耗运行的应用场景。

\5. 数据采集和日志记录

RTC 提供稳定的时间基准,可以用于时间戳记录和数据采集。


3.1.4 RTC 的优势

  1. 低功耗:RTC 工作在低功耗模式下,可以通过 VBAT 供电,适合掉电保护应用。
  2. 独立性:RTC 独立于主系统,即使 MCU 复位或掉电,时间信息也能保持不变。
  3. 多功能性:支持时间、日历、闹钟、秒中断和周期性事件管理。
  4. 高精度:结合 LSE 或 HSE 时钟源,可以提供高精度的时间跟踪。

3.2 框图(详细结构)

img

RTC(实时时钟)模块位于 后备区域(Backup Domain) 中,依赖于备用电池(VBAT)供电,即使主电源关闭也可以保持运行。框图主要由以下几个模块组成:

  • 时钟输入与分频模块
  • RTC 可编程计数器
  • 控制寄存器与中断控制
  • 待机唤醒功能

这些模块协同工作以实现 RTC 的时间计数、闹钟、秒中断和溢出中断等功能。

(1) APB1 总线与接口

  • RTC 通过 APB1 总线(Advanced Peripheral Bus 1)连接到系统。

  • APB1 接口是 RTC 的通信接口,它允许 MCU(主控制器)通过寄存器对 RTC 进行配置和读取。

  • 注意:

    • APB1 接口的时钟频率 必须高于 RTC 时钟频率的 4 倍,确保数据通信的稳定性。

(2) RTC 时钟源(RTCCLK)

  • RTC 时钟源 RTCCLK 是 RTC 模块运行的核心时钟信号。支持三种时钟源选择:

    • HSE(高速外部时钟)/128:高精度晶振时钟。
    • LSE(低速外部振荡器):通常为 32.768 kHz 晶体,精度高、功耗低。
    • LSI(低速内部振荡器):40 kHz 内部振荡器,功耗低,但精度稍差。
  • RTC 时钟源通过 RCC 模块配置。

(3) RTC 预分频器

  • 预分频器(RTC Prescaler)是 RTC 模块的重要组成部分,用于将高频时钟(RTCCLK)分频为更低的频率,适合 RTC 计数器使用。

  • 功能:

    • 通过寄存器 RTC_PRL(重载值寄存器)RTC_DIV(分频器寄存器) 设置分频值。
    • 比如,当输入时钟为 32.768 kHz,预分频器设置为 32767 时,每秒触发一次分频输出(1 Hz)。也就是PRL设置为32767(固定的),DIV初值可以设置为0,来一个输入脉冲,DIV-1,溢出,输出一个输出脉冲,同时DIV被重载为32727;后面每来一个输入脉冲,DIV的值减1,直到减到0时,再来一个输入脉冲,DIV溢出,输出一个脉冲信号,同时DIV继续回到32767。实现每来一个32768脉冲的时钟,输出的是1脉冲的时钟,也就是32.768 kHz被分频为1Hz
    • 输出时钟作为 RTC 计数器(RTC_CNT) 的输入时钟。

(4) RTC 可编程计数器

  • RTC 计数器(RTC_CNT) 是一个 32 位的递增计数器,用于存储当前的时间值。

  • 工作原理:

    • RTC_CNT 每秒递增 1(当预分频器设置为 1 秒时基)。
    • 软件可以读取 RTC_CNT 的值来获取当前的时间戳。
    • 计数器可以被设置为任意值,以实现时间的初始化或校准。

(5) 闹钟功能

  • RTC 提供 RTC_ALR(闹钟寄存器),用户可以通过设置闹钟时间与 RTC_CNT 的值进行比较。

  • 当 RTC_CNT 的值与 RTC_ALR 相等时:

    • 触发 RTC_Alarm 中断
    • 闹钟事件可以用于唤醒系统或执行定时任务。

(6) RTC 控制寄存器(RTC_CR)

  • RTC_CR 是 RTC 的核心配置寄存器,用于控制模块功能和中断管理。

  • 主要功能:

    • RTC_Second 中断(SECF 和 SECIE)
      • 每秒触发一个中断信号,用于实现周期性任务。
    • RTC_Overflow 中断(OWF 和 OWIE)
      • 当 RTC_CNT 溢出(从最大值回到 0)时触发。但一般是不会触发的,因为这里的CNT定义的是一个32位的无符号数,到2106年的时候才会溢出(时间戳)
    • RTC_Alarm 中断(ALRF 和 ALRIE)
      • 当 RTC_CNT 等于 RTC_ALR 的值时触发。
    • 通过 NVIC 中断控制器 管理中断优先级和响应。

(7) 中断和待机模式唤醒

  • RTC 的中断信号(RTC_Alarm、RTC_Second、RTC_Overflow)可以触发系统中断,通过 NVIC 中断控制器 传递给 CPU 处理。

  • 唤醒功能:

    • RTC_Alarm 信号还可以通过 WKUP pin(唤醒引脚) 唤醒系统,从待机模式恢复到正常运行模式。
    • 在低功耗应用中,RTC 是常用的唤醒触发器。

(8) 后备区域与掉电保护

  • RTC 位于后备区域(Backup Domain),由备用电池(VBAT)供电。
  • 即使主电源关闭,RTC 的计数器和寄存器依然能正常运行。
  • 在掉电或复位后,通过 VBAT 保持 RTC 的设置和当前时间不丢失。

3.3 RTC 的基本结构

img

(1) 初始化 RTC

  1. 选择 RTC 时钟源:
    • 配置 RCC 模块,选择 RTCCLK 的来源(LSE、LSI 或 HSE/128)。
  1. 配置预分频器:
    • 设置 RTC_PRL 和 RTC_DIV,确保 RTC_CNT 每秒递增 1(或其他所需频率)。
  1. 解除写保护:
    • 通过 PWR_CR 的 DBP 位解除后备域写保护,允许修改 RTC 的配置。
  1. 启动 RTC:
    • 启用 RTC_CR 寄存器中的相关位,开始 RTC 计数。

(2) 读取时间

  • 通过 APB1 接口读取 RTC_CNT 的值,获取当前时间。

(3) 配置闹钟

  • 设置 RTC_ALR 寄存器的值为目标时间。
  • 启用 RTC_ALR 中断,等待闹钟事件触发。

(4) 响应中断

  • 当 RTC_Alarm、RTC_Second 或 RTC_Overflow 中断触发时,系统可以通过 NVIC 响应中断信号,执行相关操作。

(5) 唤醒系统

  • 在低功耗模式下,RTC_Alarm 信号可以通过 WKUP pin 唤醒系统。

3.4 硬件电路

img

img

3.5 使用注意事项

3.5.1 使能对 BKP 和 RTC 的访问

RTC 位于 后备区域(Backup Domain),默认情况下对其访问是受限制的。这是为了保护后备区域(包括 RTC 和 BKP 寄存器)数据免于意外的写操作。要使能对 RTC 和后备区域的访问,需要执行以下步骤:

  1. 使能 PWR 和 BKP 的时钟:

操作:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    • 设置 RCC_APB1ENR 寄存器的 PWREN 和 BKPEN 位
      • PWREN 位:使能电源模块(PWR)的时钟。
      • BKPEN 位:使能后备区域(BKP)的时钟。
  1. 解除后备区域的写保护:

操作:

PWR_BackupAccessCmd(ENABLE);
    • 设置 PWR_CR 寄存器的 DBP 位(Disable Backup Domain Write Protection)。
    • 在解除写保护后,允许对 RTC 和后备区域进行写操作。

3.5.2 同步寄存器(RSF)状态

在某些情况下,RTC 的 APB1 接口可能处于禁止状态(如系统启动后第一次访问 RTC),此时需要等待 RTC 同步完成,才能正常读取 RTC 寄存器的值。

  1. 检查 RTC_CRL 的 RSF 位:
    • RSF 位(寄存器同步标志位):指示 RTC 是否已经与 APB1 总线同步。
    • 如果 RSF 位未被置位(同步未完成),则软硬件操作必须等待 RSF 位被置位后才能继续。
  1. 清除 RSF 标志:

操作:

while (RTC_GetFlagStatus(RTC_FLAG_RSF) == RESET); // 等待同步完成
    • 软件必须清除 RSF 位,等待同步完成。
    • 确认同步完成后,才能读取 RTC 的计数器值。

img


3.5.3 进入 RTC 配置模式

要对 RTC 进行配置(如设置计数器、预分频器或闹钟寄存器的值),必须让 RTC 进入 配置模式(Configuration Mode)

  1. 设置 CNF 位:
    • 通过设置 RTC_CRL 寄存器的 CNF 位,进入配置模式。
    • 配置完成后,必须清除 CNF 位,退出配置模式。
  1. 可配置的寄存器:
    • RTC_PRL(预分频器寄存器):用于配置 RTC 的时钟分频值。
    • RTC_CNT(计数器寄存器):设置 RTC 的当前计数值。
    • RTC_ALR(闹钟寄存器):设置 RTC 的闹钟值。
  1. 操作流程:

示例代码:

RTC_EnterConfigMode();            // 进入配置模式
RTC_SetPrescaler(32767);          // 设置预分频器值
RTC_SetCounter(0);                // 设置计数器值
RTC_SetAlarm(3600);               // 设置闹钟值
RTC_ExitConfigMode();             // 退出配置模式
    • 进入配置模式,修改寄存器值,退出配置模式。

3.5.4 写操作完成前必须等待

RTC 的所有写操作都是异步完成的,写操作可能需要一定时间。要确保写入的值生效,必须等待上一次写操作完成后,再进行下一次写操作。

  1. 检查 RTOFF 状态:
    • RTOFF 位(写完成标志位):当 RTOFF 位为 1 时,表示 RTC 的寄存器写操作已经完成,可以进行下一次写操作。
    • 在修改任何 RTC 寄存器前,必须先检查 RTOFF 位为 1。
  1. 操作:

示例代码:

while (RTC_GetFlagStatus(RTC_FLAG_RTOFF) == RESET); // 等待写完成
    • 每次写操作完成后,检查 RTOFF 位,确保写入成功。

3.5.5 概括

关键操作流程
  1. 使能 PWR 和 BKP 的时钟。
  2. 解除写保护(设置PWR_CR的DBP,使能对BKP和RTC的访问)。
  3. 检查同步状态(RSF 位)。若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1 — 也就是RTC_WaitForSynchro函数,可以去看其定义就可以发现是对RSF标志位进行设置的
  4. 进入配置模式(设置 CNF 位)。
  5. 修改 RTC 寄存器的值:
    • RTC_PRL(预分频器寄存器)
    • RTC_CNT(计数器寄存器)
    • RTC_ALR(闹钟寄存器)
  1. 确保写操作完成(检查 RTOFF 位,仅当RTOFF状态位是1时,才可以写入RTC寄存器)。对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器 ---- 也就是RTC_WaitForLastTask函数,去看其函数定义可以发现其就是对RTOFF状态进行循环查询是否处于更新中
  2. 退出配置模式(清除 CNF 位)。
可能的错误操作
  • 未使能时钟: 如果 PWR 和 BKP 的时钟未使能,将无法访问 RTC 和后备寄存器。
  • 未解除写保护: 如果未设置 DBP 位,则无法对 RTC 和后备寄存器进行写操作。
  • 未等待同步完成: 如果 RSF 位未被置位而直接读取寄存器,可能会导致读取错误。
  • 未等待写完成: 如果在 RTOFF 位清零时修改寄存器,可能会覆盖之前的写操作。
优化建议
  • 在代码中加入足够的错误检查,确保每一步操作的状态都满足要求。
  • RTC 的配置流程较为复杂,建议封装成函数,减少出错几率。
#include "stm32f10x.h"void RTC_Init(void) {// 1. 使能 PWR 和 BKP 的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);// 2. 解除写保护PWR_BackupAccessCmd(ENABLE);// 3. 选择 LSE 作为 RTC 时钟源RCC_LSEConfig(RCC_LSE_ON);while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); // 等待 LSE 就绪// while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET); // 等待 LSE 就绪RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);// 4. 启用 RTC 时钟RCC_RTCCLKCmd(ENABLE);// 5. 等待 RTC 同步完成RTC_WaitForSynchro();RTC_WaitForLastTask();			  //等待上一次操作完成,确保写操作完成// 6. 配置 RTC// RTC_EnterConfigMode();            // 进入配置模式,其实也可以不用写,下面的RTC_SetPrescaler函数其实内部就调用了RTC_SetPrescaler(32767);          // 设置预分频器(1 秒为基准)RTC_WaitForLastTask();            // 确保写操作完成RTC_SetCounter(0);                // 设置计数器初始值为 0,根据设置的分频后的时钟,会以1s的时间间隔开始自增RTC_WaitForLastTask();            // 确保写操作完成// RTC_ExitConfigMode();             // 退出配置模式,和RTC_EnterConfigMode同理
}int main(void) {RTC_Init();                       // 初始化 RTCwhile (1) {uint32_t time = RTC_GetCounter(); // 获取当前时间printf("当前时间:%lu 秒\n", time);}
}

4.实验

4.1 BKP

📎12-1 读写备份寄存器.zip

img

hardware:

  • 📎Key.c📎Key.h📎OLED.c📎OLED.h📎OLED_Font.h

User

  • 📎main.c ---- 主要看该文件中的函数使用

4.2 RTC

📎12-2 实时时钟.zip

img

Hardware:

  • 📎OLED.c📎OLED.h📎OLED_Font.h

User:

  • 📎main.c

System:

  • 📎MyRTC.c📎MyRTC.h

具体的函数去看函数手册中的:

  • img
  • img

5.扩展

STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。

  • HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时 钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。WDG
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

系统时钟SYSCLK可来源于三个时钟源:

  • HSI振荡器时钟
  • HSE振荡器时钟
  • PLL时钟

重要的时钟有:

  • SYSCLK(系统时钟)
  • AHB总线时钟
  • APB1总线时钟(低速): 速度最高36MHz
  • APB2总线时钟(高速): 速度最高72MHz
  • PLL时钟

相关文章:

  • TCPIP详解 卷1协议 八 ICMPv4和ICMPv6 Internet控制报文协议
  • 深入掌握CSS定位:构建精密布局的核心技术
  • 第二章、物理层
  • 开发环境(Development Environment)
  • 【SSM-Mybatis(一)】java持久层框架-Mybatis!本文涵盖介绍Mybatis和基本使用,分析Mybatis核心配置文件
  • 豆瓣电影Top250数据工程实践:从爬虫到智能存储的技术演进(含完整代码)
  • 【Ansible】之inventory主机清单
  • 麒麟 v10 cgroup v1 切换 cgroup v2
  • 上海海关特展:二维码讲解“外来入侵物种”的危害!
  • 小智AI客户端使用测试(Python)
  • 让 - 艾里克・德布尔与斯普林格出版公司:科技变革下的出版业探索
  • 韩国直邮新纪元:Coupang多语言支持覆盖38国市场
  • 服务网格的“解剖学” - 控制平面与数据平面
  • VIC-2D 7.0 为平面样件机械试验提供全视野位移及应变数据软件
  • 1.3 极限
  • 生成对抗网络(GAN)深度解析:理论、技术与应用全景
  • 通用RAG:通过路由模块对多源异构知识库检索生成问答思路
  • 我用Deepseek + 亮数据爬虫神器 1小时做出輿情分析器
  • 【Java学习笔记】多态数组
  • HLS图像处理:从算法到硬件的创新加速之旅
  • 男子发寻母视频被警方批评教育,律师:发寻亲信息是正当行为
  • 文学花边|对话《借命而生》原著作者石一枫:我给剧打90分
  • 来伊份:已下架涉事批次蜜枣粽产品,消费者可获额外补偿,取得实物后进一步分析
  • 石家庄推动城市能级与民生福祉并进
  • 何立峰:中方坚定支持多边主义和自由贸易,支持世界贸易组织在全球经济治理中发挥更大作用
  • 中铁房地产24.7亿元竞得上海松江新城宅地,溢价率20.42%