RTC 时间、闹钟

实时时钟RTC是一个独立的定时器。RTC模块拥有一个连续计数的计数器,在软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。

在掉电情况下 RTC仍可以独立运行 只要芯片的备用电源一直供电,RTC上的时间会一直走。相对于通用定时器TIM 外设,它十分简单,只有很纯粹的计时和触发中断的功能;但从掉电还继续运行的角度来说,它却是32 中唯一一个具有如此强大功能的外设。所以RTC外设的复杂之处并不在于它的定时功能,而在于它掉电还继续运行的特性。

以上所说的掉电,是指主电源VDD 断开的情况,为了RTC 外设掉电继续运行,必须接上锂电池给STM32 的RTC、备份发卡通过VBAT 引脚供电。当主电源VDD 有效时,由VDD 给RTC 外设供电;而当VDD 掉电后,由VBAT 给RTC 外设供电。但无论由什么电源供电,RTC 中的数据都保存在属于RTC 的备份域中,若主电源VDD 和VBAT 都掉电,那么备份域中保存的所有数据将丢失。备份域除了RTC 模块的寄存器,还有42 个16 位的寄存器可以在VDD 掉电的情况下保存用户程序的数据,系统复位或电源复位时,这些数据也不会被复位。

RCT特征:

● 可编程的预分频系数:分频系数高为220。

● 32位的可编程计数器,可用于较长时间段的测量。

● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)。

可以选择以下三种RTC的时钟源:

● HSE时钟除以128;

● LSE振荡器时钟;

● LSI振荡器时钟

2个独立的复位类型:

● APB1接口由系统复位;

● RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位

3个专门的可屏蔽中断:

● 1.闹钟中断,用来产生一个软件可编程的闹钟中断。

● 2.秒中断,用来产生一个可编程的周期性中断信号(长可达1秒)。

● 3.溢出中断,指示内部可编程计数器溢出并回转为0的状态。

结构框图:

UNIX时间戳

由于RTC_CNT是32位寄存器,可存储的最大值为2^32-1,即这样计时,它将在136年时溢出。假如某个时刻读取到计数器的数值为X = 606024*2,即两天时间的秒数,而假设又知道计数器是在2011 年1 月1 日的0 时0 分0 秒置0 的,那么就可以根据计数器的这个相对时间数值,计算得这个X 时刻是2011 年1 月3 日的0 时0 分0 秒了。而计数器则会在(2011+136) 年左右溢出,也就是说到了(2011+136)年时,如果我们还在使用这个计数器提供时间的话就会出现问题。在这个例子中,定时器被置0 的这个时间被称为计时元年,相对计时元年经过的秒数称为时间戳,也就是计数器中的值。

大多数操作系统都是利用时间戳和计时元年来计算当前时间的,而这个时间戳和计时元年大家都取了同一个标准——UNIX 时间戳和UNIX 计时元年。UNIX 计时元年被设置为格林威治时间1970 年1 月1 日0 时0 分0 秒,大概是为了纪念UNIX 的诞生的时代吧,而UNIX 时间戳即为当前时间相对于UNIX 计时元年经过的秒数。因为unix 时间戳主要用来表示当前时间或者和电脑有关的日志时间(如文件创立时间,log 发生时间等),考虑到所有电脑文件不可能在1970 年前创立,所以用unix 时间戳很少用来表示1970 前的时间。在这个计时系统中,使用的是有符号的32 位整型变量来保存UNIX 时间戳的,即实际可用计数位数比我们上面例子中的少了一位,少了这一位,UNIX 计时元年也相对提前了,这个计时方法在2038 年1 月19 日03 时14 分07 秒将会发生溢出,这个时间离我们并不远。由于UNIX 时间戳被广泛应用到各种系统中,溢出可能会导致系统发生严重错误,届时,很可能会重演一次“千年虫”的问题,所以在设计预期寿命较长的设备需要注意。

BKP备份寄存器
1备份寄存器是42个16位的寄存器。可用来存储84个字节数据。2它们处在备份区域,当VDD电源切断,仍然由Vear维持供
电。
3当系统在待机模式下被唤醒,或者系统复位或者电源复位,它们也
不会复位。
4执行以下操作将使能对后备寄存器和 RTC 访问:
设置寄存器RCC APB1ENR的 PWREN 和 BKPEN位,使能电源和后备时钟。
设置寄存器 PWR CR的 DBP位,使能对 RTC和后备寄存器的访问。

一共有 42 个 16 位备份寄存器。常用来保存一些系统配置信息和相关标志位。

RTC相关寄存器
1 、RTC控制寄存器(RTC_CRH,RTC_CRL)
2、 RTC预分频装载寄存器(RTC_ PRLH, RTC_PRLL)
3、RTC预分频余数寄存器(RTC_ DIVH,RTC_DIVL)

