两天的调试与查阅资料终于明白了HAL库中的低功耗模式的切换和退出。主要还是自己作死选择了STM32G071,本文内容基于NUCLEO-G071RB,CUBEMX版本5.2.0,STM32Cube FW_G0 V1.2.0,MDK 5.27.1.0。1 M1 j; n8 c U
7 h* k% A& n8 W" S
首先配置时钟、UART、RTC和中断。4 j: I v# v8 y5 g1 K
; \6 o& s \0 U' r6 d" s2 G8 `3 }# k" g% i6 i" ~8 q- A! N
7 t- ^ o& G8 Z" J, c
RCC选择外部晶振(shutdown 模式只能使用外部晶振)其他默认
1 P0 k0 Z+ S. @( i
! e- f6 o6 L1 C# X3 U9 _2 q2 i5 H9 L" _ R; b6 [- N
0 |) _; i* `5 Q. Y* {& K. W5 Z
SYS选择调试接口,和wakeup_pin2,STM32G0目前新线还是很多资源的, z/ S& f) X. \. c* @ k: v
* p8 v5 ~" y3 J5 z& I
( D( x8 Q. a: a. C; J, t4 z9 @$ d; m4 f, C7 ]' X
设置RTC,填写相关初始化信息、开启ALARMA时间设定为开机后30秒,注意RTC_AlarmMask=RTC_AlarmMask_None;则为精确匹配,即闹钟不仅要求时分秒匹配还要匹配日期和星期,都匹配后触发闹钟中断)) ` b' M5 ]/ e, \3 V. c# A
& S/ Y2 A7 |, }% y [
j: c1 E9 X+ Z8 a) a% o* a O9 I9 X; k* X
设置串口( A% S0 y4 t3 [. r" u; v
4 D" K a s1 s. z% }+ a, ~
6 J: o8 C' M/ O3 ~* R* X
4 T9 B5 e e5 H) h0 C打开中断入口$ N) X+ `7 `" R) z
9 ]" T" ]) K& m
T; n% I. z! B8 e* T4 f3 I5 {1 u; e% \% I2 G0 I
9 d0 N! e8 b& z; n9 F, W" P
! \5 B7 A" e- t! _9 B完成设置后点击生成代码创建工程
- @' ]1 |2 i Y l% w8 \( x
# j/ d3 O, g1 I* X1.首先喜闻乐见的printf函数; n3 m) W5 ]7 ]4 f# J
- /* USER CODE BEGIN Includes */5 n4 N; n: |4 O& P% N
- #include "stdio.h"9 g% V0 J" }2 G U1 i
- /* USER CODE END Includes */
: b0 J1 v# V& Y @+ R1 }
/ ?: f' K" ^! Z; R! `* ]: b- : ?3 L; p. d; l* X& k! d
- 6 S5 [6 X7 [0 ^, Y' {( ]
- #ifdef __GNUC__4 i4 L4 E0 O/ K7 _' d2 N6 f
- /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
% s5 w3 r. l& G) u$ k, n+ @ - set to 'Yes') calls __io_putchar() */
; O: e3 I5 i- t/ b$ K! y: o - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)3 Y- l' k6 _. A9 L; M
- #else
; J \4 d* v9 C; `6 } - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)0 S: G1 K8 O; a
- #endif /* __GNUC__ */2 i! S9 P9 ?, u% \- w# U4 e
- PUTCHAR_PROTOTYPE
# `9 h3 {3 j* y6 u' Q - {
/ j* W; v1 v5 u1 k# t" f - /* Place your implementation of fputc here */
( u+ n/ S3 l5 _ - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
9 t& @4 h! Z4 V& Y, t1 G - ' H4 W& ?$ @9 q6 K
- HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);: s5 l. z+ P' p; L1 m/ N Y! O
- 9 e$ G" m0 x/ K- V
- return ch;
; z6 n7 l- V- n - }
复制代码 + j. }& y/ ^( j( {2 G( D
2.RTC时间获取函数
3 |% N% E% i% h. i/ d" v# g5 k5 z; D' e/ {
- /* USER CODE BEGIN PTD */4 f( \3 B9 o8 m# S8 T
- RTC_DateTypeDef sdatestructureget;' p& [6 W2 S @7 z8 s* f
- RTC_TimeTypeDef stimestructureget;
' z+ b) ?) Y& ]" ~4 z# G0 y - uint8_t aShowTime[16] = "hh:ms:ss";
" J$ O2 O! `* L - /* USER CODE END PTD */- f% w+ z; t* A% S) b
- ) T0 T" ]4 W) g& y) ^3 i+ I
- /* USER CODE BEGIN PD */
1 x0 f/ m6 d8 C8 E$ p, f5 c; S - static void RTC_TimeShow(uint8_t *showtime);
4 i% _6 H3 V2 ]5 k( U - /* USER CODE END PD */
1 N [' N: ?, X$ a - ! Y9 I7 k( j" s2 Q, K0 y- h
- ) P2 o$ D2 ]1 H& n
- static void RTC_TimeShow(uint8_t *showtime)- K/ T& b, c; @1 Z8 ^8 i
- {
! `( v( K! X0 O3 I& P6 H
: w' Y9 F! X# q: ~: y# z
; s: H% W1 Z1 y- /* Get the RTC current Time */- [, `9 J# K5 y% J1 P$ F4 c
- HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);4 P/ p( w. [. Y e4 c3 _0 {
- /* Get the RTC current Date */
% }, _, o( U P- N - HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);6 A& P; K0 K$ Y0 q
- /* Display time Format : hh:mm:ss */
* l1 `: i: y7 H' U5 f5 X5 ?. A - sprintf((char *)showtime, "%02d:%02d:%02d", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);
1 s, w2 P, }7 N/ ] - }
复制代码
+ M8 ?9 Q1 V% j; p$ W! r3.standby进入函数4 n0 X- D8 h F4 k1 \3 p
- /* USER CODE BEGIN PD */
0 @9 @% I0 i8 n" D - void Sys_Enter_Standby(void);( C3 J5 d8 }- e6 w$ A3 Q$ \1 f
- /* USER CODE END PD */
- h F! Y2 f' x! E - & @4 C' L/ \% ]9 G; y
- void Sys_Enter_Standby(void)
' Y M0 @) |( g" n P - {5 O0 [2 i3 m3 r3 e
- /* The Following Wakeup sequence is highly recommended prior to Standby mode entry
- `# X/ u6 F/ h% F+ } - - Enable wakeup3 y( T: I2 X8 l; W+ d( }0 H$ v) A/ m
- - Clear wake up pin flag depending in edge detection & pin level.
" G7 w" q' t, [! z* \" z - - Enter the Standby mode.
# R5 w. |7 N) [: R - */
' e% g B8 x: W7 a+ P
, g6 L2 \+ C1 ~) q9 i5 D- /* Enable WakeUp Pin PWR_WAKEUP_PIN2 connected to PC.13 */
& }3 n7 H6 h$ Y - HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_LOW);//上升沿触发
; \$ y) j& O: d - HAL_PWREx_EnableInternalWakeUpLine();
: t2 |! f2 R7 q8 L, g9 P) W - /* Clear all related wakeup flags*/
6 }1 U9 w2 ?2 b - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);
7 X5 P9 L, Q1 ]' m' C+ e9 ? - ; i' O3 }" ?' A8 W
- /* Enter the Standby mode */% M& Z9 W* Z$ m+ V9 w0 J
- //HAL_PWR_EnterSTANDBYMode();
& ?2 C" z6 ?! b& K - printf("enter Shutdown Mode!");: j8 B. P3 R7 J' R
- HAL_PWREx_EnterSHUTDOWNMode();
( U* N, o0 v. b5 u/ J' z
( z, t5 N8 N, y1 g3 b- /* This code will never be reached! */
3 e- D. i$ x* u# y" _' J4 I - }
复制代码 7 _( v+ v' _$ ~. `
4.ALarmA中断回调函数 NVIC_SystemReset()用于standby触发AlarmA时间后与wake_pin触发系统自复位不同进入rtc中断后无法复位问题(我解决不了就软复位)" A9 y0 J* Q6 M F" u
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
" e' v: @* _0 y- N" j' { - {5 s7 t- R7 S: r6 p' i* q
- /* Prevent unused argument(s) compilation warning */
1 T L% ?* }( N& k; } - UNUSED(hrtc);
2 b+ G/ M* R* H
8 t3 r: r5 W0 q5 F; S+ f8 F1 ~' M- /* NOTE : This function should not be modified, when the callback is needed,
( C" Z$ p& {0 B5 e% @! y - the HAL_RTC_AlarmAEventCallback could be implemented in the user file
a" O6 p# X8 Q5 m, K+ y) P# ` - */
. v/ f o) F3 s3 b5 }. @ ` - 8 ~1 L/ ^/ M2 N; x& T" A
- flag =1;5 U* o! }) w; v* t, Y
- // NVIC_SystemReset();
+ F5 S1 b% d. F* j* ^# m/ l4 Y -
9 e+ E( a1 ~/ ~1 [1 i! o" w) j - }
复制代码 " e, ~# \% d2 e% C& p/ \0 ]$ c( J
5.在main函数中5秒的时候进入低功耗模式
3 o3 p, r2 y* V4 @; v5 {* I q- /* USER CODE BEGIN 2 */7 n5 d4 h$ _; x' R# {
- uint8_t sec=0;" ?4 y- V$ q5 Q+ }& R% f& s# z
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)
" @4 j5 x r8 C6 z5 h) ~4 `3 r - {; g6 H, B0 ]) e6 m
- /* Clear Standby flag */8 D4 u, ^; ]* I$ _
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
1 U) @4 o7 ~" l3 q8 D' B7 g - printf("wake up from standby!");! F* N& s$ ?: y
- /* Check and Clear the Wakeup flag */
$ G$ ^( Q) l; I W, p/ f- T9 M! A8 d - if (__HAL_PWR_GET_FLAG(PWR_FLAG_WUF2) != RESET)
% G) ]9 I! i. C( ^/ R - {
, J" R1 i! ? F F - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);$ p, x) I' T' L5 |
- }
# v( r& [0 I, S P - 4 L) o) y3 T3 y- i
- /* Wait that user release the User push-button */
/ s: H: G( v1 b- W9 \' H- {6 @" l6 c - while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET){}
7 L; W/ ]0 e4 I, S! H
- `& A2 m- i- E0 t% K- }% j$ ~! p# R; ?
- / |7 U# T8 L* k* ]2 I, y- T
- ' z" N7 o. |$ z" n J
- /* USER CODE END 2 */) I/ E3 N: \+ F8 {7 n
- 2 v; V" M: [1 P7 U7 ^/ {9 v& b
- /* Infinite loop */
, |5 O) {& {0 M+ n% \, W - /* USER CODE BEGIN WHILE *// \; X; E8 a" \* T/ S
- while (1) _1 r1 e% j- K; o3 Z
- {
: X% S: z" y% `; x$ _( f - /* USER CODE END WHILE */9 Y% ?- {0 ^/ A6 f4 T& M% c' ]/ J
8 J' C' p+ t5 q, J" ]& [* J- /* USER CODE BEGIN 3 */; Z1 f# ]! V8 t5 Q, K
- RTC_TimeShow(aShowTime);
& u2 G3 y- `$ M' L( _$ u - if(sec == 0)flag=0;
6 E5 ]3 b% ~' O
+ R& i. F0 w0 ?) }: z) r- if(sec == 5)Sys_Enter_Standby();
+ U2 {( u4 a. _9 K - if(sec!=stimestructureget.Seconds)
+ O4 N" A. a& v# H; u- q7 f - {' L3 I1 B# h$ e" U9 A# @/ F9 Q
- sec=stimestructureget.Seconds;; d+ w0 c# J/ V4 \7 x/ ^6 l
- printf("%s",(char *)aShowTime);
) ]( I/ D. y9 ] - if(flag) HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);8 g/ a# x1 [5 K4 a- _
- }
& O4 L+ K# T6 z# p- s% f+ @! { - }
; ^" w+ i9 X" P. ]& _ - /* USER CODE END 3 */
# H7 `7 t( ~. F" N& }( f y - }
复制代码 ! N- o+ j+ o ^. \3 u
至此STM32G071关于低功耗模式的进入与退出已经可以实际使用,大家可以参考,实际使用稍作调整。: E& Y: Q3 s" W: _ J3 A* h
- d2 C8 C* b8 _ |/ O
附加 避免上电自动配置RTC时钟
8 H+ A( e( E- n& X. O5 | a# r6 Z- /* USER CODE BEGIN Check_RTC_BKUP */
: e' b; Q/ Q' D9 f - if (__HAL_RTC_GET_FLAG(&hrtc, RTC_FLAG_INITS) == 0x00u){}
; N! P8 O' } R: ~+ z - else{return;}
+ j4 L3 e! I* I4 X& n - /* USER CODE END Check_RTC_BKUP */
复制代码 3 k- ^ Z( O2 H; Q; g# X
以上代码请添加于MX_RTC_Init(void)中
* i3 n. R/ h a: v; b7 Z3 [+ h- p3 |$ w, ~% `6 `( g
, j |/ I- H& y0 R7 ~, d/ K% e
2 x$ V9 U P2 ?1 K4 P% o项目文件, W E1 A6 K; d: v6 F. m+ q
' ]& Z9 U/ u: {) v. W# o
8 a" D& Z# g5 i! ?- Q6 C. T: g- z( h: d/ T, N
, ^' o# \2 x# \9 M3 v |