第12章 RTC介绍及应用

第十二章 RTC介绍及应用

1. RTC简介

STM32F407 的实时时钟(RTC)是一个独立的定时器。 STM32 的 RTC 模块拥有一组连续计数的计数器,在相对应的软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统的当前时间和日期。

RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变,只要后备区域供电正常,那么 RTC 将可以一直运行。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前,先要取消备份区域(BKP)写保护。

2. RTC使用示例

本实验通过 LCD 显示 RTC 时间,并可以通过 usmart 设置 RTC 时间,从而调节时间,或设置 RTC 闹钟,还可以写入或者读取 RTC 后备区域 SRAM。 LED0 闪烁,提示程序运行。

2.1 相关参数宏定义

#ifndef __RTC_H
#define __RTC_H

#include "sys.h"
#include "stm32f4xx_hal.h"
#include <stdint.h>

//================= 用户配置区 ===================
#define RTC_DEFAULT_YEAR       20
#define RTC_DEFAULT_MONTH      4
#define RTC_DEFAULT_DATE       22
#define RTC_DEFAULT_WEEKDAY    3
#define RTC_BACKUP_FLAG_ADDR   RTC_BKP_DR0   // 备份寄存器0地址
#define RTC_BACKUP_LSE_FLAG    0x5050
#define RTC_BACKUP_LSI_FLAG    0x5051
// =============================================

#ifdef __cplusplus
extern "C" {
#endif

void rtc_write_bkr(uint32_t bkrx, uint32_t data);
uint32_t rtc_read_bkr(uint32_t bkrx);
HAL_StatusTypeDef rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec, uint8_t ampm);
HAL_StatusTypeDef rtc_set_date(uint8_t year, uint8_t month, uint8_t date, uint8_t week);
void rtc_get_time(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *ampm);
void rtc_get_date(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *week);
uint8_t rtc_get_week(uint16_t year, uint8_t month, uint8_t day);
uint8_t rtc_init(void);

void rtc_set_alarm(uint8_t week, uint8_t hour, uint8_t min, uint8_t sec);
void rtc_set_wakeup(uint8_t wksel, uint16_t cnt);

extern volatile uint8_t rtc_alarm_flag;
extern volatile uint8_t rtc_wakeup_flag;

#ifdef __cplusplus
}
#endif

#endif /* __RTC_H */

2.2 RTX备份寄存器操作

/**
 * @brief  写RTC备份寄存器
 */
void rtc_write_bkr(uint32_t bkrx, uint32_t data)
{
    HAL_PWR_EnableBkUpAccess();
    HAL_RTCEx_BKUPWrite(&rtc_handle, bkrx, data);
}

/**
 * @brief  读RTC备份寄存器
 */
uint32_t rtc_read_bkr(uint32_t bkrx)
{
    return HAL_RTCEx_BKUPRead(&rtc_handle, bkrx);
}

2.3 设置RTC参数

/**
 * @brief  设置RTC时间
 * @note   ampm: RTC_HOURFORMAT12_AM / RTC_HOURFORMAT12_PM / RTC_HOURFORMAT24
 */
HAL_StatusTypeDef rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec, uint8_t ampm)
{
    RTC_TimeTypeDef rtc_time_handle = {0};
    rtc_time_handle.Hours = hour;
    rtc_time_handle.Minutes = min;
    rtc_time_handle.Seconds = sec;
    rtc_time_handle.TimeFormat = ampm;
    rtc_time_handle.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    rtc_time_handle.StoreOperation = RTC_STOREOPERATION_RESET;
    return HAL_RTC_SetTime(&rtc_handle, &rtc_time_handle, RTC_FORMAT_BIN);
}

/**
 * @brief  设置RTC日期
 */
HAL_StatusTypeDef rtc_set_date(uint8_t year, uint8_t month, uint8_t date, uint8_t week)
{
    RTC_DateTypeDef rtc_date_handle = {0};
    rtc_date_handle.Date = date;
    rtc_date_handle.Month = month;
    rtc_date_handle.WeekDay = week;
    rtc_date_handle.Year = year;
    return HAL_RTC_SetDate(&rtc_handle, &rtc_date_handle, RTC_FORMAT_BIN);
}

