STM32F103学习笔记(六) RTC实时时钟(应用篇)

目录

1. RTC 实时时钟的应用场景

2. RTC 的配置与初始化

2.1 设置 RTC 时钟源

2.2 初始化 RTC 寄存器

2.3 中断配置

2.4 备份寄存器配置

2.5 校准 RTC

3. 实例演示代码

4. 总结

1. RTC 实时时钟的应用场景

        实时时钟(RTC)在嵌入式系统中具有广泛的应用场景,特别是对于需要准确跟踪时间的应用。下面是一些常见的 RTC 应用场景:

        时钟显示: RTC 可用于驱动液晶显示屏上的时钟模块,以在设备上显示当前时间。

        日历功能: RTC 可用于记录日期,包括年、月、日等信息,从而实现日历功能。

        定时任务: 在需要周期性执行任务的应用中,RTC 可以作为触发定时任务执行的时钟源。

        事件记录: RTC 可用于记录系统中的事件发生时间,例如记录故障发生的时间戳。

        定时器功能: RTC 还可以用作定时器,实现定时触发操作,例如定时启动警报等。

        电源管理: RTC 可以在设备休眠时运行,唤醒时提供时间信息,从而实现高效的电源管理。

        日志记录: RTC 可以用于记录系统运行状态或用户操作记录的时间信息,以便后续分析。

2. RTC 的配置与初始化

        配置和初始化 RTC 模块是使用实时时钟功能的关键步骤。下面是配置和初始化 RTC 的一般步骤:

2.1 设置 RTC 时钟源

        RTC 的时钟源通常有两种选择:外部晶体振荡器(LSE)和内部振荡器(LSI)。外部晶体振荡器(通常是32.768kHz)提供更高的精度和稳定性,而内部振荡器则更为节省成本,可以在LSE失效时使用。

2.2 初始化 RTC 寄存器

        RTC 模块通常包含多个寄存器,用于存储时间、日期和控制信息。在初始化过程中,需要设置这些寄存器的初始值,以确保 RTC 模块能够正确地工作。

2.3 中断配置

        如果需要使用 RTC 中断功能,例如定时器中断或闹钟中断,还需要配置相应的中断使能位和中断优先级。这样,当 RTC 模块产生中断时,系统可以及时响应并处理中断事件。

2.4 备份寄存器配置

        RTC 模块通常还包含一些备份寄存器(BKP),用于存储关键信息,例如设备状态、配置参数等。在初始化过程中,可以根据需要对这些备份寄存器进行配置,以实现数据的备份和恢复功能。

2.5 校准 RTC

        通过下列RTC简图可知,后备区域的时钟与APB1总线的时钟是不相同的,为了确保 RTC 模块提供的时间信息准确可靠,需要对 RTC 进行周期性的校准。校准过程包括校正 RTC 时钟源的偏差,以及对 RTC 寄存器的时间值进行校准,以确保与外部时间标准的一致性。

3. 实例演示代码

        本节我们将利用RTC实现一个时钟显示的功能,通过读取时间戳来获取当前时间(主供电断开依然可以由备用电池供电,故主供电断开依然可以记时),本程序可以通过动态传参的方法来配置当前的初始时间。
        首先是等待RTC同步函数

void rtc_wait(void)
{RTC_WaitForSynchro();								//等待同步RTC_WaitForLastTask();								//等待上一次操作完成
}

        接着是RTC的初始化

void rtc_Init(uint16_t year,uint16_t mouth,uint16_t day,uint16_t hour,uint16_t min,uint16_t sec)
{time_t time_cnt;struct tm time_date;	BKP_Init();//备份寄存器初始化,同时使能PWR的时钟if (R_Save_data(BKP_DR10) != 0x2024)			//判断是否是第一次设置备份寄存器{RCC_LSEConfig(RCC_LSE_ON);							//LSE时钟,通常是32.768kHzwhile (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);	//LSE准备就绪RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);				//配置LSE来源RCC_RTCCLKCmd(ENABLE);								//RTC时钟使能rtc_wait();//等待同步(主时钟和低速时钟的同步)RTC_SetPrescaler(32768 - 1);						//把32.768kHz分频到1HzRTC_WaitForLastTask();								//等待上一次操作完成time_date.tm_year = year - 1900;  //time库中,年是从1900年算起的time_date.tm_mon = mouth - 1; 		//time库中,月是从1月算起的time_date.tm_mday = day;time_date.tm_hour = hour;time_date.tm_min = min;time_date.tm_sec = sec;time_cnt = mktime(&time_date) - 8 * 60 * 60;	//将日期转换为秒计数器,并减8个时区(东8)RTC_SetCounter(time_cnt);						//更新到计数器RTC_WaitForLastTask();							//等待上一次操作完成BKP_WriteBackupRegister(BKP_DR10, 0x2024);			//第一次设置完成,写入标志位}else	rtc_wait();//第一次已经配置好了,后期主上电只需等待时钟同步
}

        接着是RTC读取时间的函数

