RTC实时时钟9 m; v) H5 R3 V, `
1. RTC实时时钟简介STM32的实时时钟RTC是一个独立的定时器,RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能,修改计数器的值可以重新设置系统当前的时间和日期
5 m8 V! y. t5 O8 F6 h6 TRTC模块和时钟配置系统(RCC_BDCR寄存器)是在后背区域,即在系统复位或从待机模式唤醒后RTC的设置和事件维持不变。但是在系统复位后,会自动禁止访问后备寄存器和RTC,以防止对后备区域(BKP)的意外操作。所以在要设置时间之前,要先取消备份区域写保护。RTC的简化框图如下所示:
6 |- U* Q! X7 F9 ]7 ]. n) F8 Q
" a5 l) M v7 k1 U W9 T; {- ~$ N5 ~
+ |0 k" @! ^8 K
7 b5 B: z/ A$ {+ x$ Y5 qRTC由两个主要部分组成:第一部分(APB1接口)用来和APB1总线相连,此单元还包含一组16位寄存器,可通过APB1总线对其进行读写操作;另一部分(RTC核心)由一组可编程计数器组成,分为两个主要模块,第一个模块是RTC的预分频模块,可编程产生1秒的RTC时间基准TR_CLK。第二个模块是一个32位的可编程计数器(RTC_CNT),可被初始化为当前的系统时间,一个32位的时钟计数器按秒钟计算可以记录4294967296秒,约136年左右,一般应用已经足够
+ H" Q/ t- E z- A8 _8 _% V2 Y
" S2 _3 y7 R: `* o5 \7 S/ ARTC还有一个闹钟寄存器RTC_ALR,用于产生闹钟。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CNT = RTC_ALR将产出一个闹钟中断,从而实现闹钟功能
- L; @7 {* M2 j( f
2. 硬件设计
, {7 T0 z0 M7 s6 z0 M本实验通过RTC的秒中断来持续输出时间通过串口1打印出来,并通过设置闹钟中断实现一个闹钟提醒,D1指示灯提示系统正常运行 - D1指示灯
- USART1串口
- RTC9 S/ q3 s# y+ y; L4 M | p- V
. f" H4 W6 j+ g: p
( e# G$ n% j9 `' a3 b* `
; c8 ~/ V0 f: W5 \2 f: C
3. 软件设计3.1 STM32CubeMX设置; W7 {8 G# k @ ` J, q9 J
- RCC设置中开启外部高速晶振(HSE)以及外部低速晶振(LSE),时钟树中将RTC的频率设置为32.768KHz# ]. V$ @7 ?: Q; U2 @5 s& t9 q3 r T
1 |' p$ v$ r9 o# c; R- c- L
8 V# p% b$ |! C' o/ d
o8 E+ U: B1 ?& e3 w: V* Z# m
6 z/ j# x1 @5 X4 M0 l/ O' |4 j
: o' e: A+ o7 F6 w8 S- }, a
% x- q) U& i! {2 N0 T; H% ~% e& S/ N- f/ u2 j- c
% O, D: |' n# j" O$ \- PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
- USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
- 激活时钟源,激活日历,选择No RTC Output,设置初始日期和时间
# l8 K/ E9 T' u v6 p
: y! @( l0 R% L! J1 h* i! \* O 8 R7 u' a3 _, v$ K6 \
! T! l6 l: f7 Z% C1 d* w
& x) s% H/ [# x* H6 [; ]" c: n
- 使能RTC全局中断和闹钟中断7 ^9 Y! j( d) }& A
8 |' Z( x T; o! r% Z7 H f
+ i0 I* y( @6 M4 e* Q# K$ L! _, U9 |/ u! O8 d/ Z, B0 f
9 c. }; D3 G2 K3 ^( Q4 v$ i: w; {! R- 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
/ p5 b. o/ L; W0 a. a! F+ u! @' b
r# Q1 ?, Q3 z/ D0 K' X; H$ K0 s+ V- L5 \7 B; ], i5 `% v' }6 U9 O$ V, e
3.2 MDK-ARM编程: c$ U* Y, y3 N) G
! Z& @6 ?! B [2 F" P1 @9 @
- 在rtc.c文件中编写秒中断处理回调函数和闹钟中断处理函数
( }0 u$ q+ x7 f8 L" X! a; w8 h' F3 u
* y: A9 V! B+ l7 [
8 w: E2 ?$ R2 U& h) Q- r- extern RTC_DateTypeDef GetDate;5 O# K! L, T) c8 X9 m' R* @* l) t
- extern RTC_TimeTypeDef GetTime;- c# O7 L" F1 S0 D7 h! `) N
3 I0 s6 X7 m! m) [- void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc){
* a) L' H+ K6 C! W3 J. m - HAL_RTC_GetTime(hrtc,&GetTime,RTC_FORMAT_BIN);+ o5 [$ {7 W5 [1 x& J: o" ^. `
- HAL_RTC_GetDate(hrtc,&GetDate,RTC_FORMAT_BIN);
. h/ a2 h4 I1 P9 l - printf("Date:%02d-%02d-%02d\r\n",2000+GetDate.Year,GetDate.Month,GetDate.Date);: y( j0 U7 O' I
- printf("Time:%02d:%02d:%02d\r\n",GetTime.Hours,GetTime.Minutes,GetTime.Seconds);3 G( c ~8 j x7 l
- printf("\r\n"); / ^$ F& }& q6 N0 ?
- }
3 D1 j4 v* q/ h6 V W5 `& f0 A# v - 0 H: }# h. m5 q$ X: j7 l
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc){
7 G( x0 r9 D0 k2 V, D9 o K - printf("Alarm Active...!!!\n");; U! k2 T% u8 Q( G" I. G! p: f
- }
复制代码
9 Y( d* |. W. U' b# o- _) |" X0 h8 T4 t( n5 w5 i/ L: V
- 在main.c文件中编写闹钟设置相关代码并开启相关中断
5 O/ X- A- l$ J5 j/ z # \. l0 Y8 S( n' {$ V0 v: t
- v9 ?' H8 C2 k& u5 T6 F" Q
- /* USER CODE BEGIN PV */
. E1 `0 {+ A$ G5 X- y - RTC_DateTypeDef GetDate;) w- C# x$ `8 _# z7 \
- RTC_TimeTypeDef GetTime;
1 R4 X; `4 K8 X X: q, W4 } - RTC_AlarmTypeDef sAlarm;
* f1 E% I% J* T+ a - /* USER CODE END PV */2 N1 a2 T/ @- o1 y$ }. N7 t
- /* Private function prototypes -----------------------------------------------*/% q* K" ]; l' g# H
- void SystemClock_Config(void);2 x' K, _9 K& y
D0 l; ~: Y1 R c8 f6 Y- int main(void){' H0 c5 W; q# v/ `
- HAL_Init();
& o8 T; }% L' S6 P2 @' W" ? - SystemClock_Config();
7 y* w1 d7 R! A! T( w: o - /* Initialize all configured peripherals */
; R3 ]9 R: |, |: m) o) Q( u8 j - MX_GPIO_Init();
- E- E* G; U& m1 x2 K4 p4 l - MX_RTC_Init();+ ?! m% k- @9 M) M: ?: y
- MX_USART1_UART_Init();. P H6 P3 j) K+ @3 l4 J6 ?# I: R
- /* USER CODE BEGIN 2 */
- s* I& T5 s4 h- i* U - __HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC); //开启秒中断
7 B) o }! { {2 z/ a5 f2 i - sAlarm.Alarm = RTC_ALARM_A;
/ u# `( F" `5 b' Z3 ~ - sAlarm.AlarmTime.Hours = 16;
8 ]: l9 l( P _* g4 r: K) @ - sAlarm.AlarmTime.Minutes = 20;! P+ b6 E' O3 }& e) C- k1 W
- sAlarm.AlarmTime.Seconds = 30;
" v. D+ }0 |3 { B- m9 G! X - HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,RTC_FORMAT_BIN); //设置闹钟并使能闹钟中断% t2 a1 o* L, \# g
- /* USER CODE END 2 */
( F* |: J8 X% ~7 b - while (1){
' W0 d: p5 E6 j - HAL_Delay(1000);
7 p! W' n& e/ P - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0); E- n" \, a/ x7 C2 T& s
- }
0 i, _ Q. Q/ {- S! \ - }
复制代码 " z/ J$ }' i9 C* a- p
, J6 A3 W5 y$ C i( P- |: M$ x4. 下载验证
4 m$ s. K& e6 X! T( @& h: _! Q编译无误后下载到开发板,可以看到D1指示灯每1s闪烁一次,串口助手每1s会打印出相应的日期和时间,闹钟设置的时间到后会打印出闹钟中断函数里的相关语句 1 h0 a F# f4 f
' ~) a- }- n1 K( p, h- N/ `7 b& G3 `' ]6 c6 A3 v) n3 T4 |
; T' N1 {, T$ f( l' g |