4、RTC计数器寄存器(RTC_CNTH,RTC_CNTL)
5、RTC闹钟寄存器(RTC_ALRH, RTC_ALRL)

RTC控制寄存器:

① 修改 CRH/CRL 寄存器,必须先判断 RSF 位,确定已经同步。
② 修改 CNT,ALR,PRL的时候,必须先配置CNF 位进入配置模式,修改完之后,设置 CNF位为 0 退出配置模式
③ 同时在对 RTC 相关寄存器写操作之前,必须判断上一次写操作已经结束,也就是判断 RTOFF 位是否置位。

配置RTC寄存器
必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRRTC_CNT、RTC_ALR寄存器。
另外,对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询!RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是11'!时,才可以写入RTC寄存器。
配置过程:
1.查询RTOFF位,直到RTOFF的值变为'1’2.置CNF值为1,进入配置模式
3.对一个或多个RTC寄存器进行写操作4.清除CNF标志位,退出配置模式
5.查询RTOFF,直至RTOFF位变为'1'以确认写操作已经完成。
仅当CNF标志位被清除时,写操作才能进行,这个过程至少需要3个RTCCLK周期。
 

读RTC寄存器
RTC核完全独立于RTC APB1接口。
软件通过APB1接口访问RTC的预分频值、计数器值和闹钟值。但是,相关的可读寄存器只在与RTC APB1时钟进行重新同步的RTC时钟的上升沿被更新。RTC标志也是如此的。
这意味着,如果APB1接口曾经被关闭,而读操作又是在刚刚重新开启APB1之后,则在第一次的内部寄存器更新之前,从APB1上读出的RTC寄存器数值可能被破坏了(通常读到0)。下述几种情况下能够发生这种情形:
发生系统复位或电源复位
系统刚从待机模式唤醒(参见第4.3节:低功耗模式)。系统刚从停机模式唤醒(参见第4.3节:低功耗模式)。
所有以上情况中,APB1接口被禁止时(复位、无时钟或断电)RTC核仍保持运行状态。因此,若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置'1'。

RTC 配置一般步骤
1、使能 PWR 和 BKP 时钟
2、使能后备寄存器访问

3、配置RTC时钟源,使能RTC时钟;(如果使用: LSE,要打开)

4、设置RTC 预分频系数
5、设置时间
6、开启相关中断(如果需要)

7、编写中断服务函数

8、部分操作要等待写操作完成和同步。
等待最近一次对RTC寄存器的写操作完成;等待RTC 寄存器同步
 

RTC的时间和闹钟寄存器都是以秒钟为计数单位的,所以要把时间换算成秒钟,获取时间需要把秒钟转换成日期。

判断是否是闰年

u8 Is_Leap_Year(u16 year)
{              
    if(year%4==0) //必须能被4整除
    { 
        if(year%100==0) 
        { 
            if(year%400==0)return 1;//如果以00结尾,还要能被400整除        
            else return 0;   
        }else return 1;   
    }else return 0;    
}    

设置时间

u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5};     
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
    u16 t;
    u32 seccount=0;
    if(syear<1970||syear>2099)return 1;       
    for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
    {
        if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
        else seccount+=31536000;              //平年的秒钟数
    }
    smon-=1;
    for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
    {
        seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
        if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数       
    }
    seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
    seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;     //分钟秒钟数
    seccount+=sec;//最后的秒钟加上去

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,     ENABLE);    //使能PWR和BKP外设时钟  
    PWR_BackupAccessCmd(ENABLE);    //使能RTC和后备寄存器访问 
    RTC_SetCounter(seccount);    //设置RTC计数器的值

    RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成      
    return 0;        
}

设置闹钟

u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
    u16 t;
    u32 seccount=0;
    if(syear<1970||syear>2099)return 1;       
    for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
    {
        if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
        else seccount+=31536000;              //平年的秒钟数
    }
    smon-=1;
    for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
    {
        seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
        if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数       
    }
    seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
    seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;     //分钟秒钟数
    seccount+=sec;//最后的秒钟加上去                 
    //设置时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,            ENABLE);    //使能PWR和BKP外设时钟   
    PWR_BackupAccessCmd(ENABLE);    //使能后备寄存器访问  
    //上面三步是必须的!
    
    RTC_SetAlarm(seccount);
 
    RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成      
    
    return 0;        
}

获取时间

