×
单片机 > 其他资讯 > 详情

Stm32 RTC介绍相关笔记

发布时间:2021-07-13 发布时间:
|

1.由于最近一段时间要进行期末考试,所以很久没有动32了,从现在开始,可以再开始学了


2.RTC(REAL TIME CLOCK)


   1.作为Stm32内部的实时时钟,可以看做一个独立的定时器,在代码的配置下,可以作为时钟日历的功能


    2.注意:RTC的配置过程十分敏感,因为对于RTC的配置过程中,是在后备区域进行,由于系统在自动复位以后,自动会禁止后备寄存器和RTC(写保护),所以在配置的过程中要进行对写保护的撤销


    3.RTC简图

4.配置重点:


    因为RTC配置需要对后备区域进行配置,配置的时候要判断是否寄存器完成和同步,也要取消对备份区的写保护


1.初始化过程


#include "delay.h"

#include "usart.h"

#include "rtc.h"     

 

_calendar_obj calendar;//时钟结构体

   

//实时时钟配置

//初始化RTC时钟,同时检测时钟是否工作正常

//BKP->DR1用于保存是否第一次配置的设置

//返回0:正常

//其他:错误代码

u8 RTC_Init(void)

{

u8 temp=0;

//1.检查是不是第一次配置时钟

if(BKP->DR1!=0X5050)

{

//BKP->DR1 为可设置的位数为16位的寄存器,用来提供下一次配置

  

//2.使能电源时钟和备份区域时钟

RCC->APB1ENR|=1<<28;//电源时钟

RCC->APB2ENR|=1<<27;//备份区域时钟

//3.取消备份区写保护

PWR->CR|=1<<8;

//4.开始软件复位,开启外围振荡器

RCC->BDCR|=1<<16;

RCC->BDCR&=~(1<<16);//软件复位结束

RCC->BDCR|=1<<0;//开启外围振荡器 提供时序

//5.等待时间,检查晶振是否有问题

    while((temp<250)&&(!(RCC->BDCR&0X02)))//未准备就绪,振荡器未被旁路

{

temp++;

delay_ms(10);

}

if(temp>=250)return 1;//晶振失效

//6.确定时钟以及时钟使能

//由于RTC的操纵敏感 注意检测rtc的寄存器上一步是否操作完成和同步

RCC->BDCR|=1<<8;//确定时钟为LSI(内部低速时钟)

RCC->BDCR|=1<<15;//enable the clock

while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成

while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步

RTC->CRH|=0X01;//秒同步

while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成

RTC->CRL|=1<<4;//允许配置

  

//7.配置时钟

RTC->PRLH=0X0000;//预分频系数的高16位

RTC->PRLL=32767;//预分频系数的第16位

RTC_Set(2018,7,1,21,03,00);//设置初始化时钟

RTC->CRL&=~(1<<4);//开始配置

while(!(RTC->CRL&(1<<5)));//等待操作完成

BKP->DR1=0x5050;//初始化标志位

printf("FIRST TIME");

}

else

{

while(!(RTC->CRL&(1<<3)));//等待同步

RTC->CRH|=0X01;//允许秒中断

while(!(RTC->CRL&(1<<5)));//等待操作完成

printf("OKn");

}

//设置中断优先级

MY_NVIC_Init(0,0,RTC_IRQn,2);

RTC_Get();

return 0;

}     

//RTC时钟中断

//每秒触发一次   

void RTC_IRQHandler(void)

{  

if(RTC->CRL&0x0001)//秒钟中断

{

RTC_Get();//更新时间   

//printf("sec:%drn",calendar.sec);

  }

if(RTC->CRL&0x0002)//闹钟中断

{

RTC->CRL&=~(0x0002); //清闹钟中断   

  //printf("Alarm!n");    

  }    

    RTC->CRL&=0X0FFA;         //清除溢出,秒钟中断标志

while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成            

}

2.判断是否是闰年


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;

}    

//设置时钟

//把输入的时钟转换为秒钟

//以1970年1月1日为基准

//1970~2099年为合法年份

//返回值: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};

//syear,smon,sday,hour,min,sec:年月日时分秒

//返回值:设置结果。0,成功;1,失败。

3.设置时间 



1.所得值放在RTC->CNTR和RTC->CNTL中(2个16位寄存器)


2.设定基准值(以1970 1 1为基准)计算到目标年的秒数(年月日)


计算所得值


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; //由于设定的基准年为1970年,再加上32位的寄存器 直到2106年也不会溢出   

for(t=1970;t

{

if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数

else seccount+=31536000;   //平年的秒钟数

}

smon-=1;

for(t=0;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;//最后的秒钟加上去

//先把所有的秒钟统计 然后再去计算小时 分钟 秒钟     

//设置时钟(对RTC的再一次配置)

    RCC->APB1ENR|=1<<28;//使能电源时钟

    RCC->APB1ENR|=1<<27;//使能备份时钟

PWR->CR|=1<<8;    //取消备份区写保护

//上面三步是必须的!

RTC->CRL|=1<<4;   //允许配置 

RTC->CNTL=seccount&0xffff;//除低16位都清0(确定低16位)

RTC->CNTH=seccount>>16;//确定高16位

RTC->CRL&=~(1<<4);//配置更新

while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 

RTC_Get();//设置完之后更新一下数据

return 0;     

}

4.获取时间


读出RTC->CNTH的值(秒)


根据所得值分别计算是某年 某月 某日 某星期


//得到当前的时间,结果保存在calendar结构体里面

//返回值:0,成功;其他:错误代码.

u8 RTC_Get(void)

{

static u16 daycnt=0;

u32 timecount=0; 

u32 temp=0;

u16 temp1=0;

//将数据写入 移位写入 

  timecount=RTC->CNTH;//得到计数器中的值(秒钟数)

timecount<<=16;

timecount+=RTC->CNTL;//已经得到所有的秒数(由于STM32的寄存器为32位 所以可以支持大概136年的计时时间)  

 

  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 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;

}  

5.为什么数据会使动态的呢?

    设置分频系数(psc=32767),做到每1s对数据进行更新,同时 可以进行进行中断函数的配置 达到闹钟的效果

 


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
输入引脚的过电应力(EOS)保护