STM32物联网项目-RTC时钟

article/2025/8/6 21:03:41

RTC时钟

RTC简介

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。

系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。

执行以下操作将使能对后备寄存器和RTC的访问:

1、设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟

2、设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。

实验目标

通过串口可以设置RTC时钟的日期和时间,设置好后,可以在数码管上显示设定的时间,同时日期和时间也会被实时发送到串口上进行显示;并且系统复位或者断电后,RTC的时钟依然运行

RTC供电

由STM32电源框图可以看到,当主电源VDD掉电后,通过VBAT脚为实时时钟(RTC)和备份寄存器提供电源

在这里插入图片描述

因为RTC时钟在系统断电后需要继续工作,就需要用电池连接到VBAT引脚上,给RTC提供电源,当电池被拔掉后,RTC也不能工作了

在这里插入图片描述

CubeMX配置

RTC配置

激活RTC

在这里插入图片描述

参数默认即可

在这里插入图片描述

时钟树配置

选择外部32.768KHz的低速时钟源,直接给到RTC时钟

从时钟树可以看出,RTC时钟源还可以选择HSE的128分频和内部低速时钟LSI RC,那为什么要使用LSE外部低速时钟源呢?

因为HSE在系统断电后是不起振了,无法提供时钟源,而内部LSI随着芯片停止工作也不起振,还有原因是LSE比较精确
在这里插入图片描述

串口1配置

因为需要串口来设置时间和打印时间,所以初始化串口1
在这里插入图片描述

程序

Public.c

因为使用到串口输入字符串来设置RTC的时钟,所以与printf函数重定向一样,将 getchar 的底层函数 fgetc 映射到物理串口,后面只需使用getchar()函数即可接收串口发来的信息

/*
* @name   fgetc
* @brief  fgetc映射到物理串口
* @param  None
* @retval ch:已接收的字符
*/
int fgetc(FILE* f)
{uint8_t ch = 0;//通过查询方法等待接收HAL_UART_Receive(&huart_debug,&ch,1,0xFFFF);return ch;
}

MyRTC.c

设置RTC的日期和时间,日期就是年,月,日,星期,时间是时,分,秒,进入函数会首先判断RTC备份寄存器1的值,因为该寄存器不会被系统复位,断电复位或者待机模式唤醒复位,在设置好一次RTC的日期和时间后,往该寄存器里写入一个随机值,下次就会通过判断该寄存器的值,如果没被修改,则说明已经设置过日期和时间,不用再设置,如果值被修改,则进行设置日期和时间的操作

有两种方法可修改RTC的值,方法一:修改备份寄存器的值,通过触摸按键来实现;方法二:系统断电的时候拔掉VBAT的电池,RTC则停止工作,上电后会重新设置时间

/*
* @name   Calendar_Set
* @brief  设置日历
* @param  None
* @retval None   
*/
static void Calendar_Set()
{/*上电复位时,读取RTC备份寄存器1的值,如果为0xAAAA,表示已经设置了时间,不需要重新设置注:0xAAAA是自己随便设定的值,该寄存器不会被系统复位,电源复位或从待机模式唤醒而复位,所以该寄存器的值在断电后依然保持不变,判断该寄存器是否有预设定值,有就表示已经设置了时间*/if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1) != 0xAAAA){printf("开始设置RTC的日期和时间\r\n\r\n");RTC_Date_Set();   //设置日期RTC_Time_Set();   //设置时间//设置完日期和时间后写RTC备份寄存器1的值,表示日期和时间已经设定HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,0xAAAA);}else{printf("RTC的日期和时间已经设置\r\n\r\n");printf("重新设置的方法如下:\r\n");printf("方法一:长按触摸按键1两秒以上\r\n");printf("方法二:系统断电,同时拔掉RTC电池\r\n");}
}

设置RTC日期

定义一个日期结构体变量,从串口接收年,月,日的数据后,调用函数HAL_RTC_SetDate将日期写入到结构体变量中;

设置RTC时间的函数类似,只是最大值不同,时钟是23,分钟是59,秒钟也是59

