Stm32 RTC介绍相关笔记

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("OK\n");
		}
		//设置中断优先级
		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:%d\r\n",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<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;//最后的秒钟加上去
	//先把所有的秒钟统计 然后再去计算小时 分钟 秒钟										    
	//设置时钟(对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对数据进行更新,同时 可以进行进行中断函数的配置 达到闹钟的效果



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值