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

STM32G070KBT6的RTC HAL库使用

*配置问题

    首先使能时钟源,这里在时钟配置中选择LSI,为什么后面会说,然后使能Calender结构体,保证可以对RTC的年月日时分秒等进行写入和读取;alarmA和alarmB是闹钟,这里不用就Disable;      Tamper用于检测外部篡改事件(通常用于增强系统的安全性,尤其是在需要保护敏感数据或防止恶意操作的应用中。),使能后会有一个专用引脚,Timestamp是时间戳,使能后会出现一个引脚,当该引脚检测到篡改事件时,可以触发中断或其他响应机制(例如自动清除 RTC 的备份寄存器,以防止敏感数据被读取或篡改。)同时RTC 备份域中的特定寄存器可以记录篡改事件的发生,以便后续分析和处理。

    TimeStamp功能允许在特定事件发生时,记录当前的日期和时间。这对于需要精确记录事件发生时间的应用非常有用。使能后同样会有一个专用引脚,可以记录按钮按下、外部中断、篡改检测等事件的时间,在数据记录系统(RTC 备份域)中,可以为每条记录添加时间戳,以便后续分析。

    Calibration使能后也有一个专用引脚,用于对外输出特定频率的脉冲,外部可以通过该引脚输出的脉冲判断RTC的精度;

    根据我们选择的功能,我们需要配置上述参数,首先Asynchronous Predivider value和Synchronous Predivider value用于将RTC的时钟分频,我们一般进行秒级计数,所以将其分频到1HZ,计算方法为:时钟源频率/(Asynchronous Predivider value+1)/(Synchronous Predivider value),这里为32.768KHZ/128/256 = 1HZ;  

    Day Light Saving和Store Operation分别代表夏令时和重置存储操作,夏令时是一种为了节约能源而对时钟进行调整的制度。在夏令时期间,时钟会提前一小时,以便在白天更长的时间内利用自然光。夏令时的设置可以帮助设备自动调整时间以适应这种变化。我们一般不开启夏令时以保证RTC的时间是标准时间;重置存储操作:

  • RTC_STOREOPERATION_RESET:在低功耗模式下不存储当前时间设置,退出低功耗模式时时间会被重置。
  • RTC_STOREOPERATION_SET:在低功耗模式下保存当前时间设置,退出低功耗模式时恢复到之前的时间。

    我们一般选择RTC_STOREOPERATION_SET,这样就算进入和退出低功耗模式,RTC时间仍然会保持计数;

    Wake UP用于设置RTC唤醒中断,其中的Wake UP Clock是唤醒中断周期,设置为1HZ唤醒中断周期就是1秒,Wake Up Counter就是经过n+1次唤醒中断周期后触发中断,这里n为0,表示经过1次唤醒中断周期,也就是1秒后触发中断;

    Data Format分为BCD格式和BIN格式,BIN格式十进制数12表示0x0C,和我们正常的二进制-十进制转换相同,BCD格式是一种将每个十进制数的每一位用四位二进制表示的方法,十进制数12表示为0x12;一般我们用BIN格式更符合常识;

HAL_RTC_GetTime()和HAL_RTC_SetTime()用于获取和设置RTC的时分秒;

HAL_RTC_GetDate()和HAL_RTC_SetDate()用于获取和设置RTC的年月日星期;

注意上面的函数执行时要有顺序!读取时间时先执行HAL_RTC_GetTime()再执行HAL_RTC_GetDate(),不然就会导致读取时间无效的情况;同样设置时间先HAL_RTC_SetDate()再HAL_RTC_SetTime();代码例子如下:

