两天的调试与查阅资料终于明白了HAL库中的低功耗模式的切换和退出。主要还是自己作死选择了STM32G071,本文内容基于NUCLEO-G071RB,CUBEMX版本5.2.0,STM32Cube FW_G0 V1.2.0,MDK 5.27.1.0。
8 p" l1 H; H4 n* \4 }0 q5 Q0 s' s9 @( }- G% A, |
首先配置时钟、UART、RTC和中断。5 N3 c& B, J4 M# B$ l/ v
& M( P; w: l+ k& T% F* C: ]
# s' C/ f; {6 U2 F( R3 Q: T3 J
3 G& J0 _5 `: |; E- M3 S/ C7 DRCC选择外部晶振(shutdown 模式只能使用外部晶振)其他默认
0 P3 v4 g, Y: P6 o8 `9 \. ]3 m& q* u* h
) O3 j& I& r+ y% ^3 p
/ [8 F$ M D$ A# c7 F# \% y
SYS选择调试接口,和wakeup_pin2,STM32G0目前新线还是很多资源的
, v- ~# i n; [& t2 e a( E& M6 t3 s2 d- L8 N6 I# Y
# E, ]/ s% ~# f( }
+ n. g2 A: u* g0 N8 l8 |0 r8 O! y
设置RTC,填写相关初始化信息、开启ALARMA时间设定为开机后30秒,注意RTC_AlarmMask=RTC_AlarmMask_None;则为精确匹配,即闹钟不仅要求时分秒匹配还要匹配日期和星期,都匹配后触发闹钟中断)4 x/ E* C+ `% L; V
: Q) w" h4 X3 g& u# P, l4 Q$ r0 u l* ^ ]
4 {! J" x6 {$ U8 \设置串口, t% o) K! P5 I+ V- s
7 ]. W5 a! L1 H) t1 i. I
7 w6 q, Q) K$ i$ c4 Z5 N
3 R' U f& q; T3 v打开中断入口7 e4 ~9 u$ J+ X4 G& k6 i# X/ h
7 _8 J' m. f9 `3 R p, C. y
* l4 E6 S( T9 V/ o1 b; ~: Q8 z$ {7 y/ o* C. N; F! Y4 w
: m$ j2 p# ~. Q: E& M+ p& v$ ^
; B& |. s- N8 j. |* E$ O
完成设置后点击生成代码创建工程; m9 h; P( o- H
* P8 K6 l: n. z/ p+ y( A3 Z2 Z1.首先喜闻乐见的printf函数
; V6 P3 e1 |6 |7 `( R. I- /* USER CODE BEGIN Includes */9 G6 ]) q& |2 t$ Z+ q+ W
- #include "stdio.h"
( ^/ `0 U6 x2 A6 w# O) f - /* USER CODE END Includes */, A4 g: s- R# _* k1 W4 b: S
7 h o& u9 _3 n7 q2 T- ! ~: {8 M! T) J! L
- : O) _# `& j9 N4 k
- #ifdef __GNUC__
: O5 i* Q ~: I8 J4 h ] - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf' F P/ q$ c' w8 C+ `1 n( L0 k6 X, r+ }
- set to 'Yes') calls __io_putchar() */
3 W1 H$ b! k4 X5 J - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
_) G! O2 _& t3 a: w: u' H$ G - #else
- F; t6 c0 h( F* d8 b2 z - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
4 ^6 H0 }! _& d7 w) j - #endif /* __GNUC__ */
' ^3 k1 Q3 }! G9 ]: O/ ^+ z- x - PUTCHAR_PROTOTYPE4 y0 x. u# [. p
- {: F) _7 z9 ^0 o. s! l
- /* Place your implementation of fputc here */
8 R. O# Z ~0 Q+ J+ x/ m - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */: x W" L, i/ ?$ H! l. f
Q# }& h, M9 D- HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
& o" T2 T1 d! P2 z5 w) r9 ? -
2 {+ z, @0 z% d$ X1 L" F* c - return ch;5 A/ a" O2 Y& x! V: i+ |
- }
复制代码
! e0 `& d* {' y1 g6 y! K; U2.RTC时间获取函数8 ?# {9 Z4 |) Q" f4 I% ]
0 D+ ?! }/ v' ]# O. O
- /* USER CODE BEGIN PTD */
x" r8 j( w! B) A* c4 l5 J- n8 o5 c. { - RTC_DateTypeDef sdatestructureget;* o [8 g; |: x* S' H2 W4 e
- RTC_TimeTypeDef stimestructureget;
) G9 P9 S8 f! S( k" i$ f - uint8_t aShowTime[16] = "hh:ms:ss";* K# U5 t/ `. w; n" z. R: w! t6 W
- /* USER CODE END PTD *// c1 V8 I$ N! s% g1 j
- ; `9 d) P6 Y' H' @) `% I) M I( v+ b0 n
- /* USER CODE BEGIN PD */
6 c+ ~# h3 k- y- E0 K/ a0 r: } - static void RTC_TimeShow(uint8_t *showtime);
* |& P8 ?$ i) C, ^. v" I: F5 p2 ? - /* USER CODE END PD */
8 p8 e% U, h$ M
& I. L7 w0 g" q6 W& i- , Z) s; d) l( s" I t: g2 t
- static void RTC_TimeShow(uint8_t *showtime)
: t( z; V- T* \ - {, U& U& W/ u& ]* D' H2 O
- 6 t) X- Z$ [" c# B5 J$ _* d
. ^ k6 H, R, m2 j; B; R! l' F- /* Get the RTC current Time */
0 ~5 |8 T" `7 f9 q6 O- Q8 s - HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);* t% V" v; Q. h- O$ F( ^2 R' @
- /* Get the RTC current Date */9 a8 \% g# c) E2 N
- HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);" A8 y, y1 b5 m
- /* Display time Format : hh:mm:ss */
( X- T' `6 p9 N% A) v - sprintf((char *)showtime, "%02d:%02d:%02d", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);
) T4 p# ?8 e! q% m* e - }
复制代码
) T3 @8 e( i/ O h3.standby进入函数: h' x0 l( B# B- ^) U
- /* USER CODE BEGIN PD */6 [) B& l( p& d0 R( I# M
- void Sys_Enter_Standby(void);
* H, h; @ _1 ^. _ - /* USER CODE END PD */% E; i2 W, j# o8 b. x# k# c6 b( s
6 i; C- C7 I& v# G) L- void Sys_Enter_Standby(void) ]& @9 g+ F5 i. K% i5 h9 N
- {
: a0 _* c% J4 B - /* The Following Wakeup sequence is highly recommended prior to Standby mode entry
: H$ D3 Y" {" h" x0 [7 Q - - Enable wakeup4 V P* A2 f# p% s7 q* O. v% M: M s
- - Clear wake up pin flag depending in edge detection & pin level.
0 \1 L2 x/ G! i N% [* J2 M - - Enter the Standby mode.# b5 P% {. Z) k5 t8 P
- */
' ?/ j0 s) w; d# u2 C - - k& k1 s" |# X* ]
- /* Enable WakeUp Pin PWR_WAKEUP_PIN2 connected to PC.13 */
' D; d- j- n( ?6 C. O* b3 V$ k - HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_LOW);//上升沿触发8 b; |0 O" x' d$ F6 Y: N
- HAL_PWREx_EnableInternalWakeUpLine();
9 G/ p' Z8 L4 c7 z - /* Clear all related wakeup flags*/" o, ]6 d! B& t3 k
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);
0 y; C) q) ?, P6 m
C- I* e8 r6 ?: | b9 B; k; E- /* Enter the Standby mode */
' r2 n- `& Y. n - //HAL_PWR_EnterSTANDBYMode();# b& F4 u! |# X) i& [7 L
- printf("enter Shutdown Mode!");. X2 Q" |% @4 y6 v4 a1 t" B8 q
- HAL_PWREx_EnterSHUTDOWNMode();0 Z8 n/ \1 Q% R5 B3 i7 ?* U: B
- ! |3 T0 ~0 J+ M( q% V5 H
- /* This code will never be reached! */3 F: P6 [- e/ J, D
- }
复制代码
- m9 I3 N. n U2 `, @4.ALarmA中断回调函数 NVIC_SystemReset()用于standby触发AlarmA时间后与wake_pin触发系统自复位不同进入rtc中断后无法复位问题(我解决不了就软复位). }, x/ [6 g( R p
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)( R4 n) n( x8 }. R/ f+ b: o
- {- v f) o* u x: x% i$ y
- /* Prevent unused argument(s) compilation warning */7 Q" @# U' u' n3 E
- UNUSED(hrtc);
; c3 C: J! ]! E! | O
0 S- E5 n) L& ]0 Y- /* NOTE : This function should not be modified, when the callback is needed,
! G4 @0 l! r/ x. o5 _; ~ - the HAL_RTC_AlarmAEventCallback could be implemented in the user file* z% D) L' p; k& n: H, k# x
- */
) ?. c1 e& S; ]' N" m7 S0 A
& E% K7 A5 G4 b {- S- flag =1;
5 x) @+ B, l6 Y: U% a - // NVIC_SystemReset();3 m' n. j4 m3 D3 S3 a" R5 n
- : ~; A7 o4 Y7 h4 O3 z
- }
复制代码
* }, r: \; w/ I7 K8 d 5.在main函数中5秒的时候进入低功耗模式
9 U) f. q, m# E0 i- /* USER CODE BEGIN 2 */1 p1 R) S2 c$ w
- uint8_t sec=0;8 l2 z" ?' @/ v% o
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)( }4 V0 z- e; X, R1 q, P% z
- {
3 A5 d' H, t6 E: a' a - /* Clear Standby flag */
; m* Q2 M1 T' H9 @! g - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);. z' I+ o% D0 L: Z
- printf("wake up from standby!");
4 g5 ?, j1 B- |, c - /* Check and Clear the Wakeup flag */
G+ o+ e X* H* X3 D1 c7 A5 P - if (__HAL_PWR_GET_FLAG(PWR_FLAG_WUF2) != RESET)3 g- e2 y# p7 u$ a" c: k9 e8 s, I
- {
9 K) n1 R7 ^8 G# F- M" P0 J - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);
5 J* A" v" ]% O" l2 d' f: S! F& W - }# H! U- A' R) q$ u2 D
-
, Q1 a: {; P5 x7 A) M0 {$ D - /* Wait that user release the User push-button */9 O+ s% i- \0 R
- while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET){}" K! ~. d P2 S7 O
- % r( \1 w% ?2 F9 ?' @
- }
# W1 p! |" K% e C* K4 q - ; A# F! ~* _' l( }. z- `2 [' M
v* Z1 Z5 m3 v- /* USER CODE END 2 */# K/ S# s2 E$ n
) j; V, F; C5 `1 }: W) M0 ^- /* Infinite loop */ L6 j" d# p) }) D5 {9 v
- /* USER CODE BEGIN WHILE */
) k# \1 W' P- Q) ~$ L" ] - while (1)% W: o0 H% ^1 j% s& b- H1 N, }( {
- {
% l$ ]8 R# c& g3 L8 E - /* USER CODE END WHILE */+ l9 @; Z' L3 v5 x0 z
- 7 s! |: n/ @7 b U% P6 v
- /* USER CODE BEGIN 3 */
8 c. Q5 h0 G3 _; w - RTC_TimeShow(aShowTime);
; d2 Y! i2 E. A - if(sec == 0)flag=0;
. G4 L2 _ S: d9 L/ q( f) Q8 H - ! x% \$ m2 O& U5 T2 m
- if(sec == 5)Sys_Enter_Standby();% B# |( |5 n8 n
- if(sec!=stimestructureget.Seconds)
/ e0 y5 h4 P- {5 @: N9 E - {
8 ]4 c4 z6 T5 r, \ - sec=stimestructureget.Seconds;$ P$ H. F$ K) e9 w) w
- printf("%s",(char *)aShowTime);: u, z6 P$ G3 L( H [
- if(flag) HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);% U6 t0 O! M: g1 ?
- }
/ Y* a! T: J# _ - }
2 ^; a( Y: F, h1 J+ W - /* USER CODE END 3 */8 E3 J4 k1 ^$ U3 k! F. `2 L
- }
复制代码 5 }2 d4 H, G" q/ Z
至此STM32G071关于低功耗模式的进入与退出已经可以实际使用,大家可以参考,实际使用稍作调整。
0 T7 a, m1 g) n8 J2 A. g. s" ~% k) _
5 Q* j1 q, a# r$ i& h# D附加 避免上电自动配置RTC时钟3 F9 m/ W* c1 L& ]8 m7 E/ z% J
- /* USER CODE BEGIN Check_RTC_BKUP */
7 ]* F. k5 ~6 _# ~: t1 C - if (__HAL_RTC_GET_FLAG(&hrtc, RTC_FLAG_INITS) == 0x00u){}2 d7 j3 ~. A& @% x$ A" D
- else{return;}
+ P1 [0 j; M# O3 \4 W8 B# D - /* USER CODE END Check_RTC_BKUP */
复制代码
& a: C7 z) s9 b: z8 H9 x$ n# |" t以上代码请添加于MX_RTC_Init(void)中7 q' L$ E' ]! w
9 F3 L9 H, E: r- E5 O
3 p" k% J# C3 K/ S) L0 r
( C5 J9 Z* Y1 w# a项目文件
2 ^3 i- U& B$ [ K
& t% u& p f* b G4 D1 F: k7 d+ k5 [
, a- |' l( v- K) M# k! P% w: b/ m+ L$ T& e: c8 P; r
|