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

STM32 的 RTC(实时时钟)详解

目录

一、引言

二、RTC 概述

三、RTC 的工作原理

1.时钟源

2.计数器

3.闹钟功能

4.备份寄存器

四、RTC 寄存器

1.RTC_TR(Time Register,时间寄存器)

2.RTC_DR(Date Register,日期寄存器) 

3.RTC_SSR(Subsecond Register,亚秒寄存器) 

4.RTC_PRER(Prescaler Register,预分频器寄存器) 

5.RTC_CR(Control Register,控制寄存器) 

6.RTC_ISR(Interrupt Status Register,中断状态寄存器) 

7.RTC_BKPxR(Backup Register,备份寄存器)

五、实际应用

1.时间记录

2.定时任务

3.低功耗模式下的时间保持

六、代码实现 

七、总结 


一、引言

        在嵌入式系统中,准确的时间信息往往是至关重要的。STM32 系列微控制器内置的实时时钟(RTC)模块为系统提供了可靠的时间基准。本文将深入探讨 STM32 的 RTC 的功能、工作原理以及在实际应用中的使用方法

二、RTC 概述

RTC 是一种能够独立运行的时钟模块,即使在微控制器进入低功耗模式时也能保持时间的准确性。STM32 的 RTC 具有以下主要特点:

  1. 高精度计时:能够提供准确的时间信息,包括年、月、日、时、分、秒等。
  2. 低功耗运行:在电池供电的系统中,RTC 可以以极低的功耗运行,延长电池寿命。
  3. 闹钟功能:可以设置闹钟,在特定时间触发中断。
  4. 备份寄存器:用于存储关键数据,即使在系统电源关闭时也能保持数据不丢失。

三、RTC 的工作原理

1.时钟源

  • STM32 的 RTC 可以使用外部低速时钟源(LSE)或内部低速时钟源(LSI)。LSE 通常是一个 32.768kHz 的石英晶体振荡器,具有较高的精度。LSI 是一个内部的低功耗 RC 振荡器,精度相对较低,但在没有外部晶体的情况下可以作为备用时钟源。
  • 时钟源经过分频后为 RTC 提供计时脉冲。

2.计数器

  • RTC 包含一个可编程的预分频器和一个 32 位的计数器。预分频器用于将时钟源的频率分频到合适的频率,以满足不同的计时需求。计数器则根据预分频器输出的脉冲进行计数,从而实现时间的累加。
  • 通过读取计数器的值,可以获取当前的时间信息。

3.闹钟功能

  • RTC 可以设置多个闹钟,每个闹钟可以独立配置。闹钟可以基于特定的时间(如小时、分钟、秒)或日期(年、月、日)触发中断。
  • 当闹钟时间到达时,RTC 会产生一个中断信号,通知微控制器进行相应的处理。

4.备份寄存器

  • STM32 的 RTC 具有多个备份寄存器,可以用于存储关键数据。这些寄存器在系统电源关闭时由备用电源(如电池)供电,以确保数据不丢失。
  • 备份寄存器可以用于存储系统配置参数、校准数据等重要信息。

四、RTC 寄存器

1.RTC_TR(Time Register,时间寄存器)

  • 功能:用于存储当前的时间信息,包括小时、分钟、秒等。
  • 位定义
    • pm:占 1 位,用于表示上午 / 下午(AM/PM)符号,0 表示 AM/24 小时制,1 表示 PM。
    • ht(1:0):占 2 位,是小时的十位部分。
    • hu(3:0):占 4 位,是小时的个位部分。
    • mnt(2:0):占 3 位,为分钟的十位部分。
    • mnu(3:0):占 4 位,是分钟的个位部分。
    • st(2:0):占 3 位,代表秒的十位部分。
    • su(3:0):占 4 位,是秒的个位部分。
  • 操作注意事项:数据是以 BCD 码格式存储的,读取之后需要进行转换才能得到常规的十进制时间数据。在初始化模式下,对该寄存器进行写操作可以设置时间。

2.RTC_DR(Date Register,日期寄存器) 

  • 功能:保存当前的日期信息,包含年、月、日、星期等。
  • 位定义
    • yt(1:0):占 2 位,是年份的十位部分。
    • yu(3:0):占 4 位,为年份的个位部分。
    • wdu(2:0):占 3 位,表示星期几的个位,000 表示禁止,001 表示星期一,以此类推,111 表示星期日。
    • mt:占 1 位,是月份的十位部分。
    • mu:占 4 位,为月份的个位部分。
    • dt(1:0):占 2 位,代表日期的十位部分。
    • du(3:0):占 4 位,是日期的个位部分。
  • 操作要点:同样以 BCD 码格式存储数据,写操作可设置日期。