RTC_Time.c:#include "RTC_Time.h"/*** @brief	时间设置* @param   *		@arg 	分别输入 年 月 日 星期 时 分 秒* @retval 无*/
void RTC_SetTime(uint16_t yea,uint8_t mon,uint8_t da, uint8_t hou,uint8_t min,uint8_t sec)
{RTC_TimeTypeDef RTC_Time;RTC_DateTypeDef RTC_Date;system_config.calendar.year = yea;system_config.calendar.century = yea/100;system_config.calendar.month = mon;system_config.calendar.date = da;system_config.calendar.hour = hou;system_config.calendar.min = min;system_config.calendar.sec = sec;system_config.calendar.week = GregorianDay(system_config.calendar);Flash_WriteStruct(FLASH_USER_START_ADDR, &system_config);            //将系统配置保存到FLASH用户数据区RTC_Date.Year = (uint8_t)(system_config.calendar.year%100);    //RTC中year格式为uint8_t,我们这里用其保存年份后两位RTC_Date.Month = system_config.calendar.month;RTC_Date.Date = system_config.calendar.date;RTC_Date.WeekDay = system_config.calendar.week;RTC_Time.Hours = system_config.calendar.hour;RTC_Time.Minutes = system_config.calendar.min;RTC_Time.Seconds = system_config.calendar.sec;RTC_Time.DayLightSaving = DayLightSaving_status;RTC_Time.StoreOperation = StoreOperation_status;HAL_RTC_SetDate(&hrtc, &RTC_Date, RTC_FORMAT_BIN);      //将配置写入到RTCHAL_RTC_SetTime(&hrtc, &RTC_Time, RTC_FORMAT_BIN);
}/*** @brief	获取时间* *		*/
void RTC_GetTime(void)
{RTC_TimeTypeDef RTC_Time;RTC_DateTypeDef RTC_Date;HAL_RTC_GetTime(&hrtc, &RTC_Time, RTC_FORMAT_BIN);   //先运行GetTime再运行GetDateHAL_RTC_GetDate(&hrtc, &RTC_Date, RTC_FORMAT_BIN);system_config.calendar.year = system_config.calendar.century*100 + RTC_Date.Year;  //将Flash中的世纪和RTC中的年份相加获得完整年份system_config.calendar.month = RTC_Date.Month;system_config.calendar.date = RTC_Date.Date;system_config.calendar.week = RTC_Date.WeekDay;system_config.calendar.hour = RTC_Time.Hours;system_config.calendar.min = RTC_Time.Minutes;system_config.calendar.sec = RTC_Time.Seconds;//Flash_WriteStruct(FLASH_USER_START_ADDR, &system_config);            //将系统配置保存到FLASH用户数据区
}void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{/* Prevent unused argument(s) compilation warning *///HAL_IWDG_Refresh(&hiwdg);   //喂狗,5s内必须喂一次RTC_GetTime();   	//更新时间   Write_Num_Time();							  //显示时间/* NOTE : This function should not be modified, when the callback is needed,the HAL_RTCEx_WakeUpTimerEventCallback could be implemented in the user file*/
}/*计算公历天数得出星期*/
static int GregorianDay(_calendar_obj tm)
{int leapsToDate;int lastYear;int day;int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };lastYear=tm.year-1;/*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/if((tm.year%4==0) &&((tm.year%100!=0) || (tm.year%400==0)) &&(tm.month>2)) {/** We are past Feb. 29 in a leap year*/day=1;} else {day=0;}day += lastYear*365 + leapsToDate + MonthOffset[tm.month-1] + tm.date; /*计算从公元元年元旦到计数日期一共有多少天*/tm.week=day%7; //算出星期if(tm.week == 0) tm.week = 7;return tm.week;
}RTC_Time.h:#ifndef __RTC_TIME_H__
#define __RTC_TIME_H__#include "main.h"
#include "User_Flash.h"
#include "rtc.h"
#include "74HC595.h"#define DayLightSaving_status     RTC_DAYLIGHTSAVING_NONE   //配置RTC夏令时状态
#define StoreOperation_status     RTC_STOREOPERATION_SET    //配置RTC 是否在低功耗模式保持运行void RTC_SetTime(uint16_t yea,uint8_t mon,uint8_t da, uint8_t hou,uint8_t min,uint8_t sec);
void RTC_GetTime(void);
static int GregorianDay(_calendar_obj tm); 
#endif