u8 RTC_Get(void)
{
    static u16 daycnt=0;
    u32 timecount=0; 
    u32 temp=0;
    u16 temp1=0;      
    timecount=RTC_GetCounter();     
     temp=timecount/86400;   //得到天数(秒钟数对应的)
    if(daycnt!=temp)//超过一天了
    {      
        daycnt=temp;
        temp1=1970;    //从1970年开始
        while(temp>=365)
        {                 
            if(Is_Leap_Year(temp1))//是闰年
            {
                if(temp>=366)temp-=366;//闰年的秒钟数
                else {temp1++;break;}  
            }
            else temp-=365;      //平年 
            temp1++;  
        }   
        calendar.w_year=temp1;//得到年份
        temp1=0;
        while(temp>=28)//超过了一个月
        {
            if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
            {
                if(temp>=29)temp-=29;//闰年的秒钟数
                else break; 
            }
            else 
            {
                if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
                else break;
            }
            temp1++;  
        }
        calendar.w_month=temp1+1;    //得到月份
        calendar.w_date=temp+1;      //得到日期 
    }
    temp=timecount%86400;             //得到秒钟数          
    calendar.hour=temp/3600;         //小时
    calendar.min=(temp%3600)/60;     //分钟    
    calendar.sec=(temp%3600)%60;     //秒钟
    calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);// 获取星期   
    return 0;
}

获取星期

u8 RTC_Get_Week(u16 year,u8 month,u8 day)
{    
    u16 temp2;
    u8 yearH,yearL;
    
    yearH=year/100;    yearL=year%100; 
    // 如果为21世纪,年份数加100  
    if (yearH>19)yearL+=100;
    // 所过闰年数只算1900年之后的  
    temp2=yearL+yearL/4;
    temp2=temp2%7; 
    temp2=temp2+day+table_week[month-1];
    if (yearL%4==0&&month<3)temp2--;
    return(temp2%7);
}    

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

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

相关文章

材质、纹理、贴图的区别和关联

1、材质、纹理、贴图的概念 材质&#xff08;Material&#xff09;、纹理&#xff08;Texture&#xff09;、贴图&#xff08;Texture Map&#xff09;是计算机图形学中的三个概念&#xff0c;它们之间存在关系但也有一些区别。 材质&#xff08;Material&#xff09;是描述物…

java spring cloud 工程企业管理软件-综合型项目管理软件-工程系统源码

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

WIN10 NPM的安装

引言&#xff1a; 什么是node.js? javaScript是一门脚本语言&#xff0c;通常被用来编写、执行本地源代码。脚本语言需要一个解析器才能运行&#xff0c;HTML文件中的JavaScript代码由浏览器解析执行。而自行执行JavaScript代码则需要Node.js解析器才能运行。 每个解析器都…

放大招,百度文心大模型4.0正在加紧训练,即将发布

插播一条快讯&#xff01; &#xfeff;&#xfeff;刚刚看到一篇报道&#xff0c;说百度正在加紧训练文心大模型4.0&#xff01;百度5月发布了文心大模型3.5&#xff0c;才4个多月又要发布4.0了&#xff0c;这迭代速度简直了。据说这次发布将在10月17日百度世界大会上进行&am…

【AI】深度学习——人工智能、深度学习与神经网络

文章目录 0.1 如何开发一个AI系统0.2 表示学习(特征处理)0.2.1 传统特征学习特征选择过滤式包裹式 L 1 L_1 L1​ 正则化 特征抽取监督的特征学习无监督的特征学习 特征工程作用 0.2.2 语义鸿沟0.2.3 表示方式关联 0.2.4 表示学习对比 0.3 深度学习0.3.1 表示学习与深度学习0.3.…

OpenCV3-Python(7)模板匹配和霍夫检测

模板匹配 膜版匹配不能匹配尺度变换和视角变换的图像 图片中查找和模板相似度最高的图像 计算相似程度最高的位置 res cv.matchTemplate(img , template, method) 该方法返回一个类似灰度图的东西&#xff0c;如果用的相关匹配&#xff0c;那么亮的地方就是可能匹配上的地方 …

redis 事物

Redis事务 一个队列中&#xff0c;一次性、顺序性、排他性的执行一系列命令 正常执行 放弃事务 在exec执行之前&#xff0c;报错&#xff0c;则所有命令都不会执行 在exec执行后&#xff0c;报错&#xff0c;则其它正确的指令会执行&#xff0c;错误的命令会抛弃 watch 监…

文化主题公园旅游景点3d全景VR交互体验加深了他们对历史文化的认知和印象

如今&#xff0c;沉浸式体验被广泛应用于文旅行业&#xff0c;尤其是在旅游演艺活动中。在许多城市&#xff0c;沉浸式旅游演艺活动已成为游客“必打卡”项目之一。因其独特体验和强互动性&#xff0c;这类演艺活动不仅吸引了外地游客&#xff0c;也吸引了本地观众。 随着信息化…

JuiceFS 目录配额功能设计详解

JuiceFS 在最近 v1.1 版本中加入了社区中呼声已久的目录配额功能。已发布的命令支持为目录设置配额、获取目录配额信息、列出所有目录配额等。完整的详细信息&#xff0c;请查阅文档。 在设计此功能时&#xff0c;对于它的统计准确性&#xff0c;实效性以及对性能的影响&#…

