stm32-OLED屏+RTC实现简易实时时钟(下篇)

一、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模块还是不难的。如果有其它问题可以评论或给我留言

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是野火STM32板子上OLED显示RTC时钟的标准库程序,你可以根据自己的需求进行修改: ```c #include "stm32f10x.h" #include "oled.h" #include "rtc.h" RTC_TimeTypeDef RTC_TimeStructure; RTC_DateTypeDef RTC_DateStructure; uint16_t RTC_Year = 0, RTC_Month = 0, RTC_Date = 0, RTC_WeekDay = 0; uint8_t RTC_Hours = 0, RTC_Minutes = 0, RTC_Seconds = 0; char time_str[20]; int main(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); BKP_DeInit(); RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_SetPrescaler(32767); RTC_WaitForLastTask(); OLED_Init(); OLED_Clear(); OLED_ShowString(0, 0, "RTC Clock:", 16); while (1) { RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure); RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure); RTC_Year = RTC_DateStructure.RTC_Year + 2000; RTC_Month = RTC_DateStructure.RTC_Month; RTC_Date = RTC_DateStructure.RTC_Date; RTC_WeekDay = RTC_DateStructure.RTC_WeekDay; RTC_Hours = RTC_TimeStructure.RTC_Hours; RTC_Minutes = RTC_TimeStructure.RTC_Minutes; RTC_Seconds = RTC_TimeStructure.RTC_Seconds; sprintf(time_str, "%04d/%02d/%02d %02d:%02d:%02d", RTC_Year, RTC_Month, RTC_Date, RTC_Hours, RTC_Minutes, RTC_Seconds); OLED_ShowString(0, 2, time_str, 16); } } ``` 在这个程序中,我们使用了STM32F10x标准库和OLEDRTC库。程序的主要功能是在OLED幕上显示当前RTC时钟。在程序中,我们首先初始化RTC时钟,然后初始化OLED幕,并在幕上显示"RTC Clock:"的提示信息。接着进入一个死循环,不断读取RTC时钟信息,并将其转换为字符串格式,在OLED幕上显示出来。需要注意的是,我们使用了sprintf函数将时间信息转换为字符串格式,sprintf函数的使用可以参考相关文档。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值