STM32日历功能:读取、设置和输出
目录
关于RTC
1、RTC介绍
RTC(Real Time Clock):实时时钟,是指可以像时钟一样输出实际时间的电子设备,一般会是集成电路,因此也称为时钟芯片。总之,RTC只是个能靠电池维持运行的32位定时器,并不像实时时钟芯片,读出来就是年月日。
RTC就只一个定时器而已,掉电之后所有信息都会丢失,因此我们需要找一个地方来存储这些信息,于是就找到了备份寄存器(BKP)。因为它掉电后仍然可以通过纽扣电池供电,继续工作,所以能时刻保存这些数据。
stm32F103使用外部晶体的32.768kHz的振荡器,产生一个1秒长的时间基准。
RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护。
2、工作过程
RTC只是一个时钟,但与RTC相连的有两个系统时钟:一个是APB1接口的PCLK1,另一个是RTC时钟。这样,RTC功能也就分为两个部分:第一部分,APB1接口部分,与APB1总线相连,MCU也就是通过这条总线对其进行读写操作。另一部分,RTC核心,其整个核心部分位于后备区域,所以只要有VBAT引脚供电,就能一直工作,由一系列可编程计数器组成,这部分又再细分为两个组件:20位的预分频模块与32位可编程计数器。预分频模块用来产生最长为1秒的RTC时间基准,而32位的可编程的计数器可被初始化为当前的系统时间。
RTC_PRL:预分频装载寄存器
RTC_DIV:预分频器余数寄存器
RTC_CNT:计数器寄存器
RTC_ALR:闹钟寄存器
首先,在初始化时候,DIV和PRL都会装载同样的数。RTCCLK频率为32.768kHz,来驱动DIV工作,DIV为自减寄存器。当DIV减少到0时,会产生一个TR_CLK信号,该信号会触发三件事情:①将PRL的数重装在到DIV中;②触发CNT计数器+1;③触发SECF,进而产生秒中断。我们会设置一个合理的预分频数,使得TR_CLK触发时间刚好是1s。ALR中存储的是我们设置的闹钟秒数,当CNT和ALR中的数据相同时,就会触发闹钟中断或者闹钟唤醒。(关于CNT和ALR中存放的数据,为时间戳。)
1s的时间如何计算?
我们的RTC_CLK为32.768kHz,所以只要PRL中写入32767即可,即为2的15次方。
我们只需要在PRL的低16位寄存器中写入0x7FFF即可。
DIV寄存器存在的意义?
从上述能知道TR_CLK输出必须为1s。那么我们想要的到0.15s,应该怎么实现呢?
道理很简单,因为DIV是自减的,并且从32768一直减少到0,所需要的时间为1s。所以减少一个数,所用的时间为1/32768s,那么减少多少个数,就计时了0.15s呢?
1/32768s * n = 0.15
n = 0.15 * 32768
又因为DIV寄存器是可读的,所以我们就能实现0.15s的计时。
从框图中,还可以看到,只有秒中断和闹钟中断能触发中断,溢出是没有中断的。
STM32CubeMAX界面
读取STM32F103C8T6 内部的时钟(年月日时分秒),日历(星期x),1秒周期,通过串口输出到PC上位机
设置RCC
设置RTC
设置RTC参数
设置时钟树
创建工程
keil界面
在main.c文件中重写fputc函数,完成printf函数的重定向
//添加头文件#include "stdio.h"
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
在main.c中定义时间和日期的结构体用来获取时间和日期
RTC_DateTypeDef GetData; //获取日期结构体
RTC_TimeTypeDef GetTime; //获取时间结构体
在main函数的while循环中添加以下代码
/* Get the RTC current Time */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
/* Display date Format : yy/mm/dd */
printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display time Format : hh:mm:ss */
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("\r\n");
HAL_Delay(1000);
编译运行结果如下: