【STM32-学习笔记-11-】RTC实时时钟

文章目录

  • RTC实时时钟
    • 一、RTC简介
    • 二、RTC框图
    • 三、RTC基本结构
    • 四、RTC操作注意事项
    • 五、RTC函数
    • 六、配置RTC
        • MyRTC.c
    • 七、示例:实时时钟
      • ①、main.c
      • ②、MyRTC.c
      • ③、MyRTC.h

RTC实时时钟

一、RTC简介

  • RTC(Real Time Clock)实时时钟

  • RTC是一个独立的定时器,可为系统提供时钟和日历的功能

  • RTC和时钟配置系统处于后备区域,系统复位时数据不清零,VDD(2.0~3.6V)断电后可借助VBAT(1.8~3.6V)供电继续走时

  • 32位的可编程计数器,可对应Unix时间戳的秒计数器

  • 20位的可编程预分频器,可适配不同频率的输入时钟(产生稳定的1Hz的时钟

  • 可选择三种RTC时钟源:

    • 高速外部时钟信号)HSE时钟除以128(通常为8MHz/128)
      • 主要作为系统时钟
    • 低速外部时钟信号)LSE振荡器时钟(通常为32.768KHz)
      • 主要用于RTC时钟,可由VBAT供电
      • 2 15 = 32768 2^{15}=32768 215=32768 则使用15位的计数器,计数值从0~32767,自然溢出即可产生1Hz的时钟信号
    • 低速内部时钟信号)LSI振荡器时钟(40KHz)
      • 主要作为看门狗时钟
    • image-20250115103618025

二、RTC框图

  • RTC寄存器由RTCCLK寄存器驱动

image-20250115104623366

  • 灰色区域在主电源掉电之后可由VBAT供电
  • RTC_PRL 预分频装载寄存器,用来保存RTC预分频器的周期计数值(写入R则是R+1分频
  • RTC_DIV 预分频器余数寄存器
    • 每来一个脉冲,计数值-1;自减到0时,再来一个脉冲,则会产生一个溢出信号(TR_CLK);同时DIV从PRL获取一个重装值,再继续自减
    • 该溢出信号即为所需的1Hz时钟
  • RTC_CNT (秒计数器)相当于Unix时间戳,再利用<time.h>库函数即可计算出时间
  • RTC_ALR 设置闹钟
    • RTC_ALR=RTC_CNT时,则会产生RTC_Alarm闹钟信号通往NVIC中断控制器

三、RTC基本结构

image-20250115110845391

image-20250115111150460

四、RTC操作注意事项

  1. 使能对BKP(备份寄存器)和RTC的访问

    • 需要设置RCC_APB1ENR寄存器的PWRENBKPEN位,以**

      •   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
        
    • 需要设置PWR_CR寄存器的DBP位,以使能对BKPRTC的访问

      •   PWR_BackupAccessCmd(ENABLE);
        
  2. 等待寄存器同步标志位被置位

    • 如果在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1

      •   while (!(RTC->CRL & RTC_CRL_RSF));  // 等待寄存器同步标志位被置位
        
    • 这是因为在APB1接口禁止状态下,寄存器的值可能不一致,需要等待同步标志位被置位以确保寄存器值的一致性

  3. 进入配置模式

    • 必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL(预分频器)、RTC_CNT(计数器)、RTC_ALR(闹钟寄存器)等寄存器

      •   RTC->CRL |= RTC_CRL_CNF;  // 设置配置模式位while (!(RTC->CRL & RTC_CRL_CNF));  // 等待配置模式位被硬件清除
        
  4. 写操作的时序要求:等待前一次写操作结束

    • 对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行

    • 可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中

    • 仅当RTOFF状态位是1时,才可以写入RTC寄存器。这是因为RTC寄存器在更新过程中是不允许写入的,必须等待更新完成(即RTOFF位被置位)后才能进行下一次写操作

      •   while (!(RTC->CR & RTC_CR_RTOFF));  // 等待上一次写操作完成RTC->CNT = new_value;  // 写入新的值
        

五、RTC函数

// 配置RTC中断
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);// 进入RTC配置模式
void RTC_EnterConfigMode(void);
// 退出RTC配置模式
void RTC_ExitConfigMode(void);// 获取RTC计数器CNT的值
uint32_t  RTC_GetCounter(void);
// 设置RTC计数器CNT的值
void RTC_SetCounter(uint32_t CounterValue);// 设置RTC预分频值(写入PRL重装寄存器中)
void RTC_SetPrescaler(uint32_t PrescalerValue);// 设置RTC闹钟值ALR
void RTC_SetAlarm(uint32_t AlarmValue);// 获取RTC分频值(获取余数寄存器RTC_DIV的值)
uint32_t RTC_GetDivider(void);// 等待RTC上一个任务完成
void RTC_WaitForLastTask(void);// 等待RTC同步(等待RSF【寄存器同步标志】置1)
void RTC_WaitForSynchro(void);// 获取RTC标志位状态
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
// 清除RTC标志位
void RTC_ClearFlag(uint16_t RTC_FLAG);// 获取RTC中断状态
ITStatus RTC_GetITStatus(uint16_t RTC_IT);
// 清除RTC中断待处理位
void RTC_ClearITPendingBit(uint16_t RTC_IT);

