(一)工程配置
, J; N1 r0 r( M/ R! H; h! g; K我使用STM32F103RB这一款MCU,首先使用STM32CUBEMX创建工程,配置主时钟和RTC时钟,我板子上是使用的外部的32.768K晶振供RTC:
0 e3 } V% C1 Q' r& P% i, u, h
5 o1 v; H" F/ Q
0 [. h: }, F, H# N& [
5 m+ v p0 I/ f% S- D% E
$ U* m. l! O B6 n3 F) g配置了两个LED灯:
% a3 |+ U! Z( m$ Q+ o/ g; C( ^
% C! a, A/ @' B' u, ^. m- N
0 S) Z1 X; z: w
. |! f4 p7 {5 d/ o: {配置调试下载接口为SWD(此步骤如果不配置,你使用stlink的话下载一次程序之后就再次下载就会找不到MCU):
, [7 P O6 m/ R' O s$ L2 v6 N) R V
}" ]) z6 M5 K. v9 p5 E1 s
( R3 Q; C' L' b( l( P& ~
' @1 s; K0 M. |配置串口1:3 f2 ~2 W5 |$ c- N% J- ~* B: R+ q
0 H: e& A0 R3 h ]& @& t* o0 V
7 C8 G1 f9 q. M+ X! R
' m" J/ z9 p# r) e配置RTC时钟,激活日历和时钟源,这里我设置时间为2020年12月25日0点0分0秒,设置闹钟提醒的时间为3s:' L. W$ `; h9 ?% R* R
! ?5 S' i% d4 c- Q6 Q
+ R- T1 q \% u7 l, X& C& P2 k8 g2 W1 u7 D5 y" \3 J
使能RTC闹钟提醒功能的中断:
6 H& S$ o t1 f+ N' I: g
( @$ ~, M- V- ~8 e; _
4 U5 w% Z4 F) Q( x
2 U& L8 o$ q' X1 [) \5 D2 T其他工程设置:0 Y! X8 c2 c: W
, x- J" L: `2 U$ z. @& t/ Z
: w* C* G2 L( d5 [! m) v6 d4 Q
3 K0 k2 m; b. q, z
然后生成工程就可以了。
4 W' A- _' P& j7 E
" ^/ t, `9 E6 Z3 d" b. B$ E" p8 L(二)代码编写
% @) r' d9 x$ z4 z5 z! R m重定向printf函数:
# r% j/ ^" e. i$ f+ @; z8 y1 O" r7 P) w9 @& D1 Q0 q- P8 s9 \
- int fputc(int ch, FILE* fp)
; t8 D; `/ u' m- J; h0 V) x- D( S$ a - {
# K+ m1 O) V9 w5 G: | - while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) != SET);. t2 L( o% V! z
- huart1.Instance->DR = ch & 0XFF;
& E. h: C" f/ R3 l- z3 w+ M! } - return ch;& u3 @8 E, C2 s5 i, x6 ?
- }
复制代码
Y- i/ [6 ?- ~( R" b1 U, R/ I: @! ~HAL库获取RTC时间的函数有两个:% n: d' W+ W8 {3 C
HAL_RTC_GetTime:获取时间
3 u S r- W1 Y" vHAL_RTC_GetDate:获取日期# z4 e0 G0 g* }/ b/ `! y$ s, I, t
1 r V- a; y8 e/ o这两个函数的第三个参数是格式:RTC_FORMAT_BIN和RTC_FORMAT_BCD,BIN格式就是十六进制数值直接表示的时间数值,BCD格式就是用数值的十六进制面值表示时间数值,例如表示第24分钟的时候,BCD格式的分钟值就是0X24。3 _& r' Q ~/ h- M C7 p
/ p- w9 v. L2 r9 I* U
注意: 这两个函数调用是有先后顺序的,必须先调用HAL_RTC_GetTime然后在调用HAL_RTC_GetDate。- L: m, w& u) C4 G1 n/ X
2 L* ^0 Q7 A! {% i2 ?
可以通过以下两个函数设置时间:
% s( k6 z' I0 S! Q& R" @HAL_RTC_SetTime" }5 a+ V3 l$ y% h8 w: J' e
HAL_RTC_SetDate
+ g3 P) r( t7 d$ S+ ]$ t% G+ ^
+ i9 k6 d! R, q1 f- [1 n! F这里我简单的把时间设置的函数做了个封装:! q8 C% ~0 |, B5 g0 }7 b
' v; w7 g+ u3 {' Q9 d* N$ h
- #pragma pack(1)+ I8 c2 a5 v- Q# q: @1 q
- typedef struct6 N8 t4 M- q- K2 \ X f
- {" h4 o: ]9 V' g/ q
- uint8_t Hours;; q% I- ?" `4 a" t7 k" `6 y
- uint8_t Minutes;5 m& `& J! T8 {7 |+ d/ I
- uint8_t Seconds;/ T, Y% ~% I5 w) d
- uint8_t WeekDay;- G% Q" R' J1 i) w) A
- uint8_t Month;
/ h4 x5 r7 Z( u6 F0 z- \/ U - uint8_t Day;
# I- |% z) L3 V2 N - uint8_t Year;3 d1 }1 |7 j. b' q/ R( y1 _% I4 T3 d
- } rtc_time_t;
0 @( Q7 d& A' s; L1 P$ E7 X7 W - #pragma pack()
: |; e- o. [1 M - 8 e0 u+ _2 C) L: d
- 3 z2 q; w5 F. A4 x# C9 k! w
- void RTC_GetTime(rtc_time_t* time)
# U3 T3 z F) e - {0 l- _8 A+ ~. ~4 \
- HAL_RTC_GetTime(&hrtc, (RTC_TimeTypeDef *)&time->Hours, RTC_FORMAT_BIN);
. A* \3 I3 ~+ \- U9 t5 S - HAL_RTC_GetDate(&hrtc, (RTC_DateTypeDef *)&time->WeekDay, RTC_FORMAT_BIN);8 P m, Z' w, I0 {2 y
- }: M' E! O. [) t- ?
- . C# g7 v4 h# r3 R/ P
- void RTC_SetTime(rtc_time_t* time)
( _8 ?+ Z+ i) `$ G$ L- A: Q, A - {6 z# L6 @( G: v1 Y
- HAL_RTC_SetTime(&hrtc, (RTC_TimeTypeDef *)&time->Hours, RTC_FORMAT_BIN);
3 h$ b% s I' V; z' D( Y - HAL_RTC_SetDate(&hrtc, (RTC_DateTypeDef *)&time->WeekDay, RTC_FORMAT_BIN);
( R( L6 F5 k5 n0 M# O - }
复制代码
" O2 G. w1 j# |3 U覆写闹钟时间回调函数:# `; \0 K' k8 z; B" M' F" S/ l c" W
* X+ B0 k0 c& W5 N' u
闹钟事件的中断设置,要看MCU支持的是秒中断还是时间中断,比如10X系列,要通过当前时间去设置下一次闹钟,而40X系列的可以直接设置时间。
+ u* y- O& ^) L+ B. p
: b }0 m9 K* {& o- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc). f! R. u) M; c% L3 I: \0 J' f+ w
- {
) q* N% Z9 k N9 ]7 T - RTC_AlarmTypeDef sAlarm = {0};
, N3 ~6 b& F9 T1 @# y - rtc_time_t tim = {0};
0 N# V2 Y2 B7 E" ?/ C0 x - # h [' [/ T+ z
- // 获取当前时间, Q( Q3 s: g) q( h3 `9 W X
- RTC_GetTime(&tim);
* o, C/ l6 R0 \$ |, q9 C: H& c
9 L- P" M% T# p- sAlarm.AlarmTime.Hours = tim.Hours;8 z+ m# y( m# ~, Q# j
- sAlarm.AlarmTime.Minutes = tim.Minutes;
: A" c h( }% _+ R( } - sAlarm.AlarmTime.Seconds = tim.Seconds + 3; /* 设置下次闹钟提醒时间是当前时间的3s之后 */0 o0 f1 e8 d. K0 a# _
- sAlarm.Alarm = RTC_ALARM_A;. C9 n, o$ N. G0 Y9 |6 k2 U
-
4 k8 a1 o# B6 F* r& f5 ]: [ - // 再次启动闹钟中断事件/ k6 E; B7 N) s2 g
- if (HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
& @, ^ K! I2 G! e! @7 H) h7 [8 F - {6 T$ Q) I# X! ~# r
- Error_Handler();+ N/ a1 u6 o+ V$ ]2 l6 o7 Q
- }
: A: o! h! ^% z% g - - f! w) g. \$ }$ m6 Z2 P
- printf("HAL_RTC_AlarmAEventCallback\r\n");$ L! h% z2 r% X3 T7 m
- }
复制代码 2 B+ ]; K% }2 q0 X! c" ]0 B
main函数:
$ g$ [* T9 W+ I4 ^. ?8 u8 i+ z B" W. f
- int main(void)
3 v) B1 R" v! p5 P - {
0 h+ r; t/ g$ j* s$ g. a- R - rtc_time_t tim = {0};
2 E: u: e7 B$ T+ f - ) W0 ^, P0 W$ s. C& Q3 l5 b$ B
- HAL_Init();
Y/ J7 q" r3 Y5 ^4 U3 A9 H8 p - SystemClock_Config();' s, v! N9 h( U$ L
- MX_GPIO_Init();8 R3 `; S' Z: d" d2 y
- MX_USART1_UART_Init();) h2 h# o K& T, Z
- MX_RTC_Init();
1 E. j( O. {* a5 g3 W - , ]9 J: C: `- C O& M6 I3 c
- while (1)& w$ _# k. q7 u2 A) G; k
- {0 i+ g s1 z2 [
- HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);. R T/ x8 I6 g) N p2 C" |
- RTC_GetTime(&tim);
# U; v, M: h* O% s$ q - printf("%02d/%02d/%02d %02d:%02d:%02d %d\r\n", tim.Year, tim.Month, tim.Day, tim.Hours, tim.Minutes, tim.Seconds, tim.WeekDay);: B: C- C# n7 n+ Y
- HAL_Delay(1000);
* r$ |0 J8 i; F% g. E$ P - }% C0 I* `" R! n7 B9 Y8 \* Z
- }
复制代码 3 t1 W L, [5 c2 [9 `6 X+ _
(三)运行效果1 W ]; `. v/ l, X. h5 ^( h
1 d. T/ D- }$ w- X4 i
3 X1 k F: Q6 Z Q; d/ h0 b) B( f
2 m. C( K" G8 D9 @3 R
7 m% S; ?- l. t/ b
* a" ^6 D% g& Y8 l, l, ~8 |; s
|