MySQL-1(12000字详解)

一&#xff1a;数据库的引入 数据库在我们以后工作中是一个非常常用的知识&#xff0c;数据库用来存储数据&#xff0c;但是有些同学可能就会疑惑了&#xff0c;存储数据用文件就可以了&#xff0c;为什么还要弄个数据库呢&#xff1f; 文件保存数据有以下几个缺点&#xff1…

OpenGLES:3D立方体纹理贴图

效果展示 一.概述 前几篇博文讲解了OpenGLES绘制多种3D图形&#xff0c;并赋予丰富的色彩&#xff0c;但是在这些3D图形绘制过程中&#xff0c;有一点还没有涉及&#xff0c;就是纹理贴图。 今天这篇博文我会用如下六张图片对立方体进行纹理贴图&#xff0c;实现六个面都是贴…

二、图像处理

待完善 一、图片缩放 import org.bytedeco.opencv.global.opencv_imgcodecs; import org.bytedeco.opencv.global.opencv_imgproc; import org.bytedeco.opencv.opencv_core.Mat; import org.bytedeco.opencv.opencv_core.Size;public class ImageResizer {public static voi…

基于SVM+TensorFlow+Django的酒店评论打分智能推荐系统——机器学习算法应用(含python工程源码)+数据集+模型(一)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境TensorFlow 环境方法一方法二 安装其他模块安装MySQL 数据库 模块实现1. 数据预处理1&#xff09;数据整合2&#xff09;文本清洗3&#xff09;文本分词 相关其它博客工程源代码下载其它资料下载 前言 本项目以支…

剑指offer——JZ68 二叉搜索树的最近公共祖先 解题思路与具体代码【C++】

一、题目描述与要求 二叉搜索树的最近公共祖先_牛客题霸_牛客网 (nowcoder.com) 题目描述 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q&#xff0c;最近公共祖先LCA(T,p,q)表示一个节点x&#…

阿里云轻量应用服务器月流量限制说明(部分套餐不限流量)

阿里云轻量应用服务器部分套餐限制月流量&#xff0c;轻量应用服务器按照套餐售卖&#xff0c;有的套餐限制月流量&#xff0c;有的不限制流量。像阿里云轻量2核2G3M带宽轻量服务器一年108元和轻量2核4G4M带宽一年297.98元12个月&#xff0c;这两款是不限制月流量的。阿里云百科…

充电保护芯片TP4054国产替代完全兼容DP4054DP4054H 锂电充电芯片

■产品概述 DP4054H是-款完整的采用恒定电流/恒定电压单节锂离子电池充电管理芯片。其SOT小封装和较少的外部元件数目使其成为便携式应用的理想器件&#xff0c;DP4054H可 以适合USB电源和适配器电源工作。 由于采用了内部PMOSFET架构&#xff0c;加上防倒充电路,所以不需要外…

c++桥接模式,中介者模式应用实现状态跳转

上图为例&#xff0c;按上述两种方式实现的模式跳转&#xff0c;如果在原先的三种模式之间再增加多一种模式&#xff0c;就会引起每个模式都会要求改变&#xff0c;并且逻辑混乱&#xff0c;因此更改模式为桥接中介者访问&#xff0c;将抽象和实现分离&#xff0c;实现之间采用…

Flink---11、状态管理(按键分区状态(值状态、列表状态、Map状态、归约状态、聚合状态)算子状态(列表状态、广播状态))

星光下的赶路人star的个人主页 这世上唯一扛得住岁月摧残的就是才华 文章目录 1、状态管理1.1 Flink中的状态1.1.1 概述1.1.2 状态的分类 1.2 按键分区状态&#xff08;Keyed State&#xff09;1.2.1 值状态&#xff08;ValueState&#xff09;1.2.2 列表状态&#xff08;ListS…

三十一、【进阶】B+树的演变过程

1、B树简单介绍 &#xff08;1&#xff09;介绍&#xff1a;B树也属于B树&#xff0c;是B树的变种 &#xff08;2&#xff09;特点&#xff1a;所有的数据都位于叶子节点上&#xff0c;叶子节点上的所有元素形成了一个单项链表 &#xff08;3&#xff09;图示&#xff1a; 2…

【虚拟机】根据已有IP获取当前网段的主机范围

虚拟机有的时候会需要自己手动分配IP&#xff0c;此时无论是和宿主主机通信、还是访问外网&#xff0c;都需要保证和宿主主机在一个网段。现在已知宿主主机的 IP 和子网掩码&#xff0c;需要知道宿主主机所处网段可以分配哪些IP。 假设宿主主机 IP 为172.20.10.2&#xff0c;子…