六、配置RTC

  1. 开启电源(PWR)和备份寄存器(BKP)时钟

    •   	//开启电源(PWR)和备份寄存器(BKP)时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
      
  2. 使能对BKPRTC的访问

    •   	//使能对BKP和RTC的访问PWR_BackupAccessCmd(ENABLE);
      
  3. 开启LSE(外部低速时钟)时钟(RCC模块中)

  4. 配置RTCCLK数据选择器,指定LSERTCCLK的时钟源(RCC模块中)

  5. 等待:

    1. 前一次写操作结束
    2. 等待寄存器同步标志位被置位
  6. 配置PRL重装寄存器

  7. 配置CNT

  8. 选配闹钟和中断

MyRTC.c
#include "stm32f10x.h"                  // Device headervoid MyRTC_Init(void)
{//开启电源(PWR)和备份寄存器(BKP)时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);PWR_BackupAccessCmd(ENABLE);//使能对BKP和RTC的访问RCC_LSEConfig(RCC_LSE_ON);//开启LSE时钟while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == !SET);//等待LSE启动完成RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//指定LSE为RTC的时钟源RCC_RTCCLKCmd(ENABLE);//使能RTCCLK的时钟RTC_WaitForLastTask();//等待RTC上一个任务完成RTC_WaitForSynchro();//等待RTC同步RTC_SetPrescaler(32768 - 1);//(0~32767所以要减1)配置预分频器的值(32.768kHz/32768 = 1)RTC_WaitForSynchro();//写入寄存器时都需要等待RTC同步RTC_SetCounter(1735660800);//配置计数器CNT的值(时间戳)【2025-01-1 0:0:00】RTC_WaitForSynchro();//等待RTC同步
}

七、示例:实时时钟