*电源引脚问题:

    从上图我们可以看出LQFP32封装的G070KBT6是没有VBAT引脚的,只有VDD引脚,因此当主电源VDD断电后采用电池给VDD供电,因此RTC也只能由VDD保持供电,可以用一路ADC采样主电源电压,当检测到主电源电压接近0V时表示此时已切换到电池供电,然后进行相应操作。电路如下:

    巧思:要做低功耗,可以进入低功耗就把检测电源电压的ADC转化为外部中断,当再次上电时触发外部中断退出低功耗模式,这样就不用电池供电的时候还要用ADC检测电源是否重新上电,节省功耗。(未验证)

*时钟源问题 :

    只有一个外部高速时钟,可以选择LSI或者HSE/32(一般RTC外部时钟源可以选择LSE或者HSE,通常使用LSE,不过为了节省晶振的情况下也可以用HSE分频替代,这样也比LSI更稳定。),由于主电源断电之后采用外部高速时钟HSE为有源晶振,会停止起振,因此这里使用LSI内部低速32.768KHZ晶振给RTC提供时钟源。由前面关于RTC的手册描述我们可以知道当LSI计时时,VBAT模式下RTC是不工作的,因为vbat只能给LSE供电而不能给LSI供电。vdd断了以后LSI也相当于断电了,rtc自然就不走了。但是由于G070KBT6没有VBAT引脚,因此也就没有VBAT模式,就算用刚刚的电池供电也是给VDD供电,因此这里不用担心电池供电时RTC会停止工作。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • FFmpeg For Android入门NDK打印版本号
  • python自动化笔记:os模块和异常处理
  • 什么是设计模式?一文理解,通俗易懂!
  • Nacos原理自问
  • Spring Cloud Gateway实现API访问频率限制
  • uniapp 自定义图片预览组件PicturePreview(Vue3、组合式、ts)
  • 新书速览|Python数据可视化:科技图表绘制(送书)
  • 【机器学习】 Sigmoid函数:机器学习中的关键激活函数
  • jmeter-beanshell学习16-自定义函数
  • 【ML】pre-train model 是什么如何微调它,如何预训练
  • pip笔记
  • POST_CRC
  • ceph分布式存储系统
  • 多头注意力用单元矩阵实现以及原因
  • SO_REUSEADDR 和 SO_REUSEPORT 的区别
  • ES6指北【2】—— 箭头函数
  • Angular6错误 Service: No provider for Renderer2
  • CentOS7 安装JDK
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • es6
  • FineReport中如何实现自动滚屏效果
  • iOS编译提示和导航提示
  • js
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Linux各目录及每个目录的详细介绍
  • magento2项目上线注意事项
  • October CMS - 快速入门 9 Images And Galleries
  • Vue--数据传输
  • 从PHP迁移至Golang - 基础篇
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 精彩代码 vue.js
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 入口文件开始,分析Vue源码实现
  • 思维导图—你不知道的JavaScript中卷
  • 微信小程序:实现悬浮返回和分享按钮
  • 仓管云——企业云erp功能有哪些?
  • 湖北分布式智能数据采集方法有哪些?
  • 数据可视化之下发图实践
  • #Java第九次作业--输入输出流和文件操作
  • #NOIP 2014# day.2 T2 寻找道路
  • #QT(TCP网络编程-服务端)
  • (1)svelte 教程:hello world
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (2)空速传感器
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (分布式缓存)Redis分片集群
  • (六)c52学习之旅-独立按键
  • (每日一问)操作系统:常见的 Linux 指令详解
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (原创)可支持最大高度的NestedScrollView
  • .gitignore文件_Git:.gitignore
  • .NET MVC 验证码
  • .net mvc部分视图