/*
* @name   RTC_Date_Set
* @brief  设置RTC日期
* @param  None
* @retval None   
*/
static void RTC_Date_Set()
{RTC_DateTypeDef RTC_DateStruct;   //定义一个日期结构体变量uint8_t SetValue;printf("=============日期设置===========\r\n");printf("请输入年份(00-99):20\r\n");//等待串口设置SetValue = 0xFF;while(SetValue == 0xFF){//对串口输入值进行校验后,再赋给SetValue,参数99表示年份的最大值SetValue = Input_RTC_SetValue(99);}printf("年份被设置为:20%02u\r\n",SetValue);RTC_DateStruct.Year = SetValue;printf("请输入月份(1-12):\r\n");SetValue = 0xFF;while(SetValue == 0xFF){SetValue = Input_RTC_SetValue(12);if(SetValue == 0x00){printf("月份不能设置为0,请重新输入月份:\r\n");SetValue = 0xFF;}}printf("月份被设置为:%02u\r\n",SetValue);RTC_DateStruct.Month = SetValue;printf("请输入日期(01-31):\r\n");SetValue = 0xFF;while(SetValue == 0xFF){SetValue = Input_RTC_SetValue(31);if(SetValue == 0x00){printf("日期不能设置为0,请重新输入日期:\r\n");SetValue = 0xFF;}}printf("日期被设置为:%02u\r\n",SetValue);RTC_DateStruct.Date = SetValue;//设置日期——二进制数据格式HAL_RTC_SetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);
}

stm32f1xx_hal_rtc.h

通过查看RTC的HAL库头文件可以看到,RTC日期结构体的年份的取值范围是0到99,所以不能直接设置如2022这样的数值,但串口打印年份时可加上2000,数码管显示同理

/*** @brief  RTC Date structure definition*/
typedef struct
{uint8_t WeekDay;  /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).This parameter can be a value of @ref RTC_WeekDay_Definitions */uint8_t Month;    /*!< Specifies the RTC Date Month (in BCD format).This parameter can be a value of @ref RTC_Month_Date_Definitions */uint8_t Date;     /*!< Specifies the RTC Date.This parameter must be a number between Min_Data = 1 and Max_Data = 31 */uint8_t Year;     /*!< Specifies the RTC Date Year.This parameter must be a number between Min_Data = 0 and Max_Data = 99 */} RTC_DateTypeDef;

MyRTC.c

Input_RTC_SetValue函数是接收串口的设置值,并判断其有效性

/*
* @name   Input_RTC_SetValue
* @brief  输入RTC设置值
* @param  None
* @retval None   
*/
static uint8_t Input_RTC_SetValue(uint8_t MaxValue)
{uint8_t SetValue = 0;                 //返回值uint8_t Value_Arr[2] = {0};     //串口接收缓存uint8_t Index = 0;//以等待方式从串口2接收两个字符while (Index < 2){//等待串口接收数据Value_Arr[Index++] = getchar();//校验数据有效性if((Value_Arr[Index-1] < '0')||(Value_Arr[Index-1] > '9')){printf("请输入0 到 9之间的数字-->\r\n");Index--;    //下标减1,重新接收}}//接收到的两个字符转化为数值SetValue = (Value_Arr[0]-'0')*10 +(Value_Arr[1]-'0');//判断返回值有效性if(SetValue > MaxValue){printf("请输入 0 到 %d 之间的数字\r\n",MaxValue);SetValue = 0xFF;}return SetValue;
}

只需调用HAL库的RTC获取日期和时间就能得到刚刚通过串口设置的值,通过指针,MyRTC.pRTC_DataStruct保存到文件开头定义的结构体变量中

/*
* @name   Calendar_Get
* @brief  获取日历
* @param  None
* @retval None   
*/
static void Calendar_Get()
{//获取当前日期HAL_RTC_GetDate(&hrtc,MyRTC.pRTC_DataStruct,RTC_FORMAT_BIN);//获取当前时间HAL_RTC_GetTime(&hrtc,MyRTC.pRTC_TimeStruct,RTC_FORMAT_BIN);
}

System.c

主函数判断RTC的设置标志位RTC_Set_Flag,该标志位初始化为TRUE,所以一上电就会先进行RTC的日期和时间设置

