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

stm32入门学习13-时钟RTC

(一)时钟RTC

stm32内部集成了一个秒计数器RTC,用于显示我们日常的时间,如日期年月日,时分秒等,RTC的主要原理就是进行每秒自增,如果我们知道开始记秒的开始时间,就可以计算现在的日期,但是这不需要我们计算,我们只要调用C语言库函数即可自动完成秒数到日常时间或日常时间到秒数的转换,如果只是实现秒自增的功能,那么内部任何一个计数器都可以实现,但是时钟RTC与其他计数器不同的是其可以使用备用电源保持工作,在最小板供电停止时如果有备用电源其会继续工作;这里的备用电源供电引脚为stm32最小板的1好引脚,标注为VBT;

(二)备份寄存器BKP

和时钟RTC一样,备份寄存器BKP可以在备用电源供电时保持数据不丢失,但是其却不能在备用电源和主电源同时断电时候还保持掉电不丢失,这里使用BKP主要是为了给时钟判断是否需要初始化,如果备用电源没有断开,RTC依旧在工作,那么在主电源重新供电的时候时钟就不需要初始化,直接读取其时钟值即可;

(三)RTC时钟和BKP备份寄存器

这里BKP主要是为了检测备用电源是否掉电的,我们的思路是在上电的时候在备份寄存器BKP上写入一个数据(不要写默认值0),如果备用电源没有断电,这个数据会一直保持,如果断电则会恢复为0,我们只要会初始化BKP和读写BKP即可,主要用到这几个函数

void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);
// 写入备份寄存器uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);
// 读出备份寄存器void RTC_WaitForLastTask(void);
// 等待上次任务完成,内部自带while循环和进入RTC的配置模式void RTC_WaitForSynchro(void);
// 等待系统同步,自带while循环和进入RTC的配置模式

(1)BKP初始化

BKP初始化要初始BKP的时钟,还有电源管理模块的时钟RCC_APB1Periph_PWR,以便在使用备用电源时stm32可以进行电源管理进入待机模式,这些时钟都是APB1上的外设,因此我们要调动APB1的初始化函数

void rtc_bkp_init()
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
}

(2)RTC初始化

RTC不想其他外设一样用初始化结构体来进行初始化,我们要对每一步手动初始化,初始化流程图如下

首先要开启RTC的时钟并选择对应通道,然后要写入重装寄存器和预分频值以使得计数器实现每秒自增(即频率为1Hz),当然我们还要打开对应的电源控制

如果在主电源断开但备用电源没有断开时,RTC仍然会工作,但是主电源开始供电时,程序会重启,这时会再次调用RTC的初始化函数,这时不希望的,因此我们在BKP中写入一个标志位,如果该标志位没有清零,表示备用电源和主电源没有同时断电,这时我们就不需要重新对RTC进行初始化,我们在RTC初始化中加入if判断即可

void rtc_init()
{PWR_BackupAccessCmd(ENABLE);if (BKP_ReadBackupRegister(BKP_DR1) != 1){RCC_LSEConfig(RCC_LSE_ON);while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);RCC_RTCCLKCmd(ENABLE);RTC_WaitForSynchro();	// wait synchronizationRTC_WaitForLastTask();	// wait writeRTC_SetPrescaler(32768-1);RTC_WaitForLastTask();rtc_set_time(2024, 8, 9, 16, 7, 0);BKP_WriteBackupRegister(BKP_DR1, 1);}
}

由于RTC的时钟和系统时钟不是一个频率,在开启时钟后要等待时钟同步(synchronization),每次进行写操作时要等待上次任务完成;

这里选择的是外部低速时钟,其晶振为32.768KHz,因此要进行32768分频使其频率为1Hz

(3)设置和读取时间

我们可以从该时钟读取到的只有秒值,且要修改时间也只有输入对应时间的秒数才能修改,但是我们可以借助time库来计算我们常见的时间格式和对应秒数的转换,主要有两个函数和一个结构体