/**
 * @brief  获取RTC时间
 */
void rtc_get_time(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *ampm)
{ 
    RTC_TimeTypeDef rtc_time_handle;
    HAL_RTC_GetTime(&rtc_handle, &rtc_time_handle, RTC_FORMAT_BIN);
    *hour = rtc_time_handle.Hours;
    *min = rtc_time_handle.Minutes;
    *sec = rtc_time_handle.Seconds;
    *ampm = rtc_time_handle.TimeFormat;
}

2.4 获取RTC参数

/**
 * @brief  获取RTC时间
 */
void rtc_get_time(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *ampm)
{ 
    RTC_TimeTypeDef rtc_time_handle;
    HAL_RTC_GetTime(&rtc_handle, &rtc_time_handle, RTC_FORMAT_BIN);
    *hour = rtc_time_handle.Hours;
    *min = rtc_time_handle.Minutes;
    *sec = rtc_time_handle.Seconds;
    *ampm = rtc_time_handle.TimeFormat;
}

/**
 * @brief  获取RTC日期
 */
void rtc_get_date(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *week)
{
    RTC_DateTypeDef rtc_date_handle;
    HAL_RTC_GetDate(&rtc_handle, &rtc_date_handle, RTC_FORMAT_BIN);
    *year = rtc_date_handle.Year;
    *month = rtc_date_handle.Month;
    *date = rtc_date_handle.Date;
    *week = rtc_date_handle.WeekDay;
}

/**
 * @brief  计算星期几
 */
uint8_t rtc_get_week(uint16_t year, uint8_t month, uint8_t day)
{
    uint16_t temp;
    uint8_t yearH, yearL;
    if(month < 1 || month >12) month = 1;
    yearH = year / 100;
    yearL = year % 100;
    if (yearH > 19) yearL += 100;
    temp = yearL + yearL / 4;
    temp = temp % 7;
    temp = temp + day + table_week[month - 1];
    if ((yearL % 4 == 0) && (month < 3)) temp--;
    temp %= 7;
    if (temp == 0) temp = 7;
    return temp;
}

2.5 RTC初始化

/**
 * @brief  RTC模块初始化
 * @retval 0-正常 1-HAL失败
 */
uint8_t rtc_init(void)
{
    uint16_t bkpflag = 0;

    __HAL_RCC_PWR_CLK_ENABLE();
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_RTC_ENABLE();
    
    rtc_handle.Instance = RTC;
    rtc_handle.Init.HourFormat = RTC_HOURFORMAT_24;
    rtc_handle.Init.AsynchPrediv = 0x7F;
    rtc_handle.Init.SynchPrediv = 0xFF;
    rtc_handle.Init.OutPut = RTC_OUTPUT_DISABLE;
    rtc_handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    rtc_handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;

    bkpflag = rtc_read_bkr(0);

    if(HAL_RTC_Init(&rtc_handle) != HAL_OK)
    {
        printf("HAL_RTC_Init失败\r\n");
        return 1;
    }
    if((bkpflag != RTC_BACKUP_LSE_FLAG) && (bkpflag != RTC_BACKUP_LSI_FLAG))
    {
        printf("首次配置RTC时间\r\n");
        rtc_set_time(6,59,59,RTC_HOURFORMAT12_AM);
        rtc_set_date(RTC_DEFAULT_YEAR, RTC_DEFAULT_MONTH, RTC_DEFAULT_DATE, RTC_DEFAULT_WEEKDAY);
    }
    return 0;
}

// ===================== 时钟底层MSP ========================