void Read_RTC(uint16_t *year,uint16_t *mouth,uint16_t *day,uint16_t *hour,uint16_t *min,uint16_t *sec)
{time_t time_cnt;		struct tm time_date;	time_cnt = RTC_GetCounter() + 8 * 60 * 60;		//获取当前的秒计数器time_date = *localtime(&time_cnt);				//将秒计数器转换为日期*year = time_date.tm_year + 1900;		//将日期时间结构体赋值给数组的时间*mouth = time_date.tm_mon + 1;*day = time_date.tm_mday;*hour = time_date.tm_hour;*min = time_date.tm_min;*sec = time_date.tm_sec;
}

        在这里我们要注意,需要在文件的开头包含time.h文件,因为在函数中使用到了该头文件中包含的结构体和其他有关时间戳的函数,通过该头文件我们可以避免自己编写闰年等等的程序逻辑

#include <time.h>

        在获取函数之前,我们还需要定义全局变量,一定要全局变量哈,不要写在main函数或者其他功能函数中了

uint16_t year,mouth,day,hour,min,sec;

接着,我们只需要在初始化时将当前时间作为参数传入初始化函数,就可以在获取函数中通过全局变量实时获取到当前的时间了

rtc_Init(2024,2,19,4,27,55); //RTC初始化,当前时间2024年2月19日4点27分55秒
Read_RTC(&year,&mouth,&day,&hour,&min,&sec);//获取函数,将日期信息分别赋值到全局变量中

        最后程序中如果出现函数未定义的,可能是在BKP篇中封装好的函数,下附BKP篇的.c文件

#include "bkp.h"//备份寄存器初始化
void BKP_Init(void)
{//备份寄存器通常需要在Vbat电压下工作(Vbat是用于保持备份寄存器内容的电源),而PWR模块负责监测Vbat电压RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);		//开启PWR的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);		//开启BKP的时钟PWR_BackupAccessCmd(ENABLE);							//用PWR使能备份寄存器
}/*在f103c8t6中,有20个字节的后备数据空间,对应10个16位的备份寄存器
BKP_DR对应BKP_DR1 - BKP_DR10
*/
uint16_t W_Save_data(uint16_t BKP_DR, uint16_t data)
{BKP_WriteBackupRegister(BKP_DR, data);	//将需要掉电保存的数据写入备份寄存器if(data == BKP_ReadBackupRegister(BKP_DR))		//读取写入的备份寄存器的数据{return 1; //如果正确读取到备份寄存器的数据,返回1}else return 0;
}uint16_t R_Save_data(uint16_t BKP_DR)
{return BKP_ReadBackupRegister(BKP_DR);
}

4. 总结

        RTC(实时时钟)模块在嵌入式系统中扮演着重要角色,通过提供精确时间和日期信息,帮助系统实现定时任务、时间戳记录、闹钟等功能。我们学习了RTC的原理、配置和应用场景。在配置和初始化RTC时,需要注意时钟源选择、寄存器初始化和异常处理,以确保模块的稳定可靠运行。通过掌握RTC知识,我们能够提升系统性能和稳定性。

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

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

相关文章

2023 最新 IntelliJ IDEA 2023.3 详细配置步骤演示(图文版)<中文版>

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【MySQL】探索表结构、数据类型和基本操作