struct tm {int tm_sec;   /* seconds after the minute, 0 to 60(0 - 60 allows for the occasional leap second) */int tm_min;   /* minutes after the hour, 0 to 59 */int tm_hour;  /* hours since midnight, 0 to 23 */int tm_mday;  /* day of the month, 1 to 31 */int tm_mon;   /* months since January, 0 to 11 */int tm_year;  /* years since 1900 */int tm_wday;  /* days since Sunday, 0 to 6 */int tm_yday;  /* days since January 1, 0 to 365 */int tm_isdst; /* Daylight Savings Time flag */union {       /* ABI-required extra fields, in a variety of types */struct {int __extra_1, __extra_2;};struct {long __extra_1_long, __extra_2_long;};struct {char *__extra_1_cptr, *__extra_2_cptr;};struct {void *__extra_1_vptr, *__extra_2_vptr;};};
};
// 时间结构体,对应秒、分、时、日、月、年、星期、天extern _ARMABI time_t mktime(struct tm * /*timeptr*/) __attribute__((__nonnull__(1)));
// 将时间结构体转换为秒数,输入一个时间结构体指针输出其到1990年的秒数,结构体只要年月日即可extern _ARMABI struct tm *localtime(const time_t * /*timer*/) __attribute__((__nonnull__(1)));
// 输入到1990年的秒数输出一个时间结构体指针

这里有一些规定与日常不合,这里的月是从0开始的,年是如今到1900年的年数,星期从星期天(0)开始

这里转换的是伦敦时间,要计算北京时间还要加上8小时(东八区),对应秒数加8*60*60

void rtc_set_time(unsigned int year, unsigned int month, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec)
{struct tm timer;unsigned int counter;timer.tm_year = year-1900;timer.tm_mon = month-1;timer.tm_mday = day;timer.tm_hour = hour;timer.tm_min = min;timer.tm_sec = sec;counter = mktime(&timer);counter -= 8*60*60;RTC_SetCounter(counter);RTC_WaitForLastTask();
}
struct tm* rtc_read_time()
{struct tm* timer;unsigned int counter = RTC_GetCounter() + 8*60*60;timer = localtime(&counter);timer->tm_year += 1900;timer->tm_mon += 1;return timer;
}

(4)封装与声明

最终.c 和 .h文件如下

#include "stm32f10x.h"                  // Device header
#include <time.h>void rtc_set_time(unsigned int year, unsigned int month, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec);void rtc_bkp_init()
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
}void rtc_init()
{PWR_BackupAccessCmd(ENABLE);if (BKP_ReadBackupRegister(BKP_DR1) != 1){RCC_LSEConfig(RCC_LSE_ON);while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);RCC_RTCCLKCmd(ENABLE);RTC_WaitForSynchro();	// wait synchronizationRTC_WaitForLastTask();	// wait writeRTC_SetPrescaler(32768-1);RTC_WaitForLastTask();rtc_set_time(2024, 8, 9, 16, 7, 0);BKP_WriteBackupRegister(BKP_DR1, 1);}
}void rtc_set_time(unsigned int year, unsigned int month, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec)
{struct tm timer;unsigned int counter;timer.tm_year = year-1900;timer.tm_mon = month-1;timer.tm_mday = day;timer.tm_hour = hour;timer.tm_min = min;timer.tm_sec = sec;counter = mktime(&timer);counter -= 8*60*60;RTC_SetCounter(counter);RTC_WaitForLastTask();
}struct tm* rtc_read_time()
{struct tm* timer;unsigned int counter = RTC_GetCounter() + 8*60*60;timer = localtime(&counter);timer->tm_year += 1900;timer->tm_mon += 1;return timer;
}
#ifndef __RTC_H__
#define __RTC_H__void rtc_bkp_init(void);
void rtc_init(void);
void rtc_set_time(unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec);
struct tm* rtc_read_time(void);#endif

(四)主函数

只要在主函数进行对应初始化和调用读取函数即可,初始化已经包含了开始时间的设定,如果要重新设定开始时间,可以在初始化中更改,也可以在主函数中使用rtc_set_time函数来修改,但是要注意上电后stm32复位问题,应该和初始化一样加入备用电源是否断电的判断代码

