stm32f10x_rtc

RTC(Real-Time Clock)外设是STM32F10x系列微控制器中的实时时钟模块,提供精确的时间计数和闹钟功能。该外设具有独立的时钟源,在系统掉电后仍能保持时间计数,支持秒中断、闹钟中断和溢出中断。RTC外设广泛应用于需要时间戳、定时唤醒、闹钟提醒等功能的嵌入式系统中。

数据类型定义

RTC中断定义

#define RTC_IT_OW            ((uint16_t)0x0004)  /* 溢出中断 */
#define RTC_IT_ALR           ((uint16_t)0x0002)  /* 闹钟中断 */
#define RTC_IT_SEC           ((uint16_t)0x0001)  /* 秒中断 */

说明:

  • RTC_IT_OW:RTC计数器溢出中断,当32位计数器溢出时触发
  • RTC_IT_ALR:RTC闹钟中断,当计数器值等于闹钟值时触发
  • RTC_IT_SEC:RTC秒中断,每秒触发一次

RTC标志位定义

#define RTC_FLAG_RTOFF       ((uint16_t)0x0020)  /* RTC操作关闭标志 */
#define RTC_FLAG_RSF         ((uint16_t)0x0008)  /* 寄存器同步标志 */
#define RTC_FLAG_OW          ((uint16_t)0x0004)  /* 溢出标志 */
#define RTC_FLAG_ALR         ((uint16_t)0x0002)  /* 闹钟标志 */
#define RTC_FLAG_SEC         ((uint16_t)0x0001)  /* 秒标志 */

说明:

  • RTC_FLAG_RTOFF:RTC操作关闭标志,表示RTC当前不可访问
  • RTC_FLAG_RSF:寄存器同步标志,表示RTC寄存器已同步
  • RTC_FLAG_OW:溢出标志,表示RTC计数器已溢出
  • RTC_FLAG_ALR:闹钟标志,表示闹钟事件已发生
  • RTC_FLAG_SEC:秒标志,表示秒事件已发生

RTC寄存器定义

STM32F10x RTC外设包含以下主要寄存器:

// RTC控制寄存器
#define RTC_CRH              ((uint16_t)0x0000)  /* RTC控制寄存器高字节 */
#define RTC_CRL              ((uint16_t)0x0001)  /* RTC控制寄存器低字节 */

// RTC预分频器寄存器
#define RTC_PRLH             ((uint16_t)0x0002)  /* RTC预分频器寄存器高字节 */
#define RTC_PRLL              ((uint16_t)0x0003)  /* RTC预分频器寄存器低字节 */

// RTC分频器寄存器
#define RTC_DIVH              ((uint16_t)0x0004)  /* RTC分频器寄存器高字节 */
#define RTC_DIVL              ((uint16_t)0x0005)  /* RTC分频器寄存器低字节 */

// RTC计数器寄存器
#define RTC_CNTH              ((uint16_t)0x0006)  /* RTC计数器寄存器高字节 */
#define RTC_CNTL              ((uint16_t)0x0007)  /* RTC计数器寄存器低字节 */

// RTC闹钟寄存器
#define RTC_ALRH              ((uint16_t)0x0008)  /* RTC闹钟寄存器高字节 */
#define RTC_ALRL              ((uint16_t)0x0009)  /* RTC闹钟寄存器低字节 */

标准库函数详解

1. RTC_ITConfig

/**
 * @brief  使能/屏蔽 RTC 中断源(秒、闹钟、溢出),配合 NVIC 实现定时唤醒或事件响应
 * @param  RTC_IT: 要配置的RTC中断
 *         该参数可以是以下值之一:
 *           @arg RTC_IT_OW: 溢出中断
 *           @arg RTC_IT_ALR: 闹钟中断
 *           @arg RTC_IT_SEC: 秒中断
 * @param  NewState: 中断的新状态
 *         该参数可以是以下值之一:
 *           @arg ENABLE: 使能中断
 *           @arg DISABLE: 禁用中断
 * @retval
 * @example
 *     RTC_ITConfig(RTC_IT_SEC, ENABLE);
 */
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);

功能说明:

  • 可单独打开秒中断(每秒节拍)、闹钟中断(定时唤醒)或溢出中断
  • 使能后还需在 NVIC 中配置 RTC_IRQn 才能进入中断服务程序
  • 修改中断使能后建议调用 RTC_WaitForLastTask 等待写入完成

2. RTC_EnterConfigMode

/**
 * @brief  进入 RTC 配置模式,解锁对预分频器、计数器、闹钟等寄存器的写访问
 * @param
 * @retval
 * @example
 *     RTC_EnterConfigMode();
 */
void RTC_EnterConfigMode(void);

功能说明:

  • 修改 PRL、CNT、ALR 等寄存器前必须先调用
  • 与 RTC_ExitConfigMode 成对使用,退出后寄存器受硬件保护
  • 通常配合 PWR_BackupAccessCmd(ENABLE) 和备份域时钟使能

3. RTC_ExitConfigMode

/**
 * @brief  退出 RTC 配置模式,锁定寄存器并使新配置生效
 * @param
 * @retval
 * @example
 *     RTC_ExitConfigMode();
 */
void RTC_ExitConfigMode(void);

功能说明:

  • 完成 SetCounter/SetPrescaler/SetAlarm 后必须调用
  • 退出后 RTC 硬件开始按新配置计数
  • 建议随后调用 RTC_WaitForLastTask 确认写操作完成

4. RTC_GetCounter

/**
 * @brief  读取 RTC 32 位计数器当前值,即自上电/复位以来累计的秒数
 * @param
 * @retval RTC计数器的32位值
 * @example
 *     uint32_t counter = RTC_GetCounter();
 */
uint32_t RTC_GetCounter(void);

功能说明:

  • 返回值即当前时间戳(秒),可换算为时分秒
  • 读取前应调用 RTC_WaitForSynchro 确保寄存器已同步
  • 32 位计数器约 136 年溢出,需配合 RTC_IT_OW 处理

5. RTC_SetCounter

/**
 * @brief  设置 RTC 计数器初值,用于校时或系统上电后初始化时间基准
 * @param  CounterValue: 要设置的计数器值
 * @retval
 * @example
 *     RTC_SetCounter(0);
 */
void RTC_SetCounter(uint32_t CounterValue);

功能说明:

  • 须在 RTC_EnterConfigMode 与 RTC_ExitConfigMode 之间调用
  • 写入后调用 RTC_WaitForLastTask 等待硬件完成
  • 常用于首次上电将计数器归零或写入已知时间戳

6. RTC_SetPrescaler

/**
 * @brief  设置 RTC 预分频器,将 LSE/LSI 时钟分频为 1 Hz 秒节拍
 * @param  PrescalerValue: 预分频器值,范围0-0xFFFFF
 * @retval
 * @example
 *     RTC_SetPrescaler(32767);
 */
void RTC_SetPrescaler(uint32_t PrescalerValue);

功能说明:

  • 预分频值 = 输入时钟频率 − 1(LSE 32.768 kHz 时设为 32767)
  • 须在配置模式下调用,通常只在初始化时设置一次
  • 分频正确后 RTC 计数器每秒递增 1

7. RTC_SetAlarm

/**
 * @brief  设置 RTC 闹钟匹配值,计数器等于该值时触发闹钟中断
 * @param  AlarmValue: 闹钟值
 * @retval
 * @example
 *     RTC_SetAlarm(3600);
 */
void RTC_SetAlarm(uint32_t AlarmValue);

功能说明:

  • 须在配置模式下调用,AlarmValue 为绝对计数值而非相对延时
  • 配合 RTC_ITConfig(RTC_IT_ALR, ENABLE) 实现定时唤醒
  • 触发后需在中断中清除挂起位,可重新设置下一次闹钟

8. RTC_GetDivider

/**
 * @brief  读取 RTC 分频器当前计数值,反映当前秒内亚秒级进度
 * @param
 * @retval RTC分频器的32位值
 * @example
 *     uint32_t divider = RTC_GetDivider();
 */
uint32_t RTC_GetDivider(void);

功能说明:

  • 分频器从预分频值向下计数到 0 时产生秒脉冲
  • 可用于亚秒精度时间推算或调试 RTC 分频状态
  • 读取前建议先等待 RTC_WaitForSynchro

9. RTC_WaitForLastTask

/**
 * @brief  阻塞等待 RTC 最后一次写操作完成(RTOFF 标志置位)
 * @param
 * @retval
 * @example
 *     RTC_SetCounter(0);
 *     RTC_WaitForLastTask();
 */
void RTC_WaitForLastTask(void);

功能说明:

  • 每次写 RTC 寄存器后应调用,确保数据已写入备份域
  • 轮询 RTC_FLAG_RTOFF,为 SET 时表示可继续下一次操作
  • 连续多次写操作之间不可省略此等待

10. RTC_WaitForSynchro

/**
 * @brief  等待 RTC 寄存器与 APB 总线同步(RSF 标志置位),读寄存器前必须调用
 * @param
 * @retval
 * @example
 *     RTC_WaitForSynchro();
 */
void RTC_WaitForSynchro(void);

