你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32心得:低功耗待机唤醒实验

[复制链接]
STMCU小助手 发布时间:2022-11-20 15:53
主要内容:/ X, @4 ^2 F6 M4 f9 ^( I& `+ X
1) STM32低功耗模式讲解;
( R4 `2 [) a" O! w' i0 z8 E2 O2) 寄存器和库函数配置;9 U$ i$ j1 e% B; l9 C
3) 实验代码解读。% [1 \( I0 ?* p& t+ j
实验功能:针对GPIOA,引脚0,启动后系统进入待机模式,长按3秒待机唤醒,LED0和LED1闪烁,长按3秒进入待机模式,LED0和LED1灭。
3 _" f. n0 J* V. W
$ F3 j  z0 d) G+ z$ l1. 待机唤醒/ z( c2 p* p) i0 X+ P% ~7 M
很多单片机有低功耗模式,STM32也不例外。在系统或者电源复位后,微控制器处于运行状态之下,HCLK为CPU提供时钟,内核执行代码。当CPU不需要继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个事件触发。* r7 N. o9 G  Z
1 [; ^' L: Z/ u0 ?2 V( Q; E1 s. w
2. 低功耗模式:
% E6 K- L- P5 h& y: N0 q2 h8 j2.1 睡眠模式:内核停止,外设如NVIC,系统时钟Systick仍运行;* w3 _$ Z- V" X) R+ _1 X
2.2 停止模式:所有时钟都已停止。1.8V内核电源工作。PLL,HIS和HSE RC振荡器功能禁止。寄存器和SRAM内容保留;# Q0 D/ [$ @% ?( J2 c9 a" a
2.3 待机模式:1.8V内核电源关闭。只有备份寄存器和待机电路维持供电。寄存器和SRAM内容全部丢失。实现最低功耗。
, R; o; R( U4 Y8 h; B. y" X功耗消耗排序:睡眠模式>停止模式>待机模式(功耗消耗最低)4 j0 k/ B! [1 T, Q7 g5 Z9 n4 ?
2.4 运行模式下降低功耗的办法:
$ e& N2 ?' o4 q, n: |* m+ h2.4.1 降低系统时钟;
) _2 C" }6 N1 u' A- E2.4.2 关闭APB和AHB总线上未被使用的外设时钟。- A' x0 Z- i8 W

. `' E4 i' @/ _' L3 n4 G 20200518100102494.png 5 z3 z: G: M/ w4 `2 X# X. _

6 s+ a+ n2 j+ X: i% s! ~8 M! X( D用户可根据电源消耗,最快启动时间和可用的唤醒源等条件,选择一种最佳的低功耗模式。% D0 A  P$ H" T8 |% ]: O% V
3 u! a0 ^, Q+ i. g; S: Z" w
3. STM32的待机模式

+ \# @; `. y, F% j/ T7 u5 G* q1 y2 z5 u( h% W( ]  K* p4 X4 U
20200518100213879.png
+ U, L$ v: K4 G! G3 ?待机模式理想状态下,只需要2uA电流。停机模式下典型电流为20uA。- {  ?9 Q. e' `) y8 }

6 a% W7 z0 O. e) b% a# ?( X4. 相关寄存器
: {7 y! Q5 @$ A& D4.1 PWR_CR电源控制寄存器:
: F, p" R1 P" Z0 b6 J1 y1 I) P7 [7 S# x  B, u. L+ T) u
20200518100340920.png
5 f/ ^+ q1 R# a% z. X# S) V9 n& Q! f' O
4.1.1 设置PDDS位进入深度睡眠时进入待机模式;7 b* W' [. }1 U3 u2 Q1 A
4.1.2 设置CWUF位,清除之前的WUF唤醒位。
& i6 L. n  |7 D' r$ a: ^2 M4.2 PWR_CSR电源控制/状态寄存器:- \8 x, q" v# s$ R
9 @; q- w- M8 v" j0 H1 [+ \
20200518100440476.png 1 p) S* H2 o3 R
$ _+ z7 @/ P$ m
4.1.1 设置EWUP,使能WKUP引脚用于待机模式唤醒;; {6 ], o* v2 p% }5 J2 ?
4.1.2 WUF唤醒标志,用来判断是否发生唤醒事件。
# w, ~( n0 o- [$ O
1 J- \+ ~# Q2 a8 e5. 相关库函数5 e3 s. R+ B; i8 K
5.1 官方文件为stm32f10x_pwr.c / stm32f10x_pwr.h;8 X) l8 f  V& L  D" b5 _
5.2 主要库函数:: O8 w+ d  E3 u/ h

/ S3 k! }3 u1 u; p% Q  t
  1. voidPWR_EnterSTOPMode();                           //进入停机模式1 R9 s( Q+ L: Z4 v3 J/ D1 b; D
  2. voidPWR_EnterSTANDBYMode(void);                    //进入待机模式
    6 m0 U' I. l, t* P6 f. ~
  3. void PWR_WakeUpPinCmd(FunctionalState NewState);   //使能Wakeup引脚唤醒
    . H: _4 v, z2 {$ ]9 N
  4. FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
    3 _. H/ G9 J4 _; F" e
  5. void PWR_ClearFlag(uint32_t PWR_FLAG);
复制代码

. P  S- k: n6 i% I  _6. 待机唤醒配置步骤:/ r: U5 W" p7 [; e7 e" t
6.1 使能电源时钟。因为要配置电源控制寄存器,所以必须先使能电源时钟:( J" `7 h0 b# Z. G) ^4 t# R% G
9 _8 E* j! V! ?6 N
  1. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
复制代码

3 R$ T7 N5 e  A& F8 L6.2 设置WK_UP引脚作为唤醒源。设置PWR_CSR的EWUP位,使能WK_UP用于将CPU从待机模式唤醒:7 _: O" k2 c7 V4 k

" ~: G5 Y' C; Y% b
  1. PWR_WakeUpPinCmd(ENABLE);  //使能唤醒管脚功能
复制代码

3 U4 ?5 U2 z+ M6.3 设置SLEEPDEEP位,设置PDDS位,执行WFI指令,进入待机模式:
) o( s" |* z. J9 b: O6 @6 U7 Y3 `: z( t4 X* d
  1. void PWR_EnterSTANDBYMode(void);
复制代码

' t8 e# i0 g; t" }7. 程序思路1 a4 n$ X3 j. A# P
7.1 在待机模式下,WKUP用来唤醒。按下WKUP,就会从待机模式唤醒;
$ {; W' Q* j+ |  `+ L- h7.2 正常情况下(没有进入低功耗模式),WKUP是可以作为正常的输入口,或者中断触发引脚来使用。
/ m: ]& S* [7 S" D; `: z
2 b( }" @) S7 z8. 相关实验代码解读
- `3 ]& w! J3 P& I6 a0 W& q! W8.1 wkup.h头文件代码
* R" R# o$ y# X; c4 M5 Y8 D9 G' J) ^
  1. #ifndef __WKUP_H
    8 ?7 X" ^& F, t! y. |
  2. #define __WKUP_H  ! S( X2 X3 n# W" u# a& e
  3. #include "sys.h"         
    / \# o- w5 c0 X' G7 n
  4. #define WKUP_KD PAin(0)        //位带操作,WKUP_KD对应GPIOA_IDR的0位//
    3 F0 Z6 N& o$ n6 `2 d6 H! V
  5. //三个函数//2 M$ M4 J0 \! g0 U& c% d9 V
  6. u8 Check_WKUP(void);           //检测WKUP脚的信号,返回u8格式数据//2 ?4 M4 J8 o1 A6 P* c+ e* N- s
  7. void WKUP_Init(void);          //PA0 WKUP唤醒初始化//8 R+ K) Z# o) d  p
  8. void Sys_Enter_Standby(void);  //系统进入待机模式//
    $ Y+ K8 ~& `, r7 A# |' V
  9. #endif
复制代码

) F# p6 k9 b; g8.2 wkup.c文件代码解读
/ M- `+ V8 V; T& |2 w5 o' k& z+ r
5 d2 J2 F+ s: |# N  c7 R; m
  1. #include "wkup.h"
    " c/ E4 k+ o* X; }* S8 V5 y
  2. #include "led.h". G7 x$ I, n( P* _
  3. #include "delay.h"6 L' y) g, m9 W8 a
  4. //待机唤醒配置函数//  / p+ z0 f2 a6 t3 R  [. ~
  5. void Sys_Standby(void)
    2 V4 w0 [' o# r8 ^) j9 y
  6. {    R7 G4 Z  A, ?; B5 ^
  7. //第一步,使能PWR外设时钟//" l1 Y! M4 N0 D, q5 T' P# p2 M
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    7 f3 E+ D) C7 H9 i/ j: i
  9. //第二步,设置PWR_CSR的EWUP位,使能WK_UP用于将CPU从待机模式唤醒//7 M" M2 s9 s9 l$ v7 L  g" G" E
  10. PWR_WakeUpPinCmd(ENABLE);  ) c0 O' E7 {7 j7 q! l
  11. //第三步,进入待机模式//
    ( N  O9 t: A& _! h, X7 q
  12. PWR_EnterSTANDBYMode();      : A8 [$ C5 ~/ u. l. n5 r' L
  13. }
    ; `5 E$ Q8 A6 z# M0 O/ ~( i; Y1 B, ^
  14. //系统进入待机模式//! `" y4 h5 h8 f1 v( u0 r
  15. void Sys_Enter_Standby(void): ^7 U$ z/ J% R5 H0 i7 W3 j) p
  16. {   
    8 I2 e! d% a+ i
  17. RCC_APB2PeriphResetCmd(0X01FC,DISABLE);    //复位所有IO口
    ' H' m- H5 Y) Y- W' B9 I
  18. Sys_Standby();6 U2 `) M( V$ l/ C. Y9 h4 g4 ?
  19. }
    $ D& p8 v: E  m4 j
  20. //检测WKUP脚的信号,纯C语言//- ~- e! ~- w: `$ n
  21. //返回值1:连续按下3s以上;0:错误的触发// + ?1 S) N- N- j! G" R7 J  t
  22. u8 Check_WKUP(void) : z- {, I! P* N2 u1 S6 o$ B
  23. {
    $ ?! b8 Y% x: f4 ^1 s/ P( \
  24. u8 t=0;                                    //记录按下的时间//' v' y  Z) v& e
  25. LED0=1;                                    //LED0灭//
    & B% a; |% o' }; Z
  26. LED1=1;                                    //LED1灭//- n! t- Q- s  M9 i. j5 y2 I
  27. while(1)
    / m: ~3 z9 T$ T! d# L
  28. {/ J, @3 y4 w4 i3 M
  29.   if(WKUP_KD)                               //WK_UP按键对应PA0,即按下时为高电平//. b0 b1 i+ w5 o5 c, |9 y. l& i
  30.   {9 \1 u& i9 K) S- I* M8 F& V
  31.    t++;                                     //已经按下了// , f# h7 L0 c3 j( O
  32.    LED0=!LED0;
    , N* n  H- {. B: }! k7 ^1 @
  33.    LED1=!LED1;. W& y- r' p- G; {! P! W) i
  34.    delay_ms(30);   
    ' E: `: n/ G- I' I
  35.    if(t>=100)                               //按下超过3秒钟//3 E* `+ A- r1 D7 J
  36.    {
    $ y: R+ G$ g7 h8 n% U3 l
  37.     LED0=0;                                 //LED0亮// # N* I. r: N6 n7 Z1 v9 `8 U2 t
  38.     LED1=0;                     
    & X7 k5 c/ @7 |/ p
  39.     return 1;                               //按下3s以上了//3 l1 P2 k! G. p) c3 J
  40.    }
    ( K! c/ n  Y/ o) r9 j$ ?
  41.   }else
    , [5 _/ Y: b4 C) M6 Y! B4 o3 X
  42.   {
    ' r  Y" s/ T' k
  43.    LED0=1;                                  //LED0灭//
    1 O9 T5 p5 L$ s2 `/ d
  44.    LED1=1;                                  //LED0灭//
    ) Q5 j8 y7 O5 P1 ~/ Z6 P
  45.    return 0;                                //按下不足3秒//: j, X7 m5 R1 b3 q/ p( o6 r
  46.   }
    ) k8 ~6 p# Y2 \5 f% |
  47. }
    $ C  c( p' s8 l4 q( }' q6 U
  48. } 4 ]7 J1 R, v: K+ }
  49. //编写外部中断服务函数//( h& t2 |" \* ~1 ]6 m
  50. void EXTI0_IRQHandler(void)                 //因为检测PA0,所以用EXTI0//$ I! r% `% k* g! |  ?6 [( V- L
  51. {                            9 j$ K- @$ _' I. ~
  52. EXTI_ClearITPendingBit(EXTI_Line0);        //清除LINE0上的中断标志位//    ; w# f% ^4 T+ t1 Z
  53. if(Check_WKUP())                           //检查WK_UP是否按下3s以上//& P: V- Y8 Y  ~& @0 M4 }5 r
  54. {   
    , U) d' v/ E% B# G. V9 A
  55.   Sys_Enter_Standby();                      //按下3s以上,系统进入待机模式//- U7 [  {" ?3 H2 b8 Q
  56. }+ m  f" d3 R7 {4 N
  57. } ' S' Q# N  C0 N" W8 o
  58. //编写WK_UP初始化函数//  I5 ?' x) m* Z' N$ O. h, v
  59. void WKUP_Init(void)6 O4 f+ a9 o* o1 Z* V' y( }- u
  60. { , p  G, F2 J; {. V) n  @
  61. GPIO_InitTypeDef  GPIO_InitStructure;      / S0 e$ }6 K1 T
  62. NVIC_InitTypeDef  NVIC_InitStructure;
    % D( C/ \  F$ Q, p5 ]7 r
  63. EXTI_InitTypeDef  EXTI_InitStructure;# K8 ]/ f* z: X( ?7 h7 J
  64. //使能GPIOA和复用功能时钟//6 T7 ?! I7 I5 y" K! _* M
  65. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    & [  c1 v& r2 i0 }! p2 F4 C$ r
  66. //GPIOA,引脚0配置//
    # I; x: j! }7 ]
  67. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0;                     //GPIOA,引脚0//
    4 D. ]+ X0 V& D9 O7 S" F* z
  68. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;                 //上拉输入//
    ; J2 h6 X9 Z# M
  69. GPIO_Init(GPIOA, &GPIO_InitStructure);      ) }- M. o: u$ r+ H( b" F) k1 z
  70. //使用外部中断方式//
    6 r" `3 ?( T, S
  71. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);  //中断线0连接GPIOA.0//4 O# X: Q4 X0 N" Z4 ?
  72. EXTI_InitStructure.EXTI_Line = EXTI_Line0;                   //设置按键所有的外部线路//
    5 w4 G$ @8 m3 c8 S7 \, v. f
  73. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;          //中断模式//; Q( I: z0 i, J5 p$ J
  74. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;       //上升沿触发//( }0 k. R* H6 M! p
  75. EXTI_InitStructure.EXTI_LineCmd = ENABLE;                    //使能//
    * A8 j; U. D6 B0 U$ u8 t1 }
  76. EXTI_Init(&EXTI_InitStructure);
    5 j  T5 P4 _2 q* W% s. }% s6 d
  77. //中断优先级初始化//# V- E2 }+ ~2 G& {
  78. NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;             //使能按键所在的外部中断通道//: S2 q$ A/ E+ g, K
  79. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    //先占优先级2级//: c1 p% o" b6 h- v. l- n
  80. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;           //从优先级2级//
    2 P6 \6 d; K6 i5 C/ p  X6 Q
  81. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //使能外部中断通道//2 _7 [4 B/ G5 v# R) |
  82. NVIC_Init(&NVIC_InitStructure);
    " m/ `; ]1 U/ H! q$ d0 [& h
  83. if(Check_WKUP()==0) Sys_Standby();                         //不是开机,进入待机模式//
    * R9 o: ^' b) W5 @5 y* }
  84. }
复制代码
- _8 X* S6 V$ x3 u5 s
8.3 main.c文件代码
; G$ u0 A& W: E; ?' ^# a
6 f" ^( _$ D; X
  1. #include "led.h"
      |$ B0 h. u4 b  i$ c, K; P8 a
  2. #include "delay.h"+ {! c4 r# `0 O' _! q
  3. #include "sys.h"* b% R7 o9 M+ g' R1 Q
  4. #include "usart.h"  
    7 ?) W& S; ^( K1 k: j. r& S
  5. #include "wkup.h"
    5 s. ^1 H  Z7 N1 j7 C8 w' j( H  M' l
  6. int main(void), ?# y& L7 P- k: a* Y% Z; C
  7. {  
    ! g) _+ F' \, w8 m9 Q1 m2 Z
  8. delay_init();                                   //延时函数初始化   
    ( N  w' s$ h# a3 V# |
  9. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组为组2//
    % i. J4 o. i7 k. ]) v; l5 t5 x
  10. uart_init(115200);                              //串口初始化为115200
    . W3 B: N! n' n. y
  11. LED_Init();                                     //LED端口初始化
    ! p/ x% G& C# K+ a% y, m4 O
  12. LED0=0;
    ' m8 v' Z- i3 M" u
  13. LED1=0;
    : N+ G3 M$ t# r% K
  14. delay_ms(500);  
    & u, ?" B1 l  x, Q
  15. WKUP_Init();                                    //待机唤醒初始化  $ X7 R: O: V2 P8 i- j1 t
  16. while(1)- B$ q. `7 x! {8 _6 i2 I, B- r7 y
  17. {3 u0 N7 Z3 l8 ^* S! i/ c
  18.   LED0=!LED0;# G' H" Q4 i2 y7 e' S  ?! E/ }
  19.   LED1=!LED1;4 U$ K! e$ C. ~& z  ^7 w
  20.   delay_ms(1000);
    1 P( }' O: B1 \; j8 h# e# g3 O' B
  21. }
    2 E/ y3 S1 @+ m" [' m
  22. }
复制代码
7 M! G3 q6 O2 x4 x+ N9 M# m
————————————————
9 o4 V$ k: ]3 o! g7 Y4 n% q- w3 V7 |8 O版权声明:天亮继续睡
+ F* l, q) W* x+ w% O8 Q- k2 G
& d3 w% X! _! r4 F7 d) n; y9 U- B* R2 e  w: \
赞 收藏 评论0 发布时间:2022-11-20 15:53

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版