表、记录、字段 数据库的E-R&#xff08;entity-relationship&#xff0c;实体-关系&#xff09;模型中有三个主要概念&#xff1a; 实体集 、 属性 、 关系集 。 一个实体集对应于数据库中的一个表&#xff0c;一个实体则对应于数据库表 中的一行&#xff0c;也称为一条记录。…

扫二维码播放视频的效果怎么做?如何扫码看视频?

现在经常会在很多的商品详情上发现多个二维码&#xff0c;扫码后会展现不同的内容&#xff0c;比如图片、视频、文字等等。一般产品介绍和使用说明多以视频为主&#xff0c;那么如何制作扫码播放视频的效果呢&#xff0c;相信很多小伙伴对这个制作技巧都非常的感兴趣&#xff0…

亿发:解锁数据智能力,探索数据中台的未来发展趋势与智能化革命

数据中台是什么 数据中台是一种基于现代数据技术和架构的概念&#xff0c;其提出之前&#xff0c;企业在解决数据资源整合和共享方面采用了各种不同的方法。在阿里提出数据中台概念之前&#xff0c;大型企业已经在进行各类数据处理&#xff0c;并且在没有数据中台的情况下取得…

应急响应-常规处置办法

网站中被植入Webshell&#xff0c;通常代表着网站中存在可利用的高危漏洞&#xff0c;攻击者利用这些漏洞&#xff0c;将Webshell写入网站&#xff0c;从而获取网站的控制权。一旦在网站中发现webshell文件&#xff0c;可采取以下步骤进行临时处置。 入侵确定时间 通过在网站…

揭示IP查询结果偏差的现象及其影响

在互联网的日益普及和数字化的时代&#xff0c;IP地址成为了我们在网络上进行通信和交流的关键。然而&#xff0c;尽管IP地址通常被认为是准确地标识设备位置的重要工具&#xff0c;但实际上&#xff0c;IP查询结果存在一定的偏差&#xff0c;这可能会给我们带来一些意想不到的…

抖音数据抓取工具|短视频下载工具|视频内容提取软件

一、开发背景&#xff1a; 随着抖音平台的流行&#xff0c;越来越多的人希望能够下载抖音视频以进行个人收藏或分享。然而&#xff0c;目前在网上找到的抖音视频下载工具功能单一&#xff0c;操作繁琐&#xff0c;无法满足用户的需求。因此&#xff0c;我们决定开发一款功能强大…

字节跳动Java端研发面试,P8大佬亲自讲解

2024第一次Java面试&#xff0c;我去了快手。快手的面试挺有挑战性的&#xff0c;而且还特别有意思&#xff0c;感觉啥都能问到。&#xff08;二面是10天前约的面试&#xff0c;差点要忘了&#xff09;然后是HR面&#xff0c;前天我就收到offer。 1. 面试官&#xff1a;工作中使…

深度神经网络中的计算和内存带宽

深度神经网络中的计算和内存带宽 文章目录 深度神经网络中的计算和内存带宽来源原理介绍分析1&#xff1a;线性层分析2&#xff1a;卷积层分析3&#xff1a;循环层总结 来源 相关知识来源于这里。 原理介绍 Memory bandwidth and data re-use in deep neural network computat…

骨传导耳机怎么样?六大规则与避坑绝招大揭秘

近年来&#xff0c;骨传导蓝牙耳机在健身与科技爱好者之间变得异常受欢迎。相比之下&#xff0c;传统入耳式蓝牙耳机在户外活动中无法让佩戴者听到周围的环境声&#xff0c;这一缺点限制了它们的使用场景。骨传导蓝牙耳机通过其独特的开放式设计来解决这一问题&#xff0c;使其…

力扣--双指针167.二数之和Ⅱ

这题一个穷举方法是比较好想到的&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int i,j;int nnumbers.size();vector<int>result(2,0);for(i0;i<n-1;i){for(ji1;j<n;j){if(numbers[i]numbers[j…

IO进程线程:将信号灯集的相关函数二次封装

sem.h #ifndef _SEM_H_ #define _SEM_H_//创建或打开共享内存:参数为要申请的信号灯集中包含的灯的个数&#xff0c;返回值信号灯集的id int open_sem(int semcount);//进行申请资源操作:参数为要申请的信号灯id,以及灯的编号 int P(int semid,int semno);//进行释放资源操作:…