void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
    uint16_t retry = 200;
    RCC_OscInitTypeDef rcc_osc_init_handle = {0};
    RCC_PeriphCLKInitTypeDef rcc_periphclk_init_handle = {0};
    __HAL_RCC_PWR_CLK_ENABLE();
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_RTC_ENABLE();

    RCC->BDCR |= 1 << 0;        // 启动LSE
    while (retry && ((RCC->BDCR & 0x02) == 0))
    {
        retry--;
        delay_ms(5);
    }
    if (retry == 0)
    {
        // LSE失败,改用LSI
        rcc_osc_init_handle.OscillatorType = RCC_OSCILLATORTYPE_LSI;
        rcc_osc_init_handle.LSIState = RCC_LSI_ON;
        rcc_osc_init_handle.PLL.PLLState = RCC_PLL_NONE;
        HAL_RCC_OscConfig(&rcc_osc_init_handle);

        rcc_periphclk_init_handle.PeriphClockSelection = RCC_PERIPHCLK_RTC;
        rcc_periphclk_init_handle.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
        HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_handle);

        rtc_write_bkr(0, RTC_BACKUP_LSI_FLAG);
        printf("使用RTC LSI时钟\r\n");
    }
    else
    {
        rcc_osc_init_handle.OscillatorType = RCC_OSCILLATORTYPE_LSE;
        rcc_osc_init_handle.PLL.PLLState = RCC_PLL_NONE;
        rcc_osc_init_handle.LSEState = RCC_LSE_ON;
        HAL_RCC_OscConfig(&rcc_osc_init_handle);

        rcc_periphclk_init_handle.PeriphClockSelection = RCC_PERIPHCLK_RTC;
        rcc_periphclk_init_handle.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
        HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_handle);

        rtc_write_bkr(0, RTC_BACKUP_LSE_FLAG);
        printf("使用RTC LSE时钟\r\n");
    }
}

2.6 设置闹钟和唤醒

void rtc_set_alarm(uint8_t week, uint8_t hour, uint8_t min, uint8_t sec)
{
    RTC_AlarmTypeDef rtc_alarm_handle = {0};
    rtc_alarm_handle.AlarmTime.Hours = hour;
    rtc_alarm_handle.AlarmTime.Minutes = min;
    rtc_alarm_handle.AlarmTime.Seconds = sec;
    rtc_alarm_handle.AlarmTime.SubSeconds = 0;
    rtc_alarm_handle.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
    rtc_alarm_handle.AlarmMask = RTC_ALARMMASK_NONE;
    rtc_alarm_handle.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
    rtc_alarm_handle.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
    rtc_alarm_handle.AlarmDateWeekDay = week;
    rtc_alarm_handle.Alarm = RTC_ALARM_A;

    HAL_RTC_SetAlarm_IT(&rtc_handle, &rtc_alarm_handle, RTC_FORMAT_BIN);

    HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 1, 2);
    HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}

void rtc_set_wakeup(uint8_t wksel, uint16_t cnt)
{
    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&rtc_handle, RTC_FLAG_WUTF);
    HAL_RTCEx_SetWakeUpTimer_IT(&rtc_handle, cnt, wksel);
    HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 2, 2);
    HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
}

2.7 中断处理

void RTC_Alarm_IRQHandler(void)
{
    HAL_RTC_AlarmIRQHandler(&rtc_handle);
}

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    rtc_alarm_flag = 1;
}

void RTC_WKUP_IRQHandler(void)
{
    HAL_RTCEx_WakeUpTimerIRQHandler(&rtc_handle); 
}

void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
    rtc_wakeup_flag = 1;
}

2.8 主函数测试

#include "bsp_init.h"
#include "stdio.h"
#include "usmart.h"
#include "rtc.h"

