两天的调试与查阅资料终于明白了HAL库中的低功耗模式的切换和退出。主要还是自己作死选择了STM32G071,本文内容基于NUCLEO-G071RB,CUBEMX版本5.2.0,STM32Cube FW_G0 V1.2.0,MDK 5.27.1.0。
, D' L0 s" X9 V5 L( K& ]
L0 ?+ z5 Y3 v2 h) X# [* h首先配置时钟、UART、RTC和中断。
; v% o; z! m: a- O/ } H* j# i% s+ W# R2 Z9 l, Z" D
- v. y; ` h: \/ u
5 F- |6 h% y: [" PRCC选择外部晶振(shutdown 模式只能使用外部晶振)其他默认
( m9 U+ B5 A a. V3 T6 N1 @
2 l7 f; b! g6 V
% B6 J! E; @& R! |
+ G# m' N1 R- c; b( m, i+ TSYS选择调试接口,和wakeup_pin2,STM32G0目前新线还是很多资源的
1 Z G0 p, ?: V9 u! B* r( W
" ~5 ]' H. q) ^5 k/ I$ N3 m4 a7 S: v8 T$ h; h3 g5 L7 L/ M6 x7 R0 f
$ k, |( P, X! t1 E' I' G
设置RTC,填写相关初始化信息、开启ALARMA时间设定为开机后30秒,注意RTC_AlarmMask=RTC_AlarmMask_None;则为精确匹配,即闹钟不仅要求时分秒匹配还要匹配日期和星期,都匹配后触发闹钟中断)
$ i7 E' \: ^) {0 ~3 B) r- Q% L
* O: N* m& v2 p) D; R0 P7 O
; K8 @( L6 {5 i3 m- s" H! [
+ m+ O& i0 R/ k- l2 S4 U设置串口
. W6 i0 F$ P! y' _; {; @& \& ]" ?/ \2 l' F8 J
' Z" H) B4 |5 ]2 I. j7 t, j1 M$ ^3 X( k: z+ y! Y+ d7 ~- S4 `7 M5 d
打开中断入口
% ?7 R# S/ B- ]0 m( n2 [, ?; _8 A1 N- Q6 Y6 I
9 W/ E& `* A( M5 u/ f0 ^: d# M
# _7 M& i( p3 `1 I H0 C. b) h2 z8 d3 Z
; }+ c/ P; c5 S' X. _2 u完成设置后点击生成代码创建工程 ]* |0 ]* k! Q) s- o: D
: t! |# d3 F8 E2 {, @* F7 u4 w
1.首先喜闻乐见的printf函数
0 e# q$ _; B* j. U" F- /* USER CODE BEGIN Includes */: s5 w5 z( `+ T6 H/ R3 ^
- #include "stdio.h"
2 ]& \7 _8 M) s0 b' n - /* USER CODE END Includes */
8 m0 s( Q* g" x: _+ g
7 L$ u: m2 C& N5 [( e# Z+ Y, I U& x
9 M/ N3 J0 r# q( Z1 v1 \! d
U' ]* H* A( W7 h7 m F$ A- #ifdef __GNUC__
f; t7 Z; E. Q - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
0 ?4 R" r5 Q) j, H' \ - set to 'Yes') calls __io_putchar() */* B8 a- @2 z' b) F
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
$ \; g3 G1 x; ~/ X& a) c - #else) ^+ ^+ H" P7 u$ {# D8 B8 @- K
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)( R' C4 Q$ f: \: b
- #endif /* __GNUC__ */
! t: W4 ~" P% `) _ - PUTCHAR_PROTOTYPE
* _. e7 X7 t# }( J - {- `! f& y" O) s3 S
- /* Place your implementation of fputc here */! O, c- ^- I( w0 X
- /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */5 D- n v, i7 r& |
7 j' m% P" `3 ]4 |- HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);& L! R( j/ N5 B8 {, d1 D1 a
- Y/ W+ y5 c! z$ R6 }9 ?. e
- return ch;
1 ]5 f# B% E! {- J' S" f! _5 ? - }
复制代码 % F2 `8 H; @7 B+ P& [& V
2.RTC时间获取函数
5 A7 ~2 |5 C6 d9 O
# T+ g' A9 q6 Z {2 y& {/ D- /* USER CODE BEGIN PTD */( ] d0 d9 T$ K/ K1 x4 w
- RTC_DateTypeDef sdatestructureget;/ R5 T( |6 ~7 [& D: C3 P4 s3 ^+ y9 j
- RTC_TimeTypeDef stimestructureget;' U9 `' I% \) X5 \+ D9 B
- uint8_t aShowTime[16] = "hh:ms:ss"; q" w6 v6 ?' m0 G% r
- /* USER CODE END PTD */
. v3 W j& _8 a, H. S: o - & h M% V2 @$ B* z1 a
- /* USER CODE BEGIN PD */; R, d" U* j( d' j+ b% M$ y2 t
- static void RTC_TimeShow(uint8_t *showtime);! l3 A6 R( H1 k
- /* USER CODE END PD */: M5 }0 h! K' X' M
3 \& O' Z7 i1 L: t' E8 a. M- ! R( ~* w7 g6 M' A
- static void RTC_TimeShow(uint8_t *showtime)+ C& g! p) W$ |/ f& N: Z: `
- {
8 h8 o: W! S0 L0 U
7 {# V9 w9 r, ~& A9 v0 C$ Y
. k# Y& G4 W1 ]& @$ q- /* Get the RTC current Time */
0 ^" J- n/ O8 l; i! i* Y* M* g3 f - HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);
3 }6 I7 q7 O' I- V: M7 P - /* Get the RTC current Date */
4 g5 L/ |/ Q2 c$ R- {+ E - HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);. `5 F4 }* k3 D
- /* Display time Format : hh:mm:ss */! p; G' j0 T8 `
- sprintf((char *)showtime, "%02d:%02d:%02d", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);, B# J' Z2 F! B M% s, b
- }
复制代码
, ]- {! l2 A# t5 ^' L) B3.standby进入函数6 _( ~6 S. O5 Z9 p6 R
- /* USER CODE BEGIN PD */7 ~* c& f. @- D
- void Sys_Enter_Standby(void);% F$ K5 D4 [- \0 b
- /* USER CODE END PD */6 C$ n! d6 P) P; a
* A B0 I Y9 v9 q- void Sys_Enter_Standby(void), j- J5 J* Z7 E+ y t
- {' I3 q% \0 f* V! a
- /* The Following Wakeup sequence is highly recommended prior to Standby mode entry& y. M& t- t! S& q
- - Enable wakeup% H( _$ ?2 K3 P: x9 }8 N5 A
- - Clear wake up pin flag depending in edge detection & pin level.
+ e+ j5 \9 Y0 l. @5 q8 c6 ^0 l - - Enter the Standby mode.. t) l4 a* J. H& v: N7 Z
- */
4 X/ h( J6 G4 s9 @) U# M6 c
# R5 F% [! L+ ]- i- /* Enable WakeUp Pin PWR_WAKEUP_PIN2 connected to PC.13 */. d/ U# l4 l R
- HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_LOW);//上升沿触发( U& A v" k l; B# z! _# b) S _) S
- HAL_PWREx_EnableInternalWakeUpLine();
* g5 } z& L0 _ - /* Clear all related wakeup flags*/
{% m- H& n8 h2 d - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);
" t+ F7 i( D% O o/ N. h# s - # {0 p, e+ t5 K8 I1 V% s
- /* Enter the Standby mode */
, |. l# W$ y: t2 Y - //HAL_PWR_EnterSTANDBYMode();
, C( y8 _2 ~+ B; h) ^7 v: o - printf("enter Shutdown Mode!");
- U- p- n& x1 l* N$ ?4 v2 q( ] F - HAL_PWREx_EnterSHUTDOWNMode();$ f8 I+ w4 q: t) r( J& ?
7 X8 j: h! q0 D0 B- /* This code will never be reached! */
( j$ ?. y# B1 \ A; A - }
复制代码
( m/ m5 H: p' h, f" l4.ALarmA中断回调函数 NVIC_SystemReset()用于standby触发AlarmA时间后与wake_pin触发系统自复位不同进入rtc中断后无法复位问题(我解决不了就软复位)- N4 Z; D% u. x1 h% t: w
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
4 Z* l& b$ B. ~) U$ A& J4 G6 B - {; ^6 v6 ]) i6 N; A( n/ l* o
- /* Prevent unused argument(s) compilation warning */) v6 I% f- M0 H
- UNUSED(hrtc);
" P m* F( Y& z6 j( ]$ d - + Y; d9 r. z% E
- /* NOTE : This function should not be modified, when the callback is needed,& f' \! ?% b7 E& }( _0 T
- the HAL_RTC_AlarmAEventCallback could be implemented in the user file; f O* w& `4 N
- */* b! W' t9 \! u8 R/ W6 Y& _
) J/ F7 G( Q' e% Q3 |0 j- flag =1;
9 Y: N& w9 y7 A - // NVIC_SystemReset();
7 y' [2 v8 ?2 t N - / n) I [; Y* W' P
- }
复制代码 , f# m9 L) R1 D$ f
5.在main函数中5秒的时候进入低功耗模式
, H5 b; n" ~5 n: P- /* USER CODE BEGIN 2 */
4 k+ v: V% g" \" P3 G - uint8_t sec=0;0 A1 n p) Z* ?6 O- @) h5 `) J
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)% J4 R# b: P b1 A* f; [
- {2 J, R% F( y# w5 P5 o" T7 X; @! t
- /* Clear Standby flag */
4 y2 L: p0 o+ D G9 j2 r - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);3 \( ^" |" ?* u9 k$ i
- printf("wake up from standby!");
2 }' I, m3 T6 k% ?& {4 E! B6 } - /* Check and Clear the Wakeup flag */* c6 N) p3 W3 ^! X
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_WUF2) != RESET)
7 `7 ?4 t% i! w2 c$ P - {
4 ]0 y- S, D; ]# ~$ ~; T - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF2);
* ^9 C" ]! h5 Y5 B* S% R - }
/ ^4 I4 F9 h5 v0 C# L I7 q - 5 x0 y' n j. @, S2 X3 U
- /* Wait that user release the User push-button */1 P9 _( V/ E, V
- while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET){}
* h( z' V; b9 E+ ]! ?/ l
. c9 d$ m/ H: F$ N: [ d s- }
8 L) o1 s6 U: s1 w% ?7 ?9 d! e2 ~6 J - ' t- G; Z' M) B- s
- ) b: t" `; H8 w% `. K) g
- /* USER CODE END 2 */
: P( Y2 a$ i9 L. A5 w1 d: H/ y6 I! p - ; x, H) ]* o: n
- /* Infinite loop */
" P8 x! ~8 m5 I7 _6 _- u# x% ~ - /* USER CODE BEGIN WHILE */. v+ `1 x0 Q( I( Z
- while (1)% l+ j* I- O" P7 p$ b
- {
/ M$ D" L3 F( l9 k! M- e; ?$ r - /* USER CODE END WHILE */
2 ?4 l$ g5 H2 f6 W0 r2 I' I4 y - 6 O i j" v1 G! J
- /* USER CODE BEGIN 3 */
' |/ A/ u; N! s4 ] - RTC_TimeShow(aShowTime);7 G2 K- g: p/ ]. I! b3 s: L
- if(sec == 0)flag=0;/ O! X! |! ?+ h/ W# T
- , X; Y: Z0 K6 `
- if(sec == 5)Sys_Enter_Standby();
+ N8 z* [9 F* Z2 q' b8 v/ G - if(sec!=stimestructureget.Seconds)! E/ E* s# U+ c- P5 Y
- {
; `' K& l# [3 {0 j/ L' e - sec=stimestructureget.Seconds;
- l) n: R+ y% m: _1 [ - printf("%s",(char *)aShowTime);
% G' F# k$ P' k+ C1 e - if(flag) HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);, i+ f8 M# L7 _ m4 O1 C& y
- }# y% `2 ]/ \2 ]0 m- R2 E! S
- }6 P0 l) Y7 J5 J6 C Q% L6 C
- /* USER CODE END 3 */
7 l9 X; u6 ~/ y) J+ ~8 l! ~ - }
复制代码 % T8 P1 y5 R, E" H% Y; p8 O
至此STM32G071关于低功耗模式的进入与退出已经可以实际使用,大家可以参考,实际使用稍作调整。
; c% ~0 k L8 t7 f% h
- s# x# o# e& p1 I; w附加 避免上电自动配置RTC时钟
3 r. C# j! M3 C1 v1 m' m: J- /* USER CODE BEGIN Check_RTC_BKUP */
7 L# f0 x4 E6 D& P) F - if (__HAL_RTC_GET_FLAG(&hrtc, RTC_FLAG_INITS) == 0x00u){}
3 i( N, N- s# T7 f - else{return;}
5 ~8 D2 ~6 [9 I8 Q - /* USER CODE END Check_RTC_BKUP */
复制代码 9 N5 \4 N# s& e- ?
以上代码请添加于MX_RTC_Init(void)中
' o6 ~) F3 f* d: Z( i$ l4 G3 i6 U$ l9 b! b' m9 K) |8 R% H
* U( a) A% a# Q" ~: i% `! }0 J
: A V/ @' c( T# `项目文件
' S$ y4 X$ G+ Z" K2 [6 N* Q! \, }) N$ f
8 F5 O4 a8 v, V p1 u" V! [$ v& P% D7 x5 I3 M! F) P
3 l' ^% r, U. |$ }, F# j
|