#include "stm32f10x.h"                  // Device header
#include "rtc.h"
#include "OLED.h"
#include <time.h>int main()
{struct tm* time_inf;OLED_Init();rtc_bkp_init();rtc_init();OLED_ShowString(1, 1, "time:");OLED_ShowString(2, 1, "xxxx-xx-xx");OLED_ShowString(3, 1, "xx:xx:xx");while(1){time_inf = rtc_read_time();OLED_ShowNum(2, 1, time_inf->tm_year, 4);OLED_ShowNum(2, 6, time_inf->tm_mon, 2);OLED_ShowNum(2, 9, time_inf->tm_mday, 2);OLED_ShowNum(3, 1, time_inf->tm_hour, 2);OLED_ShowNum(3, 4, time_inf->tm_min, 2);OLED_ShowNum(3, 7, time_inf->tm_sec, 2);}return 0;
}

(五)总结

通过实现一个时钟,我们学习了RTC和BKP两个可以使用备用电源供电工作的外设,了解了计数器RTC的原理和备份寄存器BKP的原理,通过备份寄存器实现了RTC的掉电继续计时和数据不丢失

相关文章:

stm32入门学习13-时钟RTC

&#xff08;一&#xff09;时钟RTC stm32内部集成了一个秒计数器RTC&#xff0c;用于显示我们日常的时间&#xff0c;如日期年月日&#xff0c;时分秒等&#xff0c;RTC的主要原理就是进行每秒自增&#xff0c;如果我们知道开始记秒的开始时间&#xff0c;就可以计算现在的日…...

vuex properties of undefined (reading ‘getters‘)

前言&#xff1a; 最近打算用vue 写个音乐播放器&#xff0c;在搞 vuex 的时候遇到一个很神奇报错&#xff1b;vuex 姿势练了千百次了&#xff0c;刚开始的时候我一直以为是代码问题&#xff0c;反复检查了带了&#xff0c;依旧报错。 Error in mounted hook: "TypeError:…...

再谈表的约束

文章目录 自增长唯一键外键 自增长 auto_increment&#xff1a;当对应的字段&#xff0c;不给值&#xff0c;会自动的被系统触发&#xff0c;系统会从当前字段中已经有的最大值1操作&#xff0c;得到一个新的不同的值。通常和主键搭配使用&#xff0c;作为逻辑主键。 自增长的…...

认识一下测试策略与测试方案

目录 测试方案 测试策略 测试策略的内容主要包括 测试技术和工具 测试启动、停止和完成标准 风险分析和应对方案 测试范围 测试角色和职责 测试方法和类型 测试工具 测试层级 测试指标 测试可交付成果 测试方案的内容包括 测试目标 测试范围 测试环境 测试策略…...

Gradle 查看包的依赖关系

在 Terminal 中可以通过 gradle 的命令查看项目中使用的依赖库及其版本&#xff0c;并且可以更加直观的看到各个模块中库之间的依赖关系。同时也可以跟踪并解决与库版本冲突有关的问题。 工具查看 在 Android Studio 中选择 View > Tool Windoors > Gradle 或者直接选择…...

虚幻5|给攻击添加特效

一&#xff0c;打开武器蓝图 选择武器网格体&#xff0c;在细节处找到组件开始重叠&#xff0c;点击 写下以下蓝图&#xff0c;这是最终蓝图&#xff0c;后面会分讲要点 二&#xff0c;actor拥有标签&#xff0c;就是被击打的敌人&#xff0c;我们给actor添加标签 到主界面&am…...

Delphi包管理与依赖:掌握GetIt与DelphiPI的艺术

标题&#xff1a;Delphi包管理与依赖&#xff1a;掌握GetIt与DelphiPI的艺术 在Delphi的广袤生态中&#xff0c;包管理和依赖解决方案是构建大型项目不可或缺的工具。本文将深入探讨Delphi中的两种主要包管理工具&#xff1a;GetIt包管理器和DelphiPI&#xff0c;通过实际代码…...

如何使用unittest和pytest进行python脚本的单元测试

1. 关于unittest和pytest unittest是python内置的支持单元测试的模块&#xff0c;他提供了核心类&#xff0c;TestCase&#xff0c;让单元测试 代码的编写不再是从0开始&#xff0c;不再是作坊式&#xff0c;而是标准化&#xff0c;模板化&#xff0c;工厂化。 pytest是第三方…...

Java中的值传递与引用传递

