【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.mzph.cn/pingmian/67561.shtml

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

相关文章

Asp .Net Core 实现微服务:集成 Ocelot+Nacos+Swagger+Cors实现网关、服务注册、服务发现

什么是 Ocelot ? Ocelot是一个开源的ASP.NET Core微服务网关&#xff0c;它提供了API网关所需的所有功能&#xff0c;如路由、认证、限流、监控等。 Ocelot是一个简单、灵活且功能强大的API网关&#xff0c;它可以与现有的服务集成&#xff0c;并帮助您保护、监控和扩展您的…

性价比1.2V电压基准替代

前言&#xff1a; 小于2V的电压基准比较少&#xff0c;且价格稍贵&#xff0c;对于要求不高的场合&#xff0c;1117可以替代使用&#xff0c;温度系数低于 100ppm/C, 价格便宜。 1117是线性稳压器的一种&#xff0c;一般情况下&#xff0c;输出电压可调。 如下述的1117&#xf…

使用 Java 和 FreeMarker 实现自动生成供货清单,动态生成 Word 文档,简化文档处理流程。

在上一篇博客中主要是使用SpringBootApache POI实现了BOM物料清单Excel表格导出&#xff0c;详见以下博客&#xff1a; Spring Boot Apache POI 实现 Exc&#xff08;&#xff09;el 导出&#xff1a;BOM物料清单生成器&#xff08;支持中文文件名、样式美化、数据合并&#…

探索与创作:2024年CSDN平台上的成长与突破

文章目录 我与CSDN的初次邂逅初学阶段的阅读CSDN&#xff1a;编程新手的避风港初学者的福音&#xff1a;细致入微的知识讲解考试复习神器&#xff1a;技术总结的“救命指南”曾经的自己&#xff1a;为何迟迟不迈出写博客的第一步兴趣萌芽&#xff1a;从“读”到“想写”的初体验…

SSM课设-学生管理系统

【课设者】SSM课设-学生管理系统 技术栈: 后端: SpringSpringMVCMybatisMySQLJSP 前端: HtmlCssJavaScriptEasyUIAjax 功能: 学生端: 登陆 学生信息管理 个人信息管理 老师端: 多了教师信息管理 管理员端: 多了班级信息管理 多了年级信息管理 多了系统用户管理

力扣 打家劫舍

动态规划&#xff0c;当前状态由前两个状态获得&#xff0c;滚动数组。 题目 从题可以看出要达到最高金额时&#xff0c;要从相邻的房屋拿。因此是当前房屋的金额隔一个做累加&#xff0c;当然还需要跟前一个相邻的房屋做比较&#xff0c;便于取到哪边金额更高&#xff0c;因此…

【Django开发】django美多商城项目完整开发4.0第12篇:商品部分,表结构【附代码文档】

本教程的知识点为&#xff1a; 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计&#xff1a; 视图原型 2. 具体视图实现 用户部分 使用Celery完成发送 判断帐号是否存在 1. 判断用户名是否存在 后…

Redis的安装和使用--Windows系统

Redis下载地址&#xff1a; windows版本readis下载&#xff08;GitHub&#xff09;&#xff1a; https://github.com/tporadowski/redis/releases &#xff08;推荐使用&#xff09; https://github.com/MicrosoftArchive/redis/releases 官网下载&#xff08;无Windows版本…

Linux操作命令之云计算基础命令

一、图形化界面/文本模式 ctrlaltF2-6 图形切换到文本 ctrlalt 鼠标跳出虚拟机 ctrlaltF1 文本切换到图形 shift ctrl "" 扩大 ctrl "-" 缩小 shift ctrl "n" 新终端 shift ctrl "t" 新标签 alt 1,…

LabVIEW桥接传感器配置与数据采集

该LabVIEW程序主要用于配置桥接传感器并进行数据采集&#xff0c;涉及电压激励、桥接电阻、采样设置及错误处理。第一个VI&#xff08;"Auto Cleanup"&#xff09;用于自动清理资源&#xff0c;建议保留以确保系统稳定运行。 以下是对图像中各个组件的详细解释&#…

