两天的调试与查阅资料终于明白了HAL库中的低功耗模式的切换和退出。主要还是自己作死选择了STM32G071,本文内容基于NUCLEO-G071RB,CUBEMX版本5.2.0,STM32Cube FW_G0 V1.2.0,MDK 5.27.1.0。$ y: U5 |4 W$ j. V: K: `- D* y+ F0 G
0 G& a. I- z7 @; P' V l首先配置时钟、UART、RTC和中断。
" T! p, ]( k5 r o. S; C
7 P: k# `" T, b7 u, W: J( U% I* l, t6 ~3 g; ]8 z% m) }( F
6 Y. H& L# `5 C) p" ERCC选择外部晶振(shutdown 模式只能使用外部晶振)其他默认
# L( ]8 a2 ?& v- E- s5 s2 c3 H! x! a
3 J% r' P% O+ M1 p7 s* b' ?' ?
( Y6 w% n, r# c+ o* I! M
SYS选择调试接口,和wakeup_pin2,STM32G0目前新线还是很多资源的: n' s. t7 W5 V/ U" j' n$ ]% |/ N
# T+ v' p' _1 e
* [2 H, ~6 \/ i6 H. s- Z! I
J; x3 ^% O1 l% P
设置RTC,填写相关初始化信息、开启ALARMA时间设定为开机后30秒,注意RTC_AlarmMask=RTC_AlarmMask_None;则为精确匹配,即闹钟不仅要求时分秒匹配还要匹配日期和星期,都匹配后触发闹钟中断)
! l8 y1 ?' @$ `7 ?8 P" e# j3 _# M& ]0 P5 T/ N+ d7 q( s0 T
0 A1 n: v& [' W7 X3 F a& v% J+ R% T. X7 ^. J
设置串口/ X& @3 ~- R4 L( f/ I
1 K/ {, t5 C; P" g s1 ]
4 A' h2 I5 T$ e. ]
7 x, Y" w& N, x6 W. R打开中断入口+ L; A8 r1 b+ o2 F; u n- c1 v q
, D$ |+ P# D( P& y6 ^4 l3 [: {& p6 M5 y2 q0 u5 B
% ]8 g6 j, o" k- K, \
+ e3 G2 k4 z% V5 Q2 o4 M- _
* E1 `7 G0 w U
完成设置后点击生成代码创建工程0 Q$ \: d) h' E4 t; Z# q
4 a6 k* V% u! b8 g. T" i1.首先喜闻乐见的printf函数
1 w8 @6 [* z: ~- /* USER CODE BEGIN Includes */
: P V. w! O7 V9 B. K0 j7 s - #include "stdio.h". G0 V. Q( r. Y+ G8 m; _
- /* USER CODE END Includes */: l* }$ n# c- @+ U; I$ d
) ~ [4 a Z3 z- 3 G6 M r9 L- O8 O8 I0 Q% J$ b
- 1 [8 B6 v( ?1 H& ]+ g' b7 E& C. |8 l7 T
- #ifdef __GNUC__/ f0 x# O+ M, k- l K
- /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
; J% i' B5 |# J* P5 t - set to 'Yes') calls __io_putchar() */' {* v+ U0 l& |
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)" Z( o) o7 X6 w. |& q/ ~7 V3 d
- #else
/ ^$ g9 I9 G; n" f& | v! K1 j - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f). L, i6 S) r o
- #endif /* __GNUC__ */, u- M# [4 E$ ~8 _* Q5 o; Z
- PUTCHAR_PROTOTYPE% q3 { r, I o" E" ?/ G6 _+ d
- {9 N9 V, ?+ g. m
- /* Place your implementation of fputc here */
0 Z2 z' ?4 F% g4 J1 I6 x4 C6 ~ - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
2 y! u/ o, }% u& d9 } - $ u4 k S0 F9 `1 k% Y' i f
- HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
" D2 C; Z9 O: r1 j1 N5 ^" G/ z$ y% [% p; D - . u* r' z* a. O# Z6 }
- return ch;
8 }" _( r# X d5 ` - }
复制代码 $ W9 W( W8 l: ]. \4 q6 K4 S# H
2.RTC时间获取函数! p' l# Q; l" ~& ]0 L
. Y& P# N5 w5 n, g& U t& X: t
- /* USER CODE BEGIN PTD */
6 O1 D8 S7 i6 y# H3 @* P: U - RTC_DateTypeDef sdatestructureget;7 m' q" r1 g# H
- RTC_TimeTypeDef stimestructureget;
0 l4 o# q/ b( E7 A6 {$ W - uint8_t aShowTime[16] = "hh:ms:ss";
( ]% `* d( k( o j2 Y, x - /* USER CODE END PTD */; ^/ [4 C" g' N
, n5 Z* v) V1 [6 }8 O! G: y9 ]- /* USER CODE BEGIN PD */0 _2 C- A2 K5 |% J' f# q# V
- static void RTC_TimeShow(uint8_t *showtime);% f3 }1 I% `3 B* N
- /* USER CODE END PD */
H& r! ? Y( D5 M - + Q/ R. W6 [; i+ J5 c
- % Z# }6 E& [/ b% y$ r `3 v) f i4 `
- static void RTC_TimeShow(uint8_t *showtime): f( T* P) ? Z5 e2 G5 A
- {
: |' r9 K3 w% y$ \
; X3 \+ Y8 ^2 j! O# Q& U- R
1 r& ^0 K7 J+ ?# k! ~2 b- /* Get the RTC current Time */9 K3 F% ^! X( ]7 s# ?2 o X) q7 ?9 b
- HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);
4 `: ]1 _- H; K& u1 r D- h - /* Get the RTC current Date */
6 ]- C/ |4 J5 j4 d! w" | - HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);8 v% ~" o3 C) I1 D
- /* Display time Format : hh:mm:ss */
- g: j0 X( I. E- z0 \, o0 F - sprintf((char *)showtime, "%02d:%02d:%02d", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);" F2 F5 @$ q" v6 ]1 d
- }
复制代码 ' ~) q# M! e9 X- u6 U
3.standby进入函数
% V2 R5 E4 I. S- /* USER CODE BEGIN PD */& A/ k) p! k+ B' s
- void Sys_Enter_Standby(void);
& F7 Y i* s4 j1 e - /* USER CODE END PD */
4 d2 v; @ [6 o; }( M$ D. M
% P2 ?% A6 z( e/ O- void Sys_Enter_Standby(void)% R; Q o* L6 |. W% r
- {
$ T* g+ R6 g" ?' a - /* The Following Wakeup sequence is highly recommended prior to Standby mode entry
9 W" M9 p6 A& H( D6 t, D - - Enable wakeup9 d9 M1 B9 a: E7 A0 }
- - Clear wake up pin flag depending in edge detection & pin level. t$ O9 Z* Q1 ?
- - Enter the Standby mode.1 u4 x5 s2 [: w! h; G: h
- */5 h7 n% y) M$ K5 ~
- ( x" h$ n9 w5 X8 l+ z3 ^1 i
- /* Enable WakeUp Pin PWR_WAKEUP_PIN2 connected to PC.13 */
x/ ]8 Q7 d J/ E - HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_LOW);//上升沿触发# @6 G. k; `! F) e
- HAL_PWREx_EnableInternalWakeUpLine();3 z9 R" t( D8 c2 \
- /* Clear all related wakeup flags*/
$ j9 R, t9 _- p; k! b1 ` - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);. b$ U! P# u( H
- ( g" u; l4 ~; C
- /* Enter the Standby mode */# _: q8 i% M7 N! k1 Z, b/ ~
- //HAL_PWR_EnterSTANDBYMode();) z, n4 a! z+ ]+ }# {! n
- printf("enter Shutdown Mode!");% a1 J* t j# X t/ W2 M _1 n
- HAL_PWREx_EnterSHUTDOWNMode();! ~! O% e; O* z1 `
1 K" |& D# S* w+ ?: j/ g, W- /* This code will never be reached! */
7 ?% L- d) O. D3 Q - }
复制代码 ; f% b# o7 P# ^& J( ]* `9 E. o
4.ALarmA中断回调函数 NVIC_SystemReset()用于standby触发AlarmA时间后与wake_pin触发系统自复位不同进入rtc中断后无法复位问题(我解决不了就软复位)6 u" F( E4 ^9 t4 D$ F! G
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
( T4 [- j! E- u: K e# ^9 ]( G - {9 M; P2 i- }; l8 ^
- /* Prevent unused argument(s) compilation warning */* b/ Q/ H% p, L7 N L
- UNUSED(hrtc);/ T- A- O' q" f6 w. h# T4 \
e. ^: o4 X* I @- /* NOTE : This function should not be modified, when the callback is needed,) K9 R# j0 e0 `: Y
- the HAL_RTC_AlarmAEventCallback could be implemented in the user file1 z4 J/ d) |. w! m5 J/ m9 ?! R
- */+ d6 @7 _ p" j7 _6 }! p
/ H6 E$ T! {/ v- V% m- flag =1;5 w8 s% a5 `, Z7 s6 N( l$ a: Z: t
- // NVIC_SystemReset();
! ^7 x* W% B. U3 p5 r9 v - 6 E& A' G# m$ H/ \! p8 {
- }
复制代码
1 B" L$ }: E+ R2 a& e9 R 5.在main函数中5秒的时候进入低功耗模式1 Q# m8 M1 w. u: z) O+ x
- /* USER CODE BEGIN 2 */( s' m7 x( F8 L1 e+ {+ @/ Z
- uint8_t sec=0; N( [9 a* |: j3 y4 g4 Q% S2 b
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)% w- G; {5 ^+ |# Y3 ?" a) F
- {
# Q3 p) N6 H Z, _1 T - /* Clear Standby flag */; K7 B- R/ n+ F! w: ~
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
( R# K# L2 j. L' `. J# I, ~ - printf("wake up from standby!");
2 j- b8 ]/ b" L - /* Check and Clear the Wakeup flag */3 V- u' k( d2 i4 O/ M
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_WUF2) != RESET)1 P8 x Q- `* G; G Q8 g
- {# z- N2 E% G# r. l- J$ f; l
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);, @. W) E+ I, v* [& Z6 b& L
- }
! U' \" Q: _% h5 ~! x N" M9 n - + D: u" ^( L7 a1 }6 [1 G7 y( W
- /* Wait that user release the User push-button */7 b1 ^. t ?: l2 X
- while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET){}
: O# N* l) s! t( V3 x - 2 z N0 _; q$ H7 R" _
- }
$ I& ]" ]7 }4 { A/ }5 }
: l- g4 K8 u9 ^" F" q' c( U* N1 E
$ w$ B2 {: P) A$ k+ o- /* USER CODE END 2 */7 k7 g: l6 s3 t0 G q. K
- * Z& x( Y! ]1 n
- /* Infinite loop */
% ^0 |# S7 N. l - /* USER CODE BEGIN WHILE */
7 R) ?- v w: Q0 Q' i# f" [ - while (1)! `5 Y( B& k* v6 D: |
- {; B& x' M1 d* D1 T. t7 l
- /* USER CODE END WHILE */
7 e0 F" F5 |$ k) M. Y5 H
6 i: v# p# F X3 |& ^, w- /* USER CODE BEGIN 3 */
. X/ ?" C' ~3 i$ z9 j$ y/ T - RTC_TimeShow(aShowTime);& R0 y. N a H+ J
- if(sec == 0)flag=0;
7 t) p. {' T5 g) L2 v$ T - ; i4 h6 B, M( f' c! w
- if(sec == 5)Sys_Enter_Standby();+ O* r6 s- p4 `# E- P' F# O
- if(sec!=stimestructureget.Seconds)1 f9 h. R' w5 h! h0 h8 q
- {5 j6 F3 F+ Y4 W* V7 c
- sec=stimestructureget.Seconds;: ^+ W1 x. Y. z+ n
- printf("%s",(char *)aShowTime);
8 ?0 ?5 r- X$ P9 ] - if(flag) HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);4 B( Y" L9 F4 E* i3 u7 U2 u: w
- }$ N0 f; k6 G2 S% d, Y( O" r
- }
5 W0 Z. l" h# ~( @ - /* USER CODE END 3 */
4 K" F4 M$ L: v% b - }
复制代码 3 e# t4 G1 q/ g3 L: K0 p5 K
至此STM32G071关于低功耗模式的进入与退出已经可以实际使用,大家可以参考,实际使用稍作调整。
! A2 I: ~! l0 w% G4 d7 [
7 Z$ q- K! W) ]7 x6 v附加 避免上电自动配置RTC时钟
& M. D2 B% X- Q% T+ H; R" p2 m- /* USER CODE BEGIN Check_RTC_BKUP */* X, y7 [" i4 l2 K2 Q) c
- if (__HAL_RTC_GET_FLAG(&hrtc, RTC_FLAG_INITS) == 0x00u){}
+ A9 J- G7 J( Q, T! o+ E( b6 } - else{return;}
$ j! |0 z* B p% i ?+ o - /* USER CODE END Check_RTC_BKUP */
复制代码
$ q$ t# g; \, u4 B9 f4 E( b以上代码请添加于MX_RTC_Init(void)中, p& w4 F* X( {: q \9 d
+ i0 e# V( l- ?- Z
1 o5 S7 i/ V% }/ k3 |6 {+ \6 a, {
% b& e# I% F' l: z4 L/ H项目文件
% h* w. s7 `- P' ]7 V
* b* |* H& ]# p- r/ ^% W
: M7 k+ s* e e: O( E: _
. U% c7 {* l+ z
4 U }: {. A, g8 D$ c& T6 W |