/*
* @name   Run
* @brief  系统运行
* @param  None
* @retval None   
*/
static void Run()
{if(MyRTC.RTC_Set_Flag == TRUE){MyRTC.RTC_Set_Flag = FALSE;//设置RTC日期和时间MyRTC.Calendar_Set();}//获取RTC日期和时间MyRTC.Calendar_Get();//显示RTC日期和时间MyRTC.Calendar_Show();//延时HAL_Delay(1000);
}

注意:

分析框图,RTC的后备区域没有日期寄存器,断电恢复后,没法直接读取日期;如果需要读取断电恢复后日期更新值,有两种方法:

方法一:使用高级些的MCU,比如STM32F4,RTC自带日期寄存器。缺点:MCU成本贵

方法二:利用32位可编程计数器进行计算。具体方法是:假定计数器为0时,为一个起始日期,比如2000年1月1日;设定日期后,减去起始日期,换算成秒钟初始化给计数器;断电后,计数器值不重新装载,与设定日期对比,换算出当前日期。

缺点:

1、不能使用HAL库编程,因为这种方法是自己设计的,没有库函数

2、需要CPU大量计算,效率低;

3、RTC溢出与闹钟功能不可用。

实验效果

在这里插入图片描述


http://chatgpt.dhexx.cn/article/SFXGhLLZ.shtml

相关文章

十九、RTC实时时钟

一、.RTC实时时钟工作框图 RTC 由两个主要部分组成&#xff0c;第一部分(APB1 接口)用来和 APB1 总线相连。此单元还包含一组 16 位寄存器&#xff0c;可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总线时钟驱动&#xff0c;用来与 APB1 总线连接。 RTC_PRL设置100&a…

STM32 RTC时钟读取时间

文章目录 一、RTC简介1.1 RTC1.2 RTC特征1.3 RTC原理框图1.4 RTC工作流程1.5 RTC时钟选择1.6 RTC复位过程1.7 RTC中断 二、CubeMX配置2.1 RCC配置2.2 SYS配置2.3 RTC配置2.4 串口配置2.5 时钟配置2.6 生成项目代码 三、代码编写3.1 重写printf3.2 RTC_HAL库函数/*设置系统时间*…

STM32 RTC实时时钟

我用的是STM32库函数&#xff1a;两个知识点&#xff1a; 一、RTC时钟框图分析&#xff08;重要&#xff09; 二、时间是怎样显示出来的&#xff08;简析&#xff09; 一、RTC时钟框图分析&#xff08;重要&#xff09; 先熟悉一下几个知识点&#xff1a; …

STM32之RTC时钟,闹钟,日历

RTC时钟的一些功能介绍 RTC时钟即实时时钟&#xff0c;它提供了用于管理所有低功耗模式的自动唤醒单元&#xff0c;还提供了具有可编程闹钟中断功能的日历时钟/日历。 并且可以自动将月份的天数补偿为 28、29&#xff08;闰年&#xff09;、30 和 31 天。并且还可以进行夏令时…

深入学习RTC时钟库 DS1302

❤️博主介绍❤️ &#x1f62c; 作者&#xff1a;单片机菜鸟哥 &#x1f449;火爆博客&#xff1a;ESP8266 Arduino教程 零基础从入门到熟悉Arduino平台下开发ESP8266&#xff0c;同时会涉及网络编程知识。专栏文章累计超过60篇&#xff0c;分为基础篇、网络篇、应用篇、高级篇…

深入学习 RTC时钟库 DS3231

❤️博主介绍❤️ &#x1f62c; 作者&#xff1a;单片机菜鸟哥 &#x1f449;火爆博客&#xff1a;ESP8266 Arduino教程 零基础从入门到熟悉Arduino平台下开发ESP8266&#xff0c;同时会涉及网络编程知识。专栏文章累计超过60篇&#xff0c;分为基础篇、网络篇、应用篇、高级篇…

rtc时钟

一、设计效果 配置RTC时钟&#xff0c;初始化为2000年1月1日00:00:00&#xff1b;通过RTC时钟秒中断串口每秒打印一次当前时刻&#xff0c;并切换一次流水灯状态&#xff1b;配置闹铃为10:00:05&#xff0c;在闹铃中断中每秒切换一次蜂鸣器状态闹铃&#xff0c;直到按KEY1关闭…

RTC时钟实现实时日历

文章目录 1、RTC时钟简介1.2、初识RTC1.2、相关寄存器 2、创建项目23、完善代码4、总结 1、RTC时钟简介 1.2、初识RTC 1、简介&#xff1a; RTC—real time clock&#xff0c;实时时钟&#xff0c;主要包含日历、闹钟和自动唤醒这三部分的功能&#xff0c;其中的日历功能我们使…

STM32之RTC时钟

前言 了解实时时钟RTC的原理。STM32芯片自带RTC&#xff0c;因此不须像其他MCU需外接RTC模块。请编程实现STM32的日历读取、设置和输出。要求&#xff1a; 1&#xff09;读取RTC初始时间&#xff0c;验证是否为 1970年1月1日零分零秒&#xff1b; 2&#xff09;将RTC时间调整为…

【STM32】HAL库 STM32CubeMX教程十三---RTC时钟

前言&#xff1a; 本系列教程将 对应外设原理&#xff0c;HAL库与STM32CubeMX结合在一起讲解&#xff0c;使您可以更快速的学会各个模块的使用 所用工具&#xff1a; 1、芯片&#xff1a; STM32F407ZET6/ STM32F103ZET6 2、STM32CubeMx软件 3、IDE&#xff1a; MDK-Keil软…

【STM32】详解RTC实时时钟的概念和配置示例代码

一、什么是RTC RTC(Real-time Clock)&#xff1a;实时时钟&#xff0c;本质上是一个支持BCD编码的定时器/计数器。主电源断电后能够由电池供电&#xff0c;使其时钟跳转依然正常。 二、STM32F4芯片内的RTC功能 ①日历时钟&#xff08;时分秒、年月日、星期&#xff09; ②两个闹…

android小错误:Failure retrieving text 0x7f050001 in package

1.在启动android应用程序的过程中&#xff0c;logcat打印如下的错误&#xff1a; 报错的原因&#xff1a;资源的id没有找到。资源在R.java文件中&#xff0c;找到0x7f050001 对应的定义 R.java public static final int AppTheme0x7f050001; AppTheme这个文件在AndroidMan…

Windows7系统蓝屏-解决办法, 错误代码:0x0000007F

1.电脑突然蓝屏提示stop:0x0000007F&#xff0c;如下图所示&#xff1a; 2.故障排除 重启电脑&#xff0c;一直按F8&#xff0c;进入“安全模式”&#xff0c;如能正常进入系统&#xff0c;查看系统错误日志。针对系统记录的错误日志&#xff0c;解决问题。如下图&#xff0c;…

java.lang.IllegalArgumentException No view found for id 0x7

java.lang.IllegalArgumentException No view found for id 0x7 布局上找不到这个View&#xff0c;看下ERROR的地方&#xff0c;可以看到是因为Container找不到因此报错了。 从布局入手&#xff0c;参考了很多文章主要分为以下两种原因 1 Fragment 嵌套了 Fragment 例如&…

Fragment报java.lang.IllegalArgumentException:No view found for id 0x7f070250的错误

我用的是Fragment嵌套Fragment做的&#xff0c;放fragment切换快的时候程序就会崩溃&#xff0c;解决这个办法就是在View生成前先将FragemnentManger创建好&#xff0c;就不会报错了

Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7f解析

先看日志报错这个错误纠结我两天了&#xff0c;真的要崩溃了~_~ 关于android.content.res.Resources$NotFoundException: Resource ID的问题&#xff0c;那行代码是onCreate加载.xml布局&#xff0c;是加载的R.layout.xxxx&#xff0c;不是R.id.xxxx&#xff0c;布局文件存在&a…

关于No view found for id 0x7f080135 (com.xxx.xxx:id/viewpager) for fragment PopupWindow

最近在开发项目中&#xff0c;遇到了一个问题。PopupWindow中无法嵌套viewpagerFragment&#xff0c;现在进行总结一下。 问题描述&#xff1a;在Fragment中弹出一个PopupWindow,PopupWindow中用viewpager加载多个Fragment时出现上面问题。 网上搜的都是那些什么没有设置id之…

流水灯设计

流水灯设计 目的与要求 通过采用单片机控制8个LED发光二极管顺序点亮的流水灯系统设计与制作&#xff0c;让读者了解C语言的数据类型、常量与变量、运算符和表达式等基本概念及使用方法。 设计要求&#xff1a;首先点亮连接到P1.7引脚的发光二极管&#xff0c;延时一定时间后…

IT管理人才必备的十大能力

公众号回复&#xff1a;干货&#xff0c;领取价值58元/套IT管理体系文档 公众号回复&#xff1a;ITIL教材&#xff0c;领取最新ITIL4中文教材 正文 作为IT技术人员&#xff0c;相信没有一个人愿意永远在底层编写程序或做简单的系统维护。经过一段时间的技术和经验的积累&#x…

他,连续 3 年担任新星计划导师,这次的内容有点特别

一、新星计划 新星计划是一个发掘潜力新人、培养优质博主为目标的创作活动&#xff0c;通过为期两周的时间&#xff0c;明白为什么要写博客&#xff0c;写作的意义是什么&#xff1f;制定学习计划&#xff0c;完善Java知识体系。 二、学习计划 创作打卡阶段第1周&#xff08…