RTC 时间、闹钟

这篇具有很好参考价值的文章主要介绍了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的状态。

结构框图:

RTC 时间、闹钟,32,单片机,stm32,嵌入式硬件,RTC

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);
}    文章来源地址https://www.toymoban.com/news/detail-727839.html

到了这里,关于RTC 时间、闹钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 单片机项目分享 基于stm32的便携用电功率统计系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月19日
    浏览(108)
  • 单片机STM32看门狗详解(嵌入式学习)

    单片机STM32的看门狗(Watchdog)是一种硬件定时器,用于监控系统的运行状态并在出现故障或死锁时采取措施以恢复正常操作。看门狗的主要功能是定期检查系统是否正常运行,并在系统出现问题时触发复位操作。 STM32系列单片机通常配备了内置的看门狗定时器(通常称为独立

    2024年02月13日
    浏览(61)
  • 单片机项目分享 stm32机器视觉的口罩佩戴检测系统 - 单片机 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月22日
    浏览(77)
  • 【单片机毕设选题】 stm32智能运动计步系统 - 物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(62)
  • 单片机项目分享 单片机自动写字机器人设计与实现 - 物联网 嵌入式 stm32

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月21日
    浏览(89)
  • 【单片机毕设选题】Stm32单片机的音乐播放器设计 - 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(48)
  • stm32毕设分享 stm32实现车牌识别系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(60)
  • stm32毕设分享 Stm32酒驾检查系统 - 单片机 嵌入式 物联网

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年01月23日
    浏览(72)
  • 嵌入式STM32 单片机 GPIO 的工作原理详解

    STM32的 GPIO 介绍 GPIO 是通用输入/输出端口的简称,是 STM32 可控制的引脚。GPIO 的引脚与外部硬件设备连接,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。 以 STM32F103ZET6 芯片为例子,该芯片共有 144 脚芯片,包括7个通用目的的输入/输出口(GPIO)组,分别为

    2024年02月20日
    浏览(48)
  • 单片机毕设分享 基于STM32单片机的老人防摔倒报警系统 - 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月02日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包