int main(void)
{
    uint8_t hour, min, sec, ampm;
    uint8_t year, month, date, week;
    char tempbuf[40];
    uint32_t last_refresh = 0, last_led = 0;

    bsp_init();
    usmart_dev.init(84);

    uint8_t rtc_status = rtc_init();
    if (rtc_status != 0)
    {
        printf("RTC初始化失败,错误代码:%d\r\n", rtc_status);
    }
    rtc_set_wakeup(RTC_WAKEUPCLOCK_CK_SPRE_16BITS, 0); // 1s周期中断

    while(1)
    {
        uint32_t now = HAL_GetTick();

        // 周期刷新时间
        if(now - last_refresh > 200)
        {
            last_refresh = now;

            rtc_get_time(&hour, &min, &sec, &ampm);
            sprintf(tempbuf, "Time:%02d:%02d:%02d", hour, min, sec);
            LCD_ShowString(30,130,210,16,16,tempbuf);

            rtc_get_date(&year, &month, &date, &week);
            sprintf(tempbuf, "Date:20%02d-%02d-%02d", year, month, date);
            LCD_ShowString(30,150,210,16,16,tempbuf);

            sprintf(tempbuf, "Week:%d", week);
            LCD_ShowString(30,170,210,16,16,tempbuf);
        }

        // LED0翻转
        if(now - last_led > 400)
        {
            last_led = now;
            LED_TOGGLE(LED0_GPIO_Pin);
        }

        // 唤醒标志事件
        if(rtc_wakeup_flag)
        {
            rtc_wakeup_flag = 0;
            // printf("RTC Wakeup!\r\n");
            LED_TOGGLE(LED1_GPIO_Pin);
        }

        // 闹钟标志事件
        if(rtc_alarm_flag)
        {
            rtc_alarm_flag = 0;
            printf("RTC Alarm!\r\n");
        }

        delay_ms(10);
    }
}

3. RTC常见函数(HAL库)

3.1 RTC 初始化与配置

3.1.1  HAL_RTC_Init()

函数原型:

HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc)

参数:

  • hrtc: RTC 句柄指针

功能:
初始化 RTC 外设,配置时钟源、预分频器等基础参数

配置结构体:

typedef struct {
  uint32_t HourFormat;      // 小时格式: RTC_HOURFORMAT_12 / RTC_HOURFORMAT_24
  uint32_t AsynchPrediv;    // 异步预分频值 (7位, 0-127)
  uint32_t SynchPrediv;     // 同步预分频值 (15位, 0-32767)
  uint32_t OutPut;          // 输出选择: RTC_OUTPUT_DISABLE / ALARMA / ALARMB / WAKEUP
  uint32_t OutPutPolarity;  // 输出极性: RTC_OUTPUT_POLARITY_HIGH / LOW
  uint32_t OutPutType;      // 输出类型: RTC_OUTPUT_TYPE_OPENDRAIN / PUSHPULL
} RTC_InitTypeDef;

示例配置:

RTC_HandleTypeDef hrtc;

hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;    // 异步分频值
hrtc.Init.SynchPrediv = 255;     // 同步分频值
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_PUSHPULL;

if (HAL_RTC_Init(&hrtc) != HAL_OK) {
  // 错误处理
}

3.2 时间设置与获取

3.2.1 HAL_RTC_SetTime()

函数原型:

HAL_StatusTypeDef HAL_RTC_SetTime(
    RTC_HandleTypeDef *hrtc,
    RTC_TimeTypeDef *sTime,
    uint32_t Format)

参数:

  • sTime: 时间结构体指针

  • Format: 格式: RTC_FORMAT_BIN (二进制) / RTC_FORMAT_BCD (BCD码)

时间结构体:

typedef struct {
  uint8_t Hours;            // 小时 (0-23 或 1-12)
  uint8_t Minutes;          // 分钟 (0-59)
  uint8_t Seconds;          // 秒 (0-59)
  uint8_t TimeFormat;       // 时间格式: RTC_HOURFORMAT12_AM / RTC_HOURFORMAT12_PM
  uint32_t SubSeconds;      // 亚秒值
  uint32_t SecondFraction;  // 亚秒分数值
  uint32_t DayLightSaving;  // 夏令时: RTC_DAYLIGHTSAVING_SUB1H / ADD1H / NONE
  uint32_t StoreOperation;  // 存储操作: RTC_STOREOPERATION_RESET / SET
} RTC_TimeTypeDef;

示例:

RTC_TimeTypeDef sTime = {0};
sTime.Hours = 14;        // 14:30:00
sTime.Minutes = 30;
sTime.Seconds = 0;
sTime.TimeFormat = RTC_HOURFORMAT12_PM;  // 24小时制下忽略
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;

HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);

3.2.2 HAL_RTC_GetTime()

函数原型:

HAL_StatusTypeDef HAL_RTC_GetTime(
    RTC_HandleTypeDef *hrtc,
    RTC_TimeTypeDef *sTime,
    uint32_t Format)

功能: 获取当前时间
注意: 必须先调用 HAL_RTC_GetTime 再调用 HAL_RTC_GetDate

3.3 日期设置与获取

3.3.1 HAL_RTC_SetDate()

函数原型:

HAL_StatusTypeDef HAL_RTC_SetDate(
    RTC_HandleTypeDef *hrtc,
    RTC_DateTypeDef *sDate,
    uint32_t Format)

日期结构体:

typedef struct {
  uint8_t WeekDay;  // 星期: RTC_WEEKDAY_MONDAY 到 SUNDAY (1-7)
  uint8_t Month;    // 月份: RTC_MONTH_JANUARY 到 DECEMBER (1-12)
  uint8_t Date;     // 日期: 1-31
  uint8_t Year;     // 年份: 0-99 (代表2000-2099)
} RTC_DateTypeDef;

示例:


RTC_DateTypeDef sDate = {0};
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_OCTOBER;
sDate.Date = 15;
sDate.Year = 23;  // 2023年

HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

3.3.2 HAL_RTC_GetDate()

函数原型:

HAL_StatusTypeDef HAL_RTC_GetDate(
    RTC_HandleTypeDef *hrtc,
    RTC_DateTypeDef *sDate,
    uint32_t Format)

3.4 闹钟功能

3.4.1 HAL_RTC_SetAlarm()

函数原型:

HAL_StatusTypeDef HAL_RTC_SetAlarm(
    RTC_HandleTypeDef *hrtc,
    RTC_AlarmTypeDef *sAlarm,
    uint32_t Alarm,
    uint32_t Format)

参数:

  • Alarm: 闹钟选择: RTC_ALARM_A / RTC_ALARM_B

闹钟结构体:

typedef struct {
  RTC_AlarmTypeDef Alarm;                // 闹钟A或B
  uint32_t AlarmMask;                    // 闹钟掩码
  uint32_t AlarmSubSecondMask;           // 亚秒掩码
  uint32_t AlarmDateWeekDaySel;          // 日期/星期选择
  uint8_t AlarmDateWeekDay;              // 日期(1-31)或星期(1-7)
  RTC_TimeTypeDef AlarmTime;             // 闹钟时间
  uint32_t AlarmSubSecondValue;          // 亚秒值
  uint32_t AlarmSubSecondFractionValue;  // 亚秒分数值
} RTC_AlarmTypeDef;

示例 (设置闹钟A在每天14:35:00触发):

RTC_AlarmTypeDef sAlarm = {0};
sAlarm.Alarm = RTC_ALARM_A;
sAlarm.AlarmTime.Hours = 14;
sAlarm.AlarmTime.Minutes = 35;
sAlarm.AlarmTime.Seconds = 0;
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_PM;
sAlarm.AlarmMask = RTC_ALARMMASK_NONE;  // 所有字段都匹配
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;  // 日期设为1 (当使用日期时)
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;

HAL_RTC_SetAlarm(&hrtc, &sAlarm, RTC_ALARM_A, RTC_FORMAT_BIN);

3.4.2 闹钟中断控制

// 使能闹钟中断
HAL_RTC_EnableAlarm(&hrtc, RTC_ALARM_A);

// 禁用闹钟中断
HAL_RTC_DisableAlarm(&hrtc, RTC_ALARM_A);

3.4.3 闹钟中断回调函数

// 用户需重写此函数
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
  if (hrtc->Instance == RTC) {
    // 处理闹钟事件
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  }
}

3.5 唤醒定时器

3.5.1 HAL_RTCEx_SetWakeUpTimer()

函数原型:

HAL_StatusTypeDef HAL_RTCEx_SetWakeUpTimer(
    RTC_HandleTypeDef *hrtc,
    uint32_t WakeUpCounter,
    uint32_t WakeUpClock)

参数:

  • WakeUpCounter: 唤醒计数器值 (0-0xFFFF)

  • WakeUpClock: 时钟源选择:

    • RTC_WAKEUPCLOCK_RTCCLK_DIV16

    • RTC_WAKEUPCLOCK_RTCCLK_DIV8

    • RTC_WAKEUPCLOCK_RTCCLK_DIV4

    • RTC_WAKEUPCLOCK_RTCCLK_DIV2

    • RTC_WAKEUPCLOCK_CK_SPRE_16BITS

    • RTC_WAKEUPCLOCK_CK_SPRE_17BITS

示例 (每1秒唤醒):

// 使用1Hz时钟 (RTC时钟通常为32768Hz)
HAL_RTCEx_SetWakeUpTimer(&hrtc, 0, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);

3.5.2 唤醒定时器控制

// 使能唤醒定时器中断
HAL_RTCEx_EnableWakeUpTimer(&hrtc);

// 禁用唤醒定时器中断
HAL_RTCEx_DisableWakeUpTimer(&hrtc);

3.5.3 唤醒中断回调函数

void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
  // 唤醒事件处理
}

3.6 备份寄存器操作

3.6.1 HAL_RTCEx_BKUPWrite()

函数原型:

void HAL_RTCEx_BKUPWrite(
    RTC_HandleTypeDef *hrtc,
    uint32_t BackupRegister,
    uint32_t Data)

参数:

  • BackupRegister: 备份寄存器 (RTC_BKP_DR0 到 RTC_BKP_DR19)

3.6.2 HAL_RTCEx_BKUPRead()

函数原型:

uint32_t HAL_RTCEx_BKUPRead(
    RTC_HandleTypeDef *hrtc,
    uint32_t BackupRegister)

示例:

// 写入备份寄存器
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, 0x1234);

// 读取备份寄存器
uint32_t data = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0);

3.7 时间戳功能

3.7.1 HAL_RTCEx_SetTimeStamp()

函数原型:

HAL_StatusTypeDef HAL_RTCEx_SetTimeStamp(
    RTC_HandleTypeDef *hrtc,
    uint32_t TimeStampEdge,
    uint32_t RTC_TimeStampPin)

参数:

  • TimeStampEdge: 时间戳边沿 RTC_TIMESTAMPEDGE_RISING / FALLING

  • RTC_TimeStampPin: 时间戳引脚 RTC_TIMESTAMPPIN_DEFAULT

3.7.2 时间戳回调函数

void HAL_RTCEx_TimeStampEventCallback(RTC_HandleTypeDef *hrtc)
{
  RTC_TimeTypeDef sTimeStamp;
  RTC_DateTypeDef sDateStamp;
  
  // 获取时间戳
  HAL_RTC_GetTime(hrtc, &sTimeStamp, RTC_FORMAT_BIN);
  HAL_RTC_GetDate(hrtc, &sDateStamp, RTC_FORMAT_BIN);
  
  // 处理时间戳
}

3.8 RTC校准

3.8.1 HAL_RTCEx_SetSynchroShift()

函数原型:

HAL_StatusTypeDef HAL_RTCEx_SetSynchroShift(
    RTC_HandleTypeDef *hrtc,
    uint32_t ShiftAdd1S,
    uint32_t ShiftSubFS)

功能: 用于RTC时钟校准

3.9 低功耗处理

3.9.1 进入低功耗模式前的处理

void BeforeEnterStopMode(void)
{
  // 禁用RTC中断
  HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
  HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
  
  // 清除RTC标志位
  __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
  __HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRAF);
}

3.9.2 退出低功耗模式后的处理

void AfterExitStopMode(void)
{
  // 重新启用RTC中断
  HAL_RTC_ActivateAlarm(&hrtc, RTC_ALARM_A);
  HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
}

posted @ 2025-08-03 18:58  hazy1k  阅读(50)  评论(0)    收藏  举报