我现在做的一个项目中需要单片机连接的屏幕可以显示时间,这时候RTC的重要性就体现出来了。
STM32的RTC(Real Time Clock,实时时钟)是一个独立的定时器,在相应软件配置下,可提供时钟日历的功能,在断电情况下RTC仍可以独立运行。只要芯片的备用电源(一般是一块纽扣电池)一直供电,RTC上的时间会一直走。
RTC包括时间Time和日期Date
在Cube的时钟设置界面可以看到,RTC的时钟来源有3个,HSE/128、LSE和PLL时钟
使用HSE分频时钟或者LSI的时候,在单片机掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作。所以RTC一般都使用时钟低速外部时钟LSE,频率为实时时钟模块中常用的32.768KHz。32,768 = 2^15,分频容易实现,所以被广泛应用到RTC模块。
我们测试下RTC的功能,使用串口把系统时间打印出来。很简单的测试。
- 首先在时钟界面选择RTC的时钟来源为LSE,32.768KHz(需要在RTC属性栏里勾选
Active Clock Source
- 在参数设置界面上把当前时间的几个参数都设置好
这里要注意Year无法设置为2022,只可取后面2位 - 其他都按照之前的工程配置好,激活串口(USART1)
- generate code
可以从stm32f1xx_hal_rtc.c
中看到有几个重要的函数
HAL_RTC_SetAlarm()
HAL_RTC_GetAlarm()
HAL_RTC_SetDate()
HAL_RTC_GetDate()
HAL_RTC_SetTime()
HAL_RTC_GetTime()
在main函数中定义两个结构体
RTC_DateTypeDef GetData; //Date结构体
RTC_TimeTypeDef GetTime; //Time结构体
然后在while(1)
循环中加入
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &GetDate, RTC_FORMAT_BIN);
printf("%02d/%02d/%02d\r\n",2000 + GetDate.Year, GetDate.Month, GetDate.Date); //注意这里为什么用2000+
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
HAL_Delay(3000);
烧写完后,打开串口调试助手可以看到每隔3秒会显示时间。可以将初始时间设置为23:59:00,然后看过了一分钟后确实日期会过一天,时间从0开始了。
但是这段简单的代码很不实用,有两个问题,第一个问题:掉电后时间会重新从代码中设定的时间开始走。这个问题就很奇怪了,按道理RTC如果使用LSE时钟的话,是可以用备用电池供电的。
第二个问题,每次时间都是要在代码里设定好,只是走一个定时器获取新的时间而已,即时间的相对值是对的,但是时间的绝对值是肯定没办法在写代码的时候知道的。这也是为什么大部分单片机单机的应用都会提示用户来输入当前时间。
所以我们也可以利用scanf
通过串口来获取用户设定的时间,稍微增加一些难度。
这两个问题我会在后续章节中解决。