3.RTC_SSR(Subsecond Register,亚秒寄存器) 

  • 功能:用于记录亚秒值,能够提供更高精度的时间信息,通常用于精确到毫秒或更短时间单位的时间记录。
  • 计算亚秒值:亚秒值的计算需要结合同步预分频器的值。公式为亚秒值 = (prediv_s – ss(15:0)) / (prediv_s + 1),其中 ss(15:0) 是同步预分频器计数器的值,prediv_s 是同步预分频器的值。

4.RTC_PRER(Prescaler Register,预分频器寄存器) 

  • 组成:由 7 位的异步预分频器 apre 和 15 位的同步预分频器 spre 组成。
  • 功能:对输入的时钟源进行分频,以得到合适的时钟频率用于 RTC 的时间和日期更新。异步预分频器时钟 ck_apre 用于为二进制 RTC_SSR 亚秒递减计数器提供时钟,同步预分频器时钟 ck_spre 用于更新日历。
  • 时钟频率计算:异步预分频器时钟 fck_apre = frtc_clk / (prediv_a + 1),同步预分频器时钟 fck_spre = frtc_clk / (prediv_s + 1)。为了最大程度降低功耗,一般将异步预分频器配置为较高的值。

5.RTC_CR(Control Register,控制寄存器) 

  • 功能:用于控制 RTC 的各种功能,如开启或关闭 RTC、设置闹钟使能、选择时钟源等。
  • 具体位的作用:不同的位具有不同的功能,例如可能有位用于使能闹钟输出、配置闹钟输出的极性、设置时间戳功能等。

6.RTC_ISR(Interrupt Status Register,中断状态寄存器) 

  • 功能:反映 RTC 的各种中断状态,例如闹钟中断标志位、时间戳中断标志位等。当相应的事件发生时,对应的标志位会被置位,通过读取该寄存器可以判断中断是否发生以及发生的是哪种中断。

7.RTC_BKPxR(Backup Register,备份寄存器)

  • 功能:STM32 的 RTC 有备份寄存器,包括 20 个 32 位寄存器,用于存储用户应用数据。这些寄存器在备份域中实现,可在 VDD 电源关闭时通过 VBAT 保持上电状态。备份寄存器不会在系统复位或电源复位时复位,也不会在器件从待机模式唤醒时复位。它可用于在掉电等情况下保存一些关键数据。

五、实际应用

1.时间记录

  • 在数据采集系统中,RTC 可以用于记录数据的采集时间,以便后续分析和处理。
  • 在日志记录系统中,RTC 可以为每条日志记录添加时间戳,方便查看和分析系统的运行情况。

2.定时任务

  • 可以使用 RTC 的闹钟功能来实现定时任务,如在特定时间执行特定的操作。例如,在智能家居系统中,可以设置在特定时间打开或关闭电器设备。
  • 在工业自动化系统中,RTC 可以用于定时控制生产过程中的各个环节。

3.低功耗模式下的时间保持

在低功耗应用中,当微控制器进入低功耗模式时,RTC 可以继续运行,保持时间的准确性。当系统从低功耗模式唤醒时,可以通过 RTC 获取当前的时间信息,无需重新初始化时间。

六、代码实现 

以下是一个使用 STM32F429 的 RTC(实时时钟)的代码示例:

#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"void RTC_Init(void)
{// 使能电源时钟和备份区域时钟__HAL_RCC_PWR_CLK_ENABLE();__HAL_RCC_BKPSRAM_CLK_ENABLE();// 允许访问备份寄存器HAL_PWR_EnableBkUpAccess();// 检查是否已经配置过 RTCif ((RCC->BDCR & RCC_BDCR_RTCEN)!= 0){// RTC 已经配置过,无需再次初始化return;}// 选择 LSE 作为 RTC 时钟源__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK){Error_Handler();}// 使能 RTC 时钟RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct)!= HAL_OK){Error_Handler();}// 初始化 RTCRTC_HandleTypeDef hrtc;hrtc.Instance = RTC;hrtc.Init.HourFormat = RTC_HOURFORMAT_24;hrtc.Init.AsynchPrediv = 0x7F;hrtc.Init.SynchPrediv = 0xFF;hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;if (HAL_RTC_Init(&hrtc)!= HAL_OK){Error_Handler();}
}void RTC_SetTime(uint8_t hour, uint8_t minute, uint8_t second)
{RTC_TimeTypeDef sTime = {0};sTime.Hours = hour;sTime.Minutes = minute;sTime.Seconds = second;sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;sTime.StoreOperation = RTC_STOREOPERATION_RESET;if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN)!= HAL_OK){Error_Handler();}
}void RTC_SetDate(uint8_t year, uint8_t month, uint8_t day)
{RTC_DateTypeDef sDate = {0};sDate.Year = year;sDate.Month = month;sDate.Date = day;sDate.WeekDay = RTC_WEEKDAY_MONDAY;if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN)!= HAL_OK){Error_Handler();}
}void RTC_GetTime(uint8_t *hour, uint8_t *minute, uint8_t *second)
{RTC_TimeTypeDef sTime;if (HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN)!= HAL_OK){Error_Handler();}*hour = sTime.Hours;*minute = sTime.Minutes;*second = sTime.Seconds;
}void RTC_GetDate(uint8_t *year, uint8_t *month, uint8_t *day)
{RTC_DateTypeDef sDate;if (HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN)!= HAL_OK){Error_Handler();}*year = sDate.Year;*month = sDate.Month;*day = sDate.Date;
}void Error_Handler(void)
{// 处理错误while (1){}
}

在主函数中,可以这样调用:

int main(void)
{HAL_Init();RTC_Init();// 设置时间为 12:30:00RTC_SetTime(12, 30, 0);// 设置日期为 2023 年 9 月 14 日RTC_SetDate(23, 9, 14);uint8_t hour, minute, second;uint8_t year, month, day;// 获取时间和日期并打印RTC_GetTime(&hour, &minute, &second);RTC_GetDate(&year, &month, &day);while (1){}
}

七、总结 

        STM32 的 RTC 模块为嵌入式系统提供了可靠的时间基准。通过了解 RTC 的工作原理、配置方法和应用场景,开发者可以充分利用 RTC 的功能,为系统添加时间记录、定时任务等功能,提高系统的实用性和可靠性。在使用 RTC 时,需要注意时钟源的选择、时间的初始化和校准以及备份寄存器的使用等问题,以确保 RTC 的正常运行和数据的安全性。

希望本文对大家在使用 STM32 的 RTC 模块时有所帮助。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 6.4图的应用
  • 简单题26 - 删除有序数组中的重复项(Java)20240917
  • 图像处理与OCR识别的实践经验(1)
  • 阿里部分集团内部中间件简介
  • Qt:实现单例模式
  • 1.1 计算机网络基本概述
  • #if等命令的学习
  • 【Unity踩坑】为什么有Rigidbody的物体运行时位置会变化
  • 【Linux】Image、zImage与uImage的区别
  • 【蜡笔小新专享】安装虚拟机、PHP、DVWA
  • 三只羊的麻烦,轮到抖音了…
  • OpenCore Legacy Patcher 2.0.0 发布,83 款不受支持的 Mac 机型将能运行最新的 macOS Sequoia
  • Android Studio Menu制作
  • GPIO子系统
  • leetcode49字母异位词分组
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 0x05 Python数据分析,Anaconda八斩刀
  • Codepen 每日精选(2018-3-25)
  • create-react-app项目添加less配置
  • Druid 在有赞的实践
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Java|序列化异常StreamCorruptedException的解决方法
  • Java方法详解
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • php的插入排序,通过双层for循环
  • python_bomb----数据类型总结
  • Python_OOP
  • React组件设计模式(一)
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • 高程读书笔记 第六章 面向对象程序设计
  • 深度学习在携程攻略社区的应用
  • 实现简单的正则表达式引擎
  • 首页查询功能的一次实现过程
  • 为什么要用IPython/Jupyter?
  • 小李飞刀:SQL题目刷起来!
  • 学习JavaScript数据结构与算法 — 树
  • 异步
  • Prometheus VS InfluxDB
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (21)起落架/可伸缩相机支架
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (el-Transfer)操作(不使用 ts):Element-plus 中 Select 组件动态设置 options 值需求的解决过程
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (二)原生js案例之数码时钟计时
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (南京观海微电子)——COF介绍
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (十五)使用Nexus创建Maven私服
  • (一)认识微服务