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時鐘

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79585.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79585.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79585.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android學習總結之算法篇八(二叉樹和數組)

路徑總和 import java.util.ArrayList; import java.util.List;// 定義二叉樹節點類 class TreeNode {int val;TreeNode left;TreeNode right;// 構造函數&#xff0c;用于初始化節點值TreeNode(int x) {val x;} }public class PathSumProblems {// 路徑總和 I&#xff1a;判…

Scala和Spark的介紹

Scala 1. Slaca的發展過程 由洛桑聯邦理工學院的馬丁 奧德斯在 2001 年基于 Funnel 的工作開始設計&#xff0c;設計初衷是想集成面向對象編程和函數式編程的各種特性。 Scala 是一種純粹的面向對象的語言&#xff0c;每個值都是對象。 Scala 也是一種函數式語言&#xff0…

配置Hadoop集群環境-使用腳本命令實現集群文件同步

在 Hadoop 集群環境中&#xff0c;確保各節點配置文件一致至關重要。以下是使用 rsync 結合 SSH 實現集群文件同步的腳本方案&#xff0c;支持批量同步文件到所有節點&#xff1a; 1. 前提條件 所有節點已配置 SSH 免密登錄主節點&#xff08;NameNode&#xff09;能通過主機…

Redis能保證數據不丟失嗎之RDB

有了AOF為什么還需要RDB? 上一篇我們介紹了Redis AOF持久化策略。Redis能保證數據不丟失嗎之AOF AOF雖然能實現持久化,但由于AOF恢復數據的時候是一條一條命令重新執行的,但數據量大的時候,Redis數據恢復的時間就會很久,這會導致Redis在重啟的時候,有一大段時間的不可用…

AI浪潮下的藝術突圍戰:對話《名人百科數據庫》執行主編劉鑫煒

當AI生成的畫作在國際賽事中摘冠&#xff0c;當算法推薦主導藝術傳播路徑&#xff0c;技術革命正以前所未有的速度重塑藝術生態。我們獨家專訪深耕藝術推廣領域的劉鑫煒主編&#xff0c;探討當代藝術家在智能時代的生存法則。 圖為《名人百科數據庫》執行主編劉鑫煒 技術重構創…

Python 實現失敗重試功能的幾種方法

更多內容請見: python3案例和總結-專欄介紹和目錄 文章目錄 方法 1:手動 `while` 循環 + 異常捕獲方法 2:使用 `tenacity` 庫(推薦)方法 3:使用 `retrying` 庫(舊版,已停止維護)方法 4:`requests` 自帶重試(適用于 HTTP 請求)方法 5:自定義裝飾器(靈活控制)方法…

