使用STM32和OLED屏幕实现简易实时时钟(下篇)

一、RTC简介

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可
提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒
后,RTC的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,
以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)
写保护。

二、RTC主要特性

挑了主要的特性:

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

2个分离的时钟:用于APB1接口的PCLK1和RTC时钟

3、可以选择以下三种RTC的时钟源:
HSE时钟除以128
LSE振荡器时钟
LSI振荡器时钟

4、2个独立的复位类型:
APB1接口由系统复位;
RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位;

5、3个专门的可屏蔽中断:
闹钟中断,用来产生一个软件可编程的闹钟中断。
秒中断,用来产生一个可编程的周期性中断信号(最长可达1秒)。
溢出中断,指示内部可编程计数器溢出并回转为0的状态。

三、功能描述

RTC由两个主要部分组成(参见下图)。第一部分(APB1接口)用来和APB1总线相连。此单元还包
含一组16位寄存器,可通过APB1总线对其进行读写操作。APB1接口由APB1总线时钟驱动,用来与APB1总线接口。

另一部分(RTC核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频
模块,它可编程产生最长为1秒的RTC时间基准TR_CLK。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。

说白了APB1总线的作用是为RTC模块提供通信和数据传输的通道,使得RTC模块能够与其他外设进行数据交换和通信。且在系统复位后需要控制APB1总线上的RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟使能对后备寄存器和RTC的访问

RTC预分频器控制计数频率,RTC_CNT与RTC_ALR值进行对比(和定时器类似)即产生闹钟

四、RTC寄存器描述

1、RTC控制寄存器高位(RTC_CRH)

中断使能。因为在系统复位之后所有的中断都被屏蔽(即此寄存器的所有位都被置为0),如果我们需要开启相应的中断则给相应的中断位置1(执行此操作的前提是RTC_CRL寄存器的标志位RTOFF=0)即对RTC寄存器的写操作完成。

2、RTC控制寄存器低位(RTC_CRL)

此寄存器是RTC模块的一些标志位。第 0 位是秒钟标志位,我们在进入闹钟中断的时候,通过判断这位来决定是不是发生了秒钟中断,此位只能通过软件清除。第3位为寄存器同步标志位,结合RTC框图,只有当寄存器同步后,才可以修改RTC_CRH和RTC_CRL的寄存器的值,否则修改的值无效。第4位是配置标志,即要想RTC寄存器写值时必须将此位置1。第5位,就是等待写操作完成,否则写入的值也无效。

所以RTC寄存器的配置过程应该是这样:
1. 查询RTOFF位,直到RTOFF的值变为’1’(判断写操作是否完成)
2. 置CNF值为1,进入配置模式
3. 对一个或多个RTC寄存器进行写操作
4. 清除CNF标志位,退出配置模式
5. 查询RTOFF,直至RTOFF位变为’1’以确认写操作已经完成。

3、RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)

RTC_PRLH

RTC_PRLL

这两个寄存器用来配置 RTC 时钟的分频数的,比如我们使用外部 32.768K 的晶振作为时钟的输入频率,那么我们要设置这两个寄存器的值为 32767,以得到一秒钟的计数频率。

4、RTC预分频器余数寄存器(RTC_DIVH / RTC_DIVL)

用户可通过读取RTC_DIV寄存器,以获得预分频计数器的当前值,此寄存器是只读寄存器,其值在RTC_PRL或RTC_CNT寄存器中的值发生改变后,由硬件重新装载。这两个寄存器的作用就是用来获得比秒钟更为准确的时钟,比如可以得到 0.1 秒,或者 0.01 秒等。

5、RTC计数器寄存器 (RTC_CNTH / RTC_CNTL)

RTC_CNT寄存器用来存放计数器的计数值。没过一秒此寄存器加1,可通过读取该寄存器的值来获得当前的时间。

因为没用到闹钟寄存器这里就不介绍了

五、其它寄存器

备份寄存器

数据备份寄存器,即使此寄存器断电依然可以保存数据,通过向此寄存器写入数据,当断电之后读取此寄存器的数据进行判断跳过RTC的初始化环节。

2、APB1 外设时钟使能寄存器(RCC_APB1ENR)和电源控制寄存器(PWR_CR)

系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操
作。执行以下操作将使能对后备寄存器和RTC的访问:

设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟

设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。

3、备份域控制寄存器 (RCC_BDCR)

将LSEON位置1使能外部低速振荡器,判断LSERDY外部LSE是否就绪,最后RTCSEL置为01选择LSE最为RTC的时钟,就完成了对RTC部分对时钟的配置。

在RTC初始化的时候应该将BDRST位置1,清除备份区域

六、主函数代码

int main(void)
 {
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
 	LED_Init();			     //LED端口初始化
	OLED_Init();			//初始化OLED      
	RTC_Init();	  			//RTC初始化
  OLED_ShowString(0,0,"RTC Test",12);  
	
  
	OLED_Refresh_Gram();		//更新显示到OLED 
//	t=' ';  
	while(1) 
	{		
		switch(calendar.week)
		{
			case 0:
			OLED_ShowString(0,12,"Sunday",12); 
			break;
			case 1:
			OLED_ShowString(0,12,"Monday",12); 
			break;
			case 2:
			OLED_ShowString(0,12,"Tuesday",12); 
			break;
			case 3:
			OLED_ShowString(0,12,"Wednesday",12); 
			break;
			case 4:
			OLED_ShowString(0,12,"Thursday",12); 
			break;
			case 5:
			OLED_ShowString(0,12,"Friday",12); 
			break;
			case 6:
			OLED_ShowString(0,12,"Saturday",12); 
			break;
			default:
			break ;
		}
	
		OLED_ShowNum(0,24,calendar.hour,2,12);
		OLED_ShowString(12,24,":",12); 
		OLED_ShowNum(18,24,calendar.min,2,12);
		OLED_ShowString(30,24,":",12); 
		OLED_ShowNum(36,24,calendar.sec,2,12);
		
		OLED_ShowNum(0,36,calendar.w_year,4,12);
		OLED_ShowString(24,36,"/",12); 
		OLED_ShowNum(30,36,calendar.w_month,2,12);
		OLED_ShowString(42,36,"/",12); 
		OLED_ShowNum(48,36,calendar.w_date,2,12);
		
		
		OLED_Refresh_Gram();		//更新显示到OLED 
	}	  
	
}

RTC模块是参考原子哥的,其实大家只要把RTC功能框图和RTC相关寄存器搞熟悉之后RTC模块还是不难的。如果有其它问题可以评论或给我留言

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32和OLED屏幕实现简易实时时钟(下篇)

发表评论