①、main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"int main(void)
{OLED_Init();MyRTC_Init();OLED_ShowString(1,1,"Date:    -  -");OLED_ShowString(2,1,"Time:  :  :");OLED_ShowString(3,1,"CNT :");OLED_ShowString(4,6,"DIV:");OLED_ShowHexNum(4,1, BKP_ReadBackupRegister(BKP_DR1), 4);struct tm* DATA;while(1){DATA = MyRTC_Get_Time();OLED_ShowNum(1,6, DATA->tm_year + 1900,4);//年OLED_ShowNum(1,11,DATA->tm_mon + 1,2);		//月OLED_ShowNum(1,14,DATA->tm_mday,2);				//日OLED_ShowNum(2,6, DATA->tm_hour,2);				//时OLED_ShowNum(2,9, DATA->tm_min ,2);				//分OLED_ShowNum(2,12,DATA->tm_sec ,2);				//秒OLED_ShowNum(3,6,RTC_GetCounter(),10);OLED_ShowNum(4,10,RTC_GetDivider(),6);}
}

②、MyRTC.c

可通过设置Timestamp时间戳变量来设置系统时间

#include "stm32f10x.h"                  // Device header
#include "MyRTC.h"#define TIME_ZONE_OFFSET (8 * 60 * 60)// 东八区时区偏移量(秒)time_t Timestamp = 1735660780;//所设置时间的时间戳void MyRTC_Init(void)
{//开启电源(PWR)和备份寄存器(BKP)时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);PWR_BackupAccessCmd(ENABLE);//使能对BKP和RTC的访问//加上if_else是为了防止重复初始化和时间重置if(BKP_ReadBackupRegister(BKP_DR1) != 0x1212){RCC_LSEConfig(RCC_LSE_ON);//开启LSE时钟while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);//等待LSE启动完成RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//指定LSE为RTC的时钟源RCC_RTCCLKCmd(ENABLE);//使能RTCCLK的时钟RTC_WaitForSynchro();//等待RTC同步RTC_WaitForLastTask();//等待RTC上一个任务完成RTC_SetPrescaler(32768 - 1);//(0~32767所以要减1)配置预分频器的值(32.768kHz/32768 = 1)RTC_WaitForLastTask();//每一次写入操作都需要等待RTC上一个任务完成//		RTC_SetCounter(1735660800);//配置计数器CNT的值(时间戳)【2025-01-1 0:0:00】
//		RTC_WaitForLastTask();//等待RTC上一个任务完成MyRTC_Set_Time();//在备份寄存器写入自己规定的标志位,用于判断RTC是不是第一次执行配置BKP_WriteBackupRegister(BKP_DR1, 0x1212);}else{RTC_WaitForSynchro();//等待RTC同步RTC_WaitForLastTask();//等待RTC上一个任务完成}
}void MyRTC_Set_Time(void)//设置时间
{	RTC_SetCounter(Timestamp);//配置计数器CNT的值(时间戳)RTC_WaitForSynchro();//等待RTC同步
}struct tm* MyRTC_Get_Time(void)//获取时间
{time_t time_cnt;time_cnt = RTC_GetCounter() + TIME_ZONE_OFFSET;//东八区 加上8天(即8*60*60秒)struct tm* Temp;Temp = localtime(&time_cnt);return Temp;
}

③、MyRTC.h

#ifndef __MYRTC_H__
#define __MYRTC_H__
#include "stdint.h"
#include <time.h>extern time_t Timestamp;//所设置时间的时间戳void MyRTC_Init(void);
void MyRTC_Set_Time(void);//设置时间
struct tm* MyRTC_Get_Time(void);//获取时间#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/5378.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop•搭建完全分布式集群

听说这里是目录哦 一、安装Hadoop&#x1f955;二、配置Hadoop系统环境变量&#x1f96e;三、验证Hadoop系统环境变量是否配置成功&#x1f9c1;四、修改Hadoop配置文件&#x1f36d;五、分发Hadoop安装目录&#x1f9cb;六、分发系统环境变量文件&#x1f368;七、格式化HDFS文…

网络通信---MCU移植LWIP

使用的MCU型号为STM32F429IGT6&#xff0c;PHY为LAN7820A 目标是通过MCU的ETH给LWIP提供输入输出从而实现基本的Ping应答 OK废话不多说我们直接开始 下载源码 LWIP包源码&#xff1a;lwip源码 -在这里下载 ST官方支持的ETH包&#xff1a;ST-ETH支持包 这里下载 创建工程 …

将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch(3.纯python的实惠版)

前情&#xff1a; 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch&#xff08;1.标准版&#xff09;-CSDN博客 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch&#xff08;2.换掉付费的Event Hubs&#xff09;-CSDN博客 python脚本实现 厉害的…

Kafka-常见的问题解答

讲一讲分布式消息中间件 问题 什么是分布式消息中间件&#xff1f;消息中间件的作用是什么&#xff1f;消息中间件的使用场景是什么&#xff1f;消息中间件选型&#xff1f; 分布式消息是一种通信机制&#xff0c;和 RPC、HTTP、RMI 等不一样&#xff0c;消息中间件采用分布式…

Android系统开发(六):从Linux到Android:模块化开发,GKI内核的硬核科普

引言&#xff1a; 今天我们聊聊Android生态中最“硬核”的话题&#xff1a;通用内核镜像&#xff08;GKI&#xff09;与内核模块接口&#xff08;KMI&#xff09;。这是内核碎片化终结者的秘密武器&#xff0c;解决了内核和供应商模块之间无尽的兼容性问题。为什么重要&#x…

数据结构-二叉树

树的相关概念&#xff1a; 1、节点的度&#xff1a;树中一个节点的孩子个数称为该节点的度&#xff0c; 所有节点的度的最大值是树的度 2、分支节点&#xff1a;度大于0的节点称为分支节点 3、叶子结点&#xff1a;度为0的节点称为叶子结点 4、节点的层次&#xff08;深度&…

他把智能科技引入现代农业领域

江苏田倍丰农业科技有限公司&#xff08;以下简称“田倍丰”&#xff09;是一家专注于粮油种植的农业科技公司&#xff0c;为拥有300亩以上田地的大户提供全面的解决方案。田倍丰通过与当地政府合作&#xff0c;将土地承包给大户&#xff0c;并提供农资和技术&#xff0c;实现利…

python进程池、线程池

Python广为使用的并发处理库futures使用入门与内部原理_concurrent.futures-CSDN博客 ThreadPoolExecutor(max_workers1) 池中至多创建max_workers个线程的池来同时异步执行&#xff0c;返回Executor实例、支持上下文&#xff0c;进入时返回自己&#xff0c;退出时调用 submit(…

51c~SLAM~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/12327374 #GSLAM 自动驾驶相关~~~ 一个通用的SLAM架构和基准 GSLAM&#xff1a;A General SLAM Framework and Benchmark 开源代码&#xff1a;https://github.com/zdzhaoyong/GSLAM SLAM技术最近取得了许多成功&am…

Node.js 完全教程:从入门到精通

Node.js 完全教程&#xff1a;从入门到精通 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;允许开发者在服务器端使用 JavaScript。它的非阻塞 I/O 和事件驱动架构使得 Node.js 非常适合于构建高性能的网络应用。本文将详细介绍 Node.js 的安装、基本语…

【JVM-9】Java性能调优利器:jmap工具使用指南与应用案例

在Java应用程序的性能调优和故障排查中&#xff0c;jmap&#xff08;Java Memory Map&#xff09;是一个不可或缺的工具。它可以帮助开发者分析Java堆内存的使用情况&#xff0c;生成堆转储文件&#xff08;Heap Dump&#xff09;&#xff0c;并查看内存中的对象分布。无论是内…

(二叉树)

我们今天就开始引进一个新的数据结构了&#xff1a;我们所熟知的&#xff1a;二叉树&#xff1b; 但是我们在引进二叉树之前我们先了解一下树&#xff1b; 树 树的概念和结构&#xff1a; 树是⼀种⾮线性的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09; …

电脑如何访问手机文件?

手机和电脑已经深深融入了我们的日常生活&#xff0c;无时无刻不在为我们提供服务。除了电脑远程操控电脑外&#xff0c;我们还可以在电脑上轻松地访问Android或iPhone手机上的文件。那么&#xff0c;如何使用电脑远程访问手机上的文件呢&#xff1f; 如何使用电脑访问手机文件…

ABP - 缓存模块(1)

ABP - 缓存模块&#xff08;1&#xff09; 1. 与 .NET Core 缓存的关系和差异2. Abp 缓存的使用2.1 常规使用2.2 非字符串类型的 Key2.3 批量操作 3. 额外功能 1. 与 .NET Core 缓存的关系和差异 ABP 框架中的缓存系统核心包是 Volo.Abp.Caching &#xff0c;而对于分布式缓存…

【RAG落地利器】向量数据库Chroma入门教程

安装部署 官方有pip安装的方式&#xff0c;为了落地使用&#xff0c;我们还是采用Docker部署的方式&#xff0c;参考链接来自官方部署: https://cookbook.chromadb.dev/running/running-chroma/#docker-compose-cloned-repo 我们在命令终端运行&#xff1a; docker run -d --…

基于Python django的音乐用户偏好分析及可视化系统设计与实现

1.1 论文背景 随着信息技术的快速发展&#xff0c;在线音乐服务已成为日常生活的重要组成部分。QQ音乐&#xff0c;凭借其创新的音乐推荐算法和独特的社交特性&#xff0c;成功在竞争激烈的市场中获得一席之地。该平台的歌单文化和评论文化不仅满足了用户自尊和自我实现的需求…

以Python构建ONE FACE管理界面:从基础至进阶的实战探索

一、引言 1.1 研究背景与意义 在人工智能技术蓬勃发展的当下,面部识别技术凭借其独特优势,于安防、金融、智能终端等众多领域广泛应用。在安防领域,可助力监控系统精准识别潜在威胁人员,提升公共安全保障水平;金融行业中,实现刷脸支付、远程开户等便捷服务,优化用户体…

以单用户模式启动 Linux 的方法

注&#xff1a;本文为 “Linux 启动单用户模式” 相关文章合辑。 未整理去重。 以单用户模式启动 linux 的三种方法 作者&#xff1a; Magesh Maruthamuthu 译者&#xff1a; LCTT Xiaobin.Liu 2020-05-03 23:01 单用户模式&#xff0c;也被称为维护模式&#xff0c;超级用户…

【C++】size_t全面解析与深入拓展

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;一、什么是size_t&#xff1f;为什么需要size_t&#xff1f; &#x1f4af;二、size_t的特性与用途1. size_t是无符号类型示例&#xff1a; 2. size_t的跨平台适应性示例对…

YOLOv9改进,YOLOv9检测头融合RFAConv卷积,适合目标检测、分割任务

摘要 空间注意力已广泛应用于提升卷积神经网络(CNN)的性能,但它存在一定的局限性。作者提出了一个新的视角,认为空间注意力机制本质上解决了卷积核参数共享的问题。然而,空间注意力生成的注意力图信息对于大尺寸卷积核来说是不足够的。因此,提出了一种新型的注意力机制—…