网络编程 | UDP广播通信

1、什么是广播 在上一篇博客文章中已经对UDP进行了详细的说明介绍及如何编程实现。本文将接着上一文的内容&#xff0c;在其基础上&#xff0c;对UDP的知识体系进一步深入的讲解。 网络编程 | UDP套接字通信及编程实现经验教程-CSDN博客 例子&#xff1a;在一些中小学的操场中&…

Count Sketch--计数草图

背景 Count Sketch 是一种空间高效的概率型数据结构&#xff0c;由 Moses Charikar、Kevin Chen 和 Martin Farach-Colton 在 2002 年提出&#xff0c;用于估计数据流中元素的频率&#xff0c;也可用于解决重击者问题。 原理 算法结构 参数设定&#xff1a;Count Sketch算法…

2025.1.17——三、SQLi regexp正则表达式|

题目来源&#xff1a;buuctf [NCTF2019]SQLi1 目录 一、打开靶机&#xff0c;整理信息 二、解题思路 step 1&#xff1a;正常注入 step 2&#xff1a;弄清关键字黑名单 1.目录扫描 2.bp爆破 step 3&#xff1a;根据过滤名单构造payload step 4&#xff1a;regexp正则注…

搭建一个基于Spring Boot的书籍学习平台

搭建一个基于Spring Boot的书籍学习平台可以涵盖多个功能模块&#xff0c;例如用户管理、书籍管理、学习进度跟踪、笔记管理、评论和评分等。以下是一个简化的步骤指南&#xff0c;帮助你快速搭建一个基础的书籍学习平台。 — 1. 项目初始化 使用 Spring Initializr 生成一个…

【Linux 之一 】Linux常用命令汇总

Linux常用命令 ./catcd 命令chmodclearcphistoryhtoplnmkdirmvpwdrmtailunamewcwhoami 我从2021年4月份开始才开始真正意义上接触Linux&#xff0c;最初学习时是一脸蒙圈&#xff0c;啥也不会&#xff0c;啥也不懂&#xff0c;做了很多乱七八糟&#xff0c;没有条理的笔记。不知…

Hexo + NexT + Github搭建个人博客

文章目录 一、 安装二、配置相关项NexT config更新主题主题样式本地实时预览常用命令 三、主题设置1.侧边栏2.页脚3.帖子发布字数统计 4.自定义自定义页面Hexo 的默认页面自定义 404 页自定义样式 5.杂项搜索服务 四、第三方插件NexT 自带插件评论系统阅读和访问人数统计 五、部…

开发神器之cursor

文章目录 cursor简介主要特点 下载cursor页面的简单介绍切换大模型指定ai学习的文件指定特定的代码喂给ai创建项目框架文件 cursor简介 Cursor 是一款专为开发者设计的智能代码编辑器&#xff0c;集成了先进的 AI 技术&#xff0c;旨在提升编程效率。以下是其主要特点和功能&a…

当前目录不是一个git仓库/远程仓库已经有了一些你本地没有的更改

目录 问题1&#xff1a;问题2&#xff1a;解决1解决2 问题1&#xff1a; fatal: not a git repository (or any parent up to mount point /) Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set). # 初始化 Git 仓库 git init需要到本地目录下先添加…

差异基因富集分析(R语言——GOKEGGGSEA)

接着上次的内容&#xff0c;上篇内容给大家分享了基因表达量怎么做分组差异分析&#xff0c;从而获得差异基因集&#xff0c;想了解的可以去看一下&#xff0c;这篇主要给大家分享一下得到显著差异基因集后怎么做一下通路富集。 1.准备差异基因集 我就直接把上次分享的拿到这…

BGP边界网关协议(Border Gateway Protocol)路由引入、路由反射器

一、路由引入背景 BGP协议本身不发现路由&#xff0c;因此需要将其他协议路由&#xff08;如IGP路由等&#xff09;引入到BGP路由表中&#xff0c;从而将这些路由在AS之内和AS之间传播。 BGP协议支持通过以下两种方式引入路由&#xff1a; Import方式&#xff1a;按协议类型将…