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.mzph.cn/news/99517.shtml

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

相关文章

实现协议互通:探索钡铼BL124EC的EtherCAT转Ethernet/IP功能

钡铼BL124EC是一种用于工业网络通信的网关设备&#xff0c;专门用于将EtherCAT协议转换成Ethernet/IP协议。它充当一个桥梁&#xff0c;连接了使用不同协议的设备&#xff0c;使它们能够无缝地进行通信和互操作。 具体来说&#xff0c;BL124EC通过支持EtherCAT&#xff08;以太…

2023,全网最真实的自动化测试学习路线,看不懂来打我!

随着测试行业的发展&#xff0c;“会代码”越来越成为测试工程师的一个标签。打开各大招聘网站&#xff0c;测试工程师月薪一万以上基本都有一个必备技能&#xff0c;那就是自动化测试。那么自动化测试到底难不难呢&#xff1f;下面我将会将我的经历讲给大家听&#xff0c;希望…

【java基础学习】之DOS命令

#java基础学习 1.常用的DOS命令&#xff1a; dir:列出当前目录下的文件以及文件夹 md: 创建目录 rd:删除目录cd:进入指定目录 cd.. :退回到上级目录 cd\ : 退回到根目录 del:删除文件 exit:退出dos命令行 1.dir:列出当前目录下的文件以及文件夹 2.md: 创建目录 …

[NewStarCTF 2023 公开赛道] week1 Crypto

brainfuck 题目描述&#xff1a; [>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<-]>>>>>>>.>----.<-----.>-----.>-----.<<<-.>>..…

黑豹程序员-架构师学习路线图-百科:AJAX

文章目录 1、什么是AJAX2、发展历史3、工作原理4、一句话概括 1、什么是AJAX Ajax即Asynchronous&#xff08;呃森可乐思&#xff09; Javascript And XML&#xff08;异步JavaScript和XML&#xff09; 在 2005年被Jesse James Garrett&#xff08;杰西詹姆斯加勒特&#xff09…

Android Studio新建项目缓慢解决方案

关于Android Studio2022新建项目时下载依赖慢的解决方案 起因解决方案gradle下载慢解决方案kotlin依赖下载慢解决方案 结尾 起因 新建Android Studio项目时&#xff0c;常会因为网络问题导致部分依赖下载缓慢&#xff0c;其中gradle和kotlin最拖慢进度。 解决方案 gradle下载…

1.3.OpenCV技能树--第一单元--图像的基础操作(进阶篇)

目录 1.文章内容来源 2.图像的进阶操作 2.1.边界填充 2.2.数值计算 2.3.图像融合 2.4.图像保存 2.5.视频读取 3.课后习题代码复现 3.1.问题一图像像素颜色 3.2.问题二图片黑客帝国化 3.3.问题三梅西的足球轨迹 4.易错点总结与反思 1.文章内容来源 1.题目来源:https://edu.c…

MySQL之主从复制

概述&#xff1a; 将主库的数据 变更同步到从库&#xff0c;从而保证主库和从库数据一致。 它的作用是 数据备份&#xff0c;失败迁移&#xff0c;读写分离&#xff0c;降低单库读写压力 原理&#xff1a; 主服务器上面的任何修改都会保存在二进制日志&#xff08; Bin-log日志…

【Zookeeper专题】Zookeeper经典应用场景实战(二)

目录 前置知识课程内容一、Zookeeper分布式锁实战1.1 什么是分布式锁1.2 基于数据库设计思路1.3 基于Zookeeper设计思路一1.4 基于Zookeeper设计思路二1.5 Curator 可重入分布式锁工作流程1.6 总结 二、基于Zookeeper实现服务的注册与发现2.1 设计思路2.2 Zookeeper实现注册中心…

GitHub相应太慢

后期使用到github下载源码&#xff0c;会发现响应太慢&#xff0c;本篇文章解决你的问题 获取域名对应的ip 访问链接&#xff1a;https://raw.hellogithub.com/hosts&#xff08;ps&#xff1a;这链接定时更新&#xff09;&#xff0c;获取对应的host配置。 如果需要工具自动…

百面机器学习书刊纠错

百面机器学习书刊纠错 P243 LSTM内部结构图 2023-10-7 输入门的输出 和 candidate的输出 进行按元素乘积之后 要和 遗忘门*上一层的cell state之积进行相加。

Linux常见指令3

Linux常见指令3 一.Linux指令1.时间相关的指令1.date指定格式显示时间2.时间戳3.补充内容-日志3.Cal 2.find补充1.which2.whereis 3.uname-a-r 4.重要的几个热键5.关机命令 二.grep-i选项-n选项-v选项grep其他用途1.搜索指定进程信息2.查找日志等级 补充命令补充命令:sort补充命…

【ElasticSearch】基于Docker 部署 ElasticSearch 和 Kibana,使用 Kibana 操作索引库,以及实现对文档的增删改查

文章目录 前言一、使用 Docker 部署 ElasticSearch 和 Kibana1.1 部署 ElasticSearch1.2 部署 Kibana1.3 利用 Kibana 演示 Elasticsearch 分词效果 二、解决中文分词的问题2.1 默认分词器对中文分词的问题2.2 引入 IK 分词器2.3 IK 分词器的两种分词模式2.4 IK 分词器存在的问…

时空智友企业流程化管控系统 sessionid泄露漏洞 复现

文章目录 时空智友企业流程化管控系统 sessionid泄露漏洞 复现0x01 前言0x02 漏洞描述0x03 影响平台0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 时空智友企业流程化管控系统 sessionid泄露漏洞 复现 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从…

Javascript笔记 rest VS spread

1 rest 2 spread 3 二者区别 在 JavaScript 中&#xff0c;spread 操作符 ... 和 rest 参数都使用三个点 ... 作为前缀&#xff0c;但它们在使用上有一些区别&#xff0c;主要体现在它们的作用和使用场景上。 Spread 操作符 ... 作用&#xff1a; "展开"数组或对象的…

无需公网IP,教学系统如何实现远程一站式管理维护?

全国多所高校应用红亚科技研发的一套教学实验系统平台&#xff0c;此实验系统服务器分别部署在学校内部&#xff0c;与校内的各种教学资源整合在一起&#xff0c;向校内师生提供服务。 红亚总部设立在北京&#xff0c;虽说在全国22个省会均设有办事处&#xff0c;在面对全国多…

多路彩灯控制器led流水灯VHDL速度可调仿真图视频、源代码

名称&#xff1a;多路彩灯控制器led流水灯VHDL速度可调 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; 使用VHDL设计彩灯控制器&#xff0c;共24个led灯&#xff0c;分为5种不同的花样&#xff0c;可以通过按键切换花样的变化速度。 代码下载&#…

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

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

【虹科分享】什么是Redis数据集成(RDI)?

大量的应用程序、日益增长的用户规模、不断扩展的技术需求&#xff0c;以及对即时响应的持续追求。想想这些是否正是你在经历的。也许你尝试过自己构建工具来应对这些需求&#xff0c;但是大量的编码和集成工作使你焦头烂额。那你是否知道&#xff0c;有这样一个工具可以帮助你…

计算机竞赛 目标检测-行人车辆检测流量计数

文章目录 前言1\. 目标检测概况1.1 什么是目标检测&#xff1f;1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 行人车辆目标检测计数系统 …