Java中的值传递与引用传递 在Java编程中&#xff0c;理解值传递与引用传递的概念是编写无误代码的关键。这两个概念有时会让人感到困惑&#xff0c;特别是当它们与对象有关时。现在&#xff0c;我们将一步步地解释这两个概念&#xff0c;帮助你彻底理解它们。 1. 值传递与引用…...

Seaborn库

目录 主要功能和特点 使用方法 实例应用 Seaborn库的最新版本有哪些新功能和改进&#xff1f; 如何在Seaborn中实现复杂的数据预处理步骤&#xff0c;例如数据清洗和转换&#xff1f; Seaborn与其他数据可视化库&#xff08;如Matplotlib、Plotly&#xff09;相比有哪些优…...

openresty整合modsecurity

安装依赖包 安装依赖 yum -y install gcc-c flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel libtool libxml2-devel libxslt-devel安装依赖包 ftp://ftp.icm.edu.pl/vol/rzm7/linux-centos-vault/7.8.2003/sclo/x86_64/rh/Packages/d/devtools…...

结构体structure、共用体union

目录 结构体 结构体类型的定义形式 结构体类型的大小 内存计算例子 共用体union 用共用体判断大小端 结构体和共用体对比 qsort&#xff08;&#xff09; 结构体 结构体类型——用来描述复杂数据的一种数据类型 构造类型&#xff08;用户自定义类型&#xff09; struc…...

Spring自动注册-<bean>标签和属性解析

xml文件中最常见也最核心的就是<bean>,<Import>,<beans>,<alias>标签,关于它们的解析主要是BeanDefinitionParserDelegate类中.<bean>标签的解析最为复杂和重要. <bean>标签 processBeanDefinition(ele, delegate)方法中,主要是是对…...

【仿RabbitMQ消息队列】基于C++11中packaged_tack异步线程池

目录 什么是同步和异步&#xff1f; future 使用future和async配合管理异步任务 使用promise和future配合管理异步任务 使⽤std::packaged_task和std::future配合 C11异步线程池 什么是同步和异步&#xff1f; 同步&#xff08;Synchronous&#xff09; 同步编程是指程…...

免费下载专利

给大家提供一个可以免费下载专利的地方 链接&#xff1a;https://www.drugfuture.com/cnpat/cn_patent.asp...

CentOS7安装流程步骤详细教程

1. 简介 1.1. 概述 CentOS 7是一款基于Red Hat Enterprise Linux(RHEL)的开源Linux发行版,它提供了一个稳定、安全、高效的操作系统,适用于企业级应用、服务器、云计算等领域。CentOS 7以其高度的稳定性和安全性而闻名,它广泛应用于各种行业和领域,包括政府、金融、医疗、…...

【大模型从入门到精通17】openAI API 构建和评估大型语言模型(LLM)应用5

这里写目录标题 理论问题&#xff1a;实践问题&#xff1a;理论实践 理论问题&#xff1a; 1.描述评估LLM应用程序输出的重要性&#xff0c;并提及至少三个维度&#xff0c;这些输出应该在这几个维度上被评估。 2.解释在评估LLM应用程序时开发稳健的性能指标的作用&#xff0c…...

苹果手机无iCloud备份下“最近删除”照片的恢复策略

iPhone最近删除清空了照片还能恢复吗&#xff1f;大家都知道&#xff0c;照片对于我们来说是承载着美好回忆的一种形式。它记录着我们的平淡生活&#xff0c;也留住了我们的美好瞬间&#xff0c;因此&#xff0c;具有极其重要的纪念价值。但由于我们的失误操作导致照片被删除&a…...

Docker搭建Minio容器

Docker搭建Minio容器 前言 在上一集我们介绍了分布式文件存储行业解决方案以及技术选型。最终我们决定选用Minio作为分布式文件存储。 那么这集我们就在Docker上搭建Minio容器即可。 Docker搭建Minio容器步骤 创建Minio文件目录 我们选择创建/minio/data目录 修改目录权…...

【C++】多源BFS问题和拓扑排序

目录 多源BFS介绍 单源BFS和多源BFS的区别 SO如何解决多源BFS问题 多源之核心 矩阵 算法思路 代码实现 飞地的数量 算法思路 代码实现 地图中的最高点 算法思路 代码实现 地图分析 算法思路 代码实现 拓扑排序介绍 有向无环图 ​编辑 如何解决这类问题 课…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...