2025年滲透測試面試題總結-滲透測試紅隊面試七(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 滲透測試紅隊面試七 一百八十一、Shiro漏洞類型&#xff0c;721原理&#xff0c;721利用要注意什么&am…

Unity動畫系統使用整理 --- Playable

??Playable API?? 是一個強大的工具&#xff0c;用于更靈活地控制動畫、音頻、腳本等時間軸內容的播放和混合。它提供了比傳統 Animator 更底層、更可控的方式管理時間軸行為&#xff0c;尤其適合復雜動畫邏輯或動態內容組合的場景。 優點&#xff1a; 1.Playables API 支…

基于STM32、HAL庫的BMP390L氣壓傳感器 驅動程序設計

一、簡介: BMP390L 是 Bosch Sensortec 生產的一款高精度氣壓傳感器,專為需要精確測量氣壓和海拔高度的應用場景設計。BMP390L 具有更低的功耗、更高的精度和更快的響應速度。 二、硬件接口: BMP390L 引腳STM32L4XX 引腳說明VDD3.3V電源GNDGND地SCLPB6 (I2C1 SCL)I2C 時鐘線…

Arduino快速入門

Arduino快速入門指南 一、硬件準備 選擇開發板&#xff1a; 推薦使用 Arduino UNO&#xff08;兼容性強&#xff0c;適合初學者&#xff09;&#xff0c;其他常見型號包括NANO&#xff08;體積小&#xff09;、Mega&#xff08;接口更多&#xff09;。準備基礎元件&#xff1a…

破解 Qt QProcess 在 Release 模式下的“卡死”之謎

在使用 Qt 的 QProcess 以調用外部 ffmpeg/ffprobe 進行音視頻處理時&#xff0c;常見的工作流程是&#xff1a; gatherParams&#xff1a;通過 ffprobe 同步獲取媒體文件的參數&#xff08;分辨率、采樣率、聲道數、碼率等&#xff09;。 reencode&#xff1a;逐個文件調用 f…

MySQL 中 UPDATE 結合 SELECT 和 UPDATE CASE WHEN 的示例

概述 以下是 MySQL 中 UPDATE 結合 SELECT 和 UPDATE CASE WHEN 的示例&#xff1a; 一、UPDATE 結合 SELECT&#xff08;跨表更新&#xff09; 場景&#xff1a;根據 orders 表中的訂單總金額&#xff0c;更新 users 表中用戶的 total_spent 字段。 -- 創建測試表 CREATE T…

【MCP】魔搭社區MCP服務(高德地圖、everything文件搜索)

【MCP】魔搭社區MCP服務&#xff08;高德地圖、everything文件搜索&#xff09; 1、上手使用2、環境配置&#xff08;1&#xff09;cherry-studio配置&#xff08;2&#xff09;添加魔搭大模型服務&#xff08;如果已經設置了其他大模型服務&#xff0c;可跳過&#xff09;&…

MapReduce 的工作原理

MapReduce 是一種分布式計算框架&#xff0c;用于處理和生成大規模數據集。它將任務分為兩個主要階段&#xff1a;Map 階段和 Reduce 階段。開發人員可以使用存儲在 HDFS 中的數據&#xff0c;編寫 Hadoop 的 MapReduce 任務&#xff0c;從而實現并行處理1。 MapReduce 的工作…

MCU開啟浮點計算FPU

FPU 測試 1. FPU 簡介2. 協處理器控制寄存器&#xff08;CPACR&#xff09;3. 開啟FPU4. 驗證FPU&#xff08;Julia 分形實驗&#xff09; 1. FPU 簡介 FPU 即浮點運算單元&#xff08;Float Point Unit&#xff09;。浮點運算&#xff0c;對于定點 CPU&#xff08;沒有 FPU 的…

進程相關面試題20道

一、基礎概念與原理 1.進程的定義及其與程序的本質區別是什么&#xff1f; 答案&#xff1a;進程是操作系統分配資源的基本單位&#xff0c;是程序在數據集合上的一次動態執行過程。核心區別&#xff1a;? 動態性&#xff1a;程序是靜態文件&#xff0c;進程是動態執行實例…

React Hooks 精要:從入門到精通的進階之路

Hooks 是 React 16.8 引入的革命性特性,它讓函數組件擁有了類組件的能力。以下是 React Hooks 的詳細使用指南。 一、基礎 Hooks 1. useState - 狀態管理 import { useState } from react;function Counter() {const [count, setCount] = useState(0); // 初始值為0return …

springboot3+vue3融合項目實戰-大事件文章管理系統-更新用戶頭像

大致分為三步 首先在usercontroller里面加入方法 PatchMapping ("/updateAvatar")public Result upadateAvatar(RequestParam URL String avatarUrl){userService.updateAvater(avatarUrl);return Result.success();}url注解能驗證傳入的url是不是合法的&#xff0c…

Mosaic數據增強技術

Mosaic 數據增強技術是一種在計算機視覺領域廣泛應用的數據增強方法。下面是Mosaic 數據增強技術原理的詳細介紹 一、原理 Mosaic 數據增強是將多張圖像&#xff08;通常是 4 張&#xff09;按照一定的規則拼接在一起&#xff0c;形成一張新的圖像。在拼接過程中&#xff0c;會…

Git安裝教程及常用命令

1. 安裝 Git Bash 下載 Git 安裝包 首先&#xff0c;訪問 Git 官方網站 下載適用于 Windows 的 Git 安裝包。 安裝步驟 啟動安裝程序&#xff1a;雙擊下載的 .exe 文件&#xff0c;啟動安裝程序。選擇安裝選項&#xff1a; 安裝路徑&#xff1a;可以選擇默認路徑&#xff0…