(一)工程配置( c+ T3 G6 h" }" v) l
我使用STM32F103RB这一款MCU,首先使用STM32CUBEMX创建工程,配置主时钟和RTC时钟,我板子上是使用的外部的32.768K晶振供RTC:9 L X' G; c9 B2 I3 n/ P! R0 q( a
" s' k) f; Y: Z1 N9 c" P+ ~
3 i3 l, \# z: g
% ~/ L. U/ n- b6 M
9 O9 V* Q7 S1 l( F5 A- S; M
配置了两个LED灯:5 c2 l! p; f# N' d
3 f1 P' Q' V/ u
" c) u: ?$ k. h) h' _
' S2 _. Z; V4 E0 ?3 v3 g配置调试下载接口为SWD(此步骤如果不配置,你使用stlink的话下载一次程序之后就再次下载就会找不到MCU):
0 n1 z+ M- }7 E/ V
9 \9 V' m! _ {6 s. ~0 [' _
" z: k7 Z5 w' ?! n: |; S9 ?4 @
7 A/ J+ Z& t9 S& V8 j. R* d7 L! c配置串口1:
7 Y; N9 m# ?7 s5 d- S# Q$ }' ?; R2 R8 z0 }& N' Q
9 ]# ?' X( {: [- ^
; K5 r x2 r) \. A5 V' J配置RTC时钟,激活日历和时钟源,这里我设置时间为2020年12月25日0点0分0秒,设置闹钟提醒的时间为3s:0 K6 T# [& X+ v. Z
7 b0 d+ z- w6 A' l" G/ y
2 z' I4 y8 t$ V
9 L/ V1 d$ g% |( `+ i) b使能RTC闹钟提醒功能的中断:+ Y/ h0 M2 G/ X7 f- S. n
- V0 ?( |# e& ]! p
; k; U) R! J, W3 V2 e
- @/ Z2 [( B7 A4 T7 F7 v其他工程设置:
8 f- E7 M6 Y/ e A% g! M3 d- ?5 D6 C! Y7 }4 u; t
0 V" B1 d% ]$ l; s) x2 v3 F, h( X1 M1 a$ F# B% ]
然后生成工程就可以了。
" a& K0 ]: ?5 y( ^- h0 `0 F6 ]1 e9 Z: |+ `& P$ n- m- P
(二)代码编写
* t% z4 B6 ?# V! X重定向printf函数:# O2 x/ X. i1 O4 N2 F
; O7 b' Y: C( a t4 U- int fputc(int ch, FILE* fp)
: \" O$ A# T$ ~2 p - {
! ]5 u2 ]$ b6 k: ^" h- b - while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) != SET);: P! V: |, }9 L+ E
- huart1.Instance->DR = ch & 0XFF;$ Z( X8 f- ~2 q9 r" ?
- return ch;
8 B8 F1 p- \7 P2 S& J - }
复制代码 % r$ o4 k ?0 {+ [
HAL库获取RTC时间的函数有两个:3 m* k8 F$ b8 N3 Q
HAL_RTC_GetTime:获取时间7 s; U/ M2 k+ f) K$ K
HAL_RTC_GetDate:获取日期
) h6 d0 V) o- X' |4 B; M5 D5 m4 w& P, ^+ G, g! l0 W
这两个函数的第三个参数是格式:RTC_FORMAT_BIN和RTC_FORMAT_BCD,BIN格式就是十六进制数值直接表示的时间数值,BCD格式就是用数值的十六进制面值表示时间数值,例如表示第24分钟的时候,BCD格式的分钟值就是0X24。. g: h8 {: C i8 r2 w
! R* m5 ]* u; F+ N( i; L注意: 这两个函数调用是有先后顺序的,必须先调用HAL_RTC_GetTime然后在调用HAL_RTC_GetDate。
1 s4 G" e2 {- f& b3 `, I! }
0 b9 v* d9 f) c6 U; w2 r4 I3 `可以通过以下两个函数设置时间:1 O* y' R, h ]0 O9 y; O, }: D I
HAL_RTC_SetTime
8 a, j8 E$ W( q6 U# p$ q5 S5 r' `HAL_RTC_SetDate8 i, \5 m4 |& c+ o8 f; G
, e/ G/ P y A2 ~0 ^* q9 c这里我简单的把时间设置的函数做了个封装:/ P: a+ ]; k2 u( y) X" [* G! c
$ E4 m! R- I( z- n- #pragma pack(1): ?4 z: O6 y e0 x9 O
- typedef struct
- w( q' V/ _% M) b' }( n2 k( ` - {
5 H2 [/ Z T F( u$ q - uint8_t Hours;- `% f; \7 }- U, t3 g
- uint8_t Minutes;
4 H* Y- m) E1 @, C. ~% u6 ^/ z) a - uint8_t Seconds;
8 H3 s9 G1 a6 G, l; n& g4 r - uint8_t WeekDay;
6 S9 d, \5 w3 d/ A/ p - uint8_t Month;9 Q3 f9 I, V& z/ G8 T
- uint8_t Day;! n" {/ F2 P5 L/ Z+ y; J
- uint8_t Year;7 h7 P0 U5 {; i4 E
- } rtc_time_t;
, N# H$ v- A1 E) c2 w3 \% n; @ - #pragma pack()2 A4 `2 M; {# J" U
- - ?! R7 g0 B: M# Y# O
- 1 N! m6 v, d5 s4 L! n
- void RTC_GetTime(rtc_time_t* time)2 C$ }+ b+ }& N. e3 M
- {- c4 d e5 L) U: P! Y* h' W
- HAL_RTC_GetTime(&hrtc, (RTC_TimeTypeDef *)&time->Hours, RTC_FORMAT_BIN);
) ?& X) J c! |1 a - HAL_RTC_GetDate(&hrtc, (RTC_DateTypeDef *)&time->WeekDay, RTC_FORMAT_BIN);
( \! ^& t7 f' y: y6 z0 j) X - }
# n- x7 j2 n6 _1 t4 l3 J8 c - * O( B) t% [9 x% c
- void RTC_SetTime(rtc_time_t* time)
`7 n, h i1 n" o8 |1 r1 [* ^* x - {+ G9 f: |( |6 W' @0 z9 k5 l# m
- HAL_RTC_SetTime(&hrtc, (RTC_TimeTypeDef *)&time->Hours, RTC_FORMAT_BIN);
9 v6 h& ]" W* M7 l/ _# b" { - HAL_RTC_SetDate(&hrtc, (RTC_DateTypeDef *)&time->WeekDay, RTC_FORMAT_BIN);+ W/ q/ l. \. J, q! s6 R, b' y
- }
复制代码 8 v! [# Q5 N. y
覆写闹钟时间回调函数:
" O. L3 ?( N# j; F; l% Z
! F3 L7 h3 l. T, ]/ s闹钟事件的中断设置,要看MCU支持的是秒中断还是时间中断,比如10X系列,要通过当前时间去设置下一次闹钟,而40X系列的可以直接设置时间。
7 W$ ^% L2 J. O8 y; T5 B# ? n' |6 }4 R! i( s: w
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc): q0 ~0 E$ A; b. h+ i m
- {
, Y' L- _% }- } - RTC_AlarmTypeDef sAlarm = {0};
& j4 a5 h! _/ V: b5 ~5 z: T - rtc_time_t tim = {0};; d5 G; N5 l0 I
, J. A \3 O+ n4 A% l) C& H# Q- // 获取当前时间
/ n6 I2 p; L9 v% r4 I1 z - RTC_GetTime(&tim);- n! {# S, D" w$ s
9 T' y$ V: k5 s. u4 F% J- sAlarm.AlarmTime.Hours = tim.Hours;
" j( G! O6 y: n. Q - sAlarm.AlarmTime.Minutes = tim.Minutes;" `# D. a& J' A! _9 G" @
- sAlarm.AlarmTime.Seconds = tim.Seconds + 3; /* 设置下次闹钟提醒时间是当前时间的3s之后 */
+ I4 G% q0 I" s' i B9 x - sAlarm.Alarm = RTC_ALARM_A;+ D+ q' A7 ~% w; @8 l. I
-
1 k1 u% m1 G# R0 z& I8 i2 h - // 再次启动闹钟中断事件
6 b- V( B" C( |$ p - if (HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
; Q1 M' E% y( d/ n5 K- G - {
- [7 ~8 g/ o' a0 H - Error_Handler();5 D4 S8 N0 e, w" L2 ~
- }
- M; \7 U! @4 ^5 l& H - / P9 I. V0 B6 e- D, ]- T$ q
- printf("HAL_RTC_AlarmAEventCallback\r\n");
$ m/ Z+ j9 ^: U/ G* p( I0 w/ ? - }
复制代码 " _5 K. J. V& P5 i! w
main函数:6 d% k, r- @3 f
3 N: R/ H/ V' w$ J& I& u
- int main(void)1 a% U$ q& {0 O1 k
- {
; c- k0 j! `0 i, V9 [ - rtc_time_t tim = {0};
# F. l8 f* z7 s% i$ Y+ N; X' v - ! L$ b, ?, o% [, ?. r {( ^4 M
- HAL_Init();
( k" I# I# |" h* y. ]: S9 [ - SystemClock_Config();5 [ A+ m5 t0 H
- MX_GPIO_Init();
7 k% G+ ?0 G6 B c - MX_USART1_UART_Init();' A0 K% N( _, A7 p9 `
- MX_RTC_Init();
; x3 V2 t @' G% e/ q+ c8 H
: B7 w0 c& f$ L; p* R5 n1 u7 m6 [- while (1)
# D& I2 v4 n" m# X* V - {8 o. V1 a& e0 R$ R2 I
- HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);( n2 S& Y' j, \% }& ]3 \
- RTC_GetTime(&tim);
5 A6 N( q% @4 h' }6 ]5 O; X+ i - printf("%02d/%02d/%02d %02d:%02d:%02d %d\r\n", tim.Year, tim.Month, tim.Day, tim.Hours, tim.Minutes, tim.Seconds, tim.WeekDay);" V5 v) J( n% x" a5 ]! L- e/ T
- HAL_Delay(1000);) s q5 w1 \" F c! T% W
- }, `$ \, _. ~2 ~
- }
复制代码 ^% ?2 J1 v; V
(三)运行效果5 t5 \: z. b J$ N, U! r
- c4 [' H+ g% r, i/ G3 `. \$ _/ U6 j
?" ^9 U" e" _" ]
5 W: h1 G J. q; S! `5 L0 O! E& \( Z) R# ]* e
5 n2 u1 l; E f" x |