蓝桥杯嵌入式开发指南 07 - 实时时钟配置(RTC)
实例
通过配置实时时钟,在 LCD 屏幕上显示时间。
电路分析
实时时钟(RTC)是一个用于获取时间的模块,STM32 把实时时钟集成在了芯片内部,它内部具有专门的实时时钟单元,不需要外接其他模块。
工程建立
本次工程在上一次的工程上继续修改,复制上一次的工程作为本次的工程基础。
添加库函数
本例中使用到了 RTC 时钟功能以及相关的 PWR 和 BKP 功能,故要添加以下库函数:
- stm32f10x_rtc.c
- stm32f10x_bkp.c
- stm32f10x_pwr.c
实时时钟 RTC
简介
实时时钟是一个独立的定时器。RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
可编程的预分频系数:分频系数最高为 220。
主要特性
- 32 位的可编程计数器,可用于较长时间段的测量
- 2 个单独的时钟:用于 APB1 接口的 PCLK1 和 RTC 时钟(此时的 RTC 时钟必须小于 PCLK1 时钟的四分之一以上)
- 2 种独立的复位类型
- APB1 接口由系统复位
- RTC 只能由后备域复位。
- 3 个专门的可屏蔽中断:
- 闹钟中断:用来产生一个软件可编程的闹钟中断
- 秒中断:用来产生一个可编程的周期性中断信号(最长可达 1 秒)
- 溢出中断:检测内部可编程计数器溢出并回转为 0 的状态
RTC 相关模块
RTC 模块和时钟配置系统 (RCC_BDCR 寄存器) 处于后备区域,即在系统复位或从待机模式唤醒后,RTC 的设置和时间维持不变。
系统复位后,对后备寄存器和 RTC 的访问被禁止,这是为了防止对后备区域 (BKP) 的意外写操作。执行以下操作将使能对后备寄存器和 RTC 的访问:
- 设置寄存器 RCC_APB1ENR 的 PWREN 和 BKPEN 位,使能电源和后备接口时钟
- 设置寄存器 PWR_CR 的 DBP 位,使能对后备寄存器和 RTC 的访问。
故需要先使能备份寄存器 BKP 后,才能对 RTC 进行访问。
同时,备份寄存器 BKP 受到 PWR 电源管理控制,故需要在 PWR 中先使能 Backup 寄存器,若没有使能,则无法正常对 RTC 进行读写操作。
初始化 RTC 时钟
1 | void RTC_Init(void) |
特别提醒
LSI 时钟频率大约 40KHz,RTC 需要 1HZ 的时钟,此处所填写的预分频值 40000-1 其实是一个估算值,若要将 RTC 时钟作为精准时钟,需要对通过定时器捕获来对 LSI 进行计算校正。
配置 RTC 中断
定义全局变量:
1 | u8 RTC_Flag=1; //RTC1秒标志 |
1 | void RTC_IRQHandler(void) |
数据显示
实例,给程序添加如下功能:
- 初始化 RTC 时钟时间为:23:59:55
- 在 LCD 的第 8 行以 Blue2 颜色按格式显示 “Time:HH:MM:SS”RTC 时钟时间
定义全局变量:
1 | u32 Time_Value=0; |
修改 RTC 初始化程序:
1 | void RTC_Init(void) |
修改主程序:
1 | int main(void) |
下载测试
将程序下载到开发板,可以看到 LCD 屏幕第八行按要求正确显示 RTC 时钟时间。
延伸拓展
RTC 时钟 LSI 时钟源校准方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 #ifdef LSI_TIM_MEASURE
/\* Enable the LSI OSC \*/
RCC_LSICmd(ENABLE);
/\* Wait till LSI is ready \*/
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
/\* TIM Configuration \*/
TIM5_ConfigForLSI();
/\* Wait until the TIM5 get 2 LSI edges \*/
while(CaptureNumber != 2);
/\* Disable TIM5 CC4 Interrupt Request \*/
TIM_ITConfig(TIM5, TIM_IT_CC4, DISABLE);
#endif
#ifdef LSI_TIM_MEASURE
/\*\*
\* @brief Configures TIM5 to measure the LSI oscillator frequency.
\* @param None
\* @retval None
\*/
void TIM5_ConfigForLSI(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
/\* Enable TIM5 clocks \*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
/\* Enable the TIM5 Interrupt \*/
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/\* Configure TIM5 prescaler \*/
TIM_PrescalerConfig(TIM5, 0, TIM_PSCReloadMode_Immediate);
/\* Connect internally the TM5_CH4 Input Capture to the LSI clock output \*/
GPIO_PinRemapConfig(GPIO_Remap_TIM5CH4_LSI, ENABLE);
/\* TIM5 configuration: Input Capture mode ---------------------
The LSI oscillator is connected to TIM5 CH4
The Rising edge is used as active edge,
The TIM5 CCR4 is used to compute the frequency value
------------------------------------------------------------ \*/
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM5, &TIM_ICInitStructure);
/\* TIM10 Counter Enable \*/
TIM_Cmd(TIM5, ENABLE);
/\* Reset the flags \*/
TIM5->SR = 0;
/\* Enable the CC4 Interrupt Request \*/
TIM_ITConfig(TIM5, TIM_IT_CC4, ENABLE);
}
#endif