功能说明:

  • 复位后、从待机唤醒后或切换 RTC 时钟源后必须调用
  • 轮询 RTC_FLAG_RSF,为 SET 后方可安全读取 CNT 等寄存器
  • 通常在 RCC_RTCCLKCmd 使能后作为初始化第一步

11. RTC_GetFlagStatus

/**
 * @brief  查询 RTC 标志位状态(同步、溢出、闹钟、秒事件等)
 * @param  RTC_FLAG: 要检查的RTC标志
 *         该参数可以是以下值之一:
 *           @arg RTC_FLAG_RTOFF: RTC操作关闭标志
 *           @arg RTC_FLAG_RSF: 寄存器同步标志
 *           @arg RTC_FLAG_OW: 溢出标志
 *           @arg RTC_FLAG_ALR: 闹钟标志
 *           @arg RTC_FLAG_SEC: 秒标志
 * @retval 标志状态
 *         该返回值可以是以下值之一:
 *           @arg SET: 标志已设置
 *           @arg RESET: 标志已清除
 * @example
 *     FlagStatus flag = RTC_GetFlagStatus(RTC_FLAG_SEC);
 */
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);

功能说明:

  • 用于轮询方式检测秒/闹钟/溢出事件,无需中断
  • RTOFF 和 RSF 常用于初始化流程中的同步等待
  • 返回 SET 表示对应事件已发生

12. RTC_ClearFlag

/**
 * @brief  清除 RTC 事件标志(溢出、闹钟、秒),轮询模式下处理完事件后调用
 * @param  RTC_FLAG: 要清除的RTC标志
 *         该参数可以是以下值之一:
 *           @arg RTC_FLAG_OW: 溢出标志
 *           @arg RTC_FLAG_ALR: 闹钟标志
 *           @arg RTC_FLAG_SEC: 秒标志
 * @retval
 * @example
 *     RTC_ClearFlag(RTC_FLAG_SEC);
 */
void RTC_ClearFlag(uint16_t RTC_FLAG);

功能说明:

  • 仅清除标志位,不影响中断使能配置
  • 轮询 RTC_FLAG_SEC 等标志后必须清除,否则会重复触发
  • 不可用于清除 RTOFF/RSF 等硬件状态标志

13. RTC_GetITStatus

/**
 * @brief  查询 RTC 中断挂起状态,用于中断服务程序中判断中断源
 * @param  RTC_IT: 要检查的RTC中断
 *         该参数可以是以下值之一:
 *           @arg RTC_IT_OW: 溢出中断
 *           @arg RTC_IT_ALR: 闹钟中断
 *           @arg RTC_IT_SEC: 秒中断
 * @retval 中断状态
 *         该返回值可以是以下值之一:
 *           @arg SET: 中断已挂起
 *           @arg RESET: 中断未挂起
 * @example
 *     ITStatus status = RTC_GetITStatus(RTC_IT_SEC);
 */
ITStatus RTC_GetITStatus(uint16_t RTC_IT);

功能说明:

  • 在 RTC_IRQHandler 中区分秒、闹钟、溢出中断源
  • 返回 SET 表示该中断已挂起且已使能
  • 处理完毕后须调用 RTC_ClearITPendingBit 清除

14. RTC_ClearITPendingBit

/**
 * @brief  清除 RTC 中断挂起位,防止同一中断重复进入
 * @param  RTC_IT: 要清除的RTC中断
 *         该参数可以是以下值之一:
 *           @arg RTC_IT_OW: 溢出中断
 *           @arg RTC_IT_ALR: 闹钟中断
 *           @arg RTC_IT_SEC: 秒中断
 * @retval
 * @example
 *     RTC_ClearITPendingBit(RTC_IT_SEC);
 */
void RTC_ClearITPendingBit(uint16_t RTC_IT);

功能说明:

  • 必须在中断服务程序末尾调用,否则中断会反复触发
  • 同时会清除对应的事件标志位
  • 三个中断源须分别判断、分别清除

使用示例

基本RTC初始化示例

#include "stm32f10x.h"

void RTC_Init_Example(void)
{
    // 使能PWR和BKP时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    
    // 使能对备份寄存器和RTC的访问
    PWR_BackupAccessCmd(ENABLE);
    
    // 使能LSE作为RTC时钟源
    RCC_LSEConfig(RCC_LSE_ON);
    
    // 等待LSE稳定
    while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
    
    // 选择LSE作为RTC时钟源
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
    
    // 使能RTC时钟
    RCC_RTCCLKCmd(ENABLE);
    
    // 等待RTC寄存器同步
    RTC_WaitForSynchro();
    
    // 等待最后一个写操作完成
    RTC_WaitForLastTask();
    
    // 进入配置模式
    RTC_EnterConfigMode();
    
    // 设置预分频器(LSE = 32.768kHz,预分频器 = 32768-1 = 32767)
    RTC_SetPrescaler(32767);
    
    // 设置初始时间(秒)
    RTC_SetCounter(0);
    
    // 退出配置模式
    RTC_ExitConfigMode();
    
    // 等待最后一个写操作完成
    RTC_WaitForLastTask();
}

RTC秒中断示例

#include "stm32f10x.h"

volatile uint32_t seconds = 0;

void RTC_SecondInterrupt_Example(void)
{
    // 初始化RTC(参考上面的初始化代码)
    RTC_Init_Example();
    
    // 使能RTC秒中断
    RTC_ITConfig(RTC_IT_SEC, ENABLE);
    
    // 使能NVIC中断
    NVIC_EnableIRQ(RTC_IRQn);
    
    // 等待最后一个写操作完成
    RTC_WaitForLastTask();
}

// RTC中断服务程序
void RTC_IRQHandler(void)
{
    if(RTC_GetITStatus(RTC_IT_SEC) == SET)
    {
        // 秒中断处理
        seconds++;
        
        // 清除中断挂起位
        RTC_ClearITPendingBit(RTC_IT_SEC);
    }
}

RTC闹钟示例

#include "stm32f10x.h"

void RTC_Alarm_Example(void)
{
    // 初始化RTC(参考上面的初始化代码)
    RTC_Init_Example();
    
    // 进入配置模式
    RTC_EnterConfigMode();
    
    // 设置闹钟在60秒后触发
    RTC_SetAlarm(60);
    
    // 退出配置模式
    RTC_ExitConfigMode();
    
    // 使能RTC闹钟中断
    RTC_ITConfig(RTC_IT_ALR, ENABLE);
    
    // 使能NVIC中断
    NVIC_EnableIRQ(RTC_IRQn);
    
    // 等待最后一个写操作完成
    RTC_WaitForLastTask();
}

// RTC中断服务程序
void RTC_IRQHandler(void)
{
    if(RTC_GetITStatus(RTC_IT_ALR) == SET)
    {
        // 闹钟中断处理
        // 执行闹钟相关操作
        
        // 清除中断挂起位
        RTC_ClearITPendingBit(RTC_IT_ALR);
    }
}

时间获取和设置示例

#include "stm32f10x.h"

// 获取当前时间(秒)
uint32_t RTC_GetTime(void)
{
    return RTC_GetCounter();
}

// 设置当前时间(秒)
void RTC_SetTime(uint32_t time)
{
    // 进入配置模式
    RTC_EnterConfigMode();
    
    // 设置时间
    RTC_SetCounter(time);
    
    // 退出配置模式
    RTC_ExitConfigMode();
    
    // 等待最后一个写操作完成
    RTC_WaitForLastTask();
}

// 时间转换函数(秒转时分秒)
void RTC_SecondsToTime(uint32_t seconds, uint8_t *hours, uint8_t *minutes, uint8_t *secs)
{
    *hours = (seconds / 3600) % 24;
    *minutes = (seconds / 60) % 60;
    *secs = seconds % 60;
}

// 时间转换函数(时分秒转秒)
uint32_t RTC_TimeToSeconds(uint8_t hours, uint8_t minutes, uint8_t secs)
{
    return hours * 3600 + minutes * 60 + secs;
}

注意事项

  1. 时钟源选择:RTC可以使用LSE(32.768kHz)或LSI作为时钟源,LSE精度更高
  2. 预分频器设置:预分频器值 = 输入时钟频率 - 1,确保得到1Hz的时钟
  3. 配置模式:修改RTC配置寄存器前必须进入配置模式
  4. 同步等待:读取RTC寄存器前应等待同步完成
  5. 中断处理:在中断服务程序中必须清除中断挂起位
  6. 备份域访问:使用RTC前必须使能备份域访问权限
  7. 时间精度:RTC时间精度取决于时钟源的稳定性
  8. 溢出处理:32位计数器约136年后溢出,需要处理溢出事件

总结

STM32F10x RTC外设提供了完整的实时时钟功能,支持精确的时间计数、闹钟功能和多种中断。通过独立的时钟源,RTC在系统掉电后仍能保持时间计数,为嵌入式系统提供可靠的时间基准。RTC外设广泛应用于需要时间戳、定时唤醒、闹钟提醒等功能的系统中。在使用时需要注意正确的初始化顺序、时钟源选择和中断处理,确保RTC功能的稳定运行。