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

STM32实例-待机唤醒实验

[复制链接]
STMCU小助手 发布时间:2022-10-11 18:35
本文我们来学**STM32的待机唤醒功能。要实现的功能是:系统运行时 D1 指示灯闪烁,5 秒后进入待机模式,D1 指示灯熄灭,同时串口 printf输出相关提示信息,可通过 K_UP 按键实现唤醒。学习本内容可以参考《STM32F10x中文参考手册》-4 电源控制器(PWR)章节。- ^9 u0 J2 c' t/ ?* H0 D# a
( c8 F: f% }+ _; ]4 }5 `
STM32 低功耗模式介绍
5 R6 ]: F0 g$ L3 K6 ~0 X0 Y    很多单片机具有低功耗模式,比如 MSP430、STM8L等。我们的STM32也不例外,相关文章:STM32低功耗模式。默认情况下,系统复位或上电复位后,微控制器进入运行模式。在运行模式下,HCLK 为 CPU 提供时钟,并执行程序代码。当 CPU 不需继续运行(例如等待外部事件)时,可以利用多种低功耗模式来节省功耗。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。" L+ F3 H3 y; _0 B9 E

9 Y- l: \) ^6 p    当然在运行模式下,也可以通过如下方式降低功耗:; m4 E6 k6 Q# y  E$ [
(1)降低系统时钟速度
1 Q% S2 W. T  h  o& P- w" U3 V(2)不使用 APBx 和 AHB 外设时,将对应的外设时钟关闭  c8 I: W  J* l, x& @, O
4 n' m2 A# s, E
    STM32 提供了 3 种低功耗模式,以达到不同层次的降低功耗的目的,这三, y, j1 z: E' ]5 a  T: \+ ~7 @

3 q5 W+ Z* Q3 S$ Y6 F, _种模式如下:
6 E" z' p. v7 j5 k) B1 f* r(1)睡眠模式( CM3 内核停止工作,外设仍在运行)* j4 s3 _) g$ ~. d/ b! j. o2 C9 K
(2)停止模式(所有时钟都停止)% D- }" x+ j( N8 ?/ l7 w8 f! }
(3)待机模式( 1.8 V 内核电源关闭)
1 d+ N5 z0 s- M3 i6 T. c& b) F# K. f+ F/ `# _, \
    这三种模式所需的功耗是逐级递减,也就是说待机模式功耗是最低的。三种低功耗模式汇总表如下图所示:
' F6 D: y: [  i) P0 Q  D% h  L7 F1 y5 v- k( _1 K
微信图片_20221011183508.jpg : h# u  }  y. N/ l; `' v5 x1 D

* X' t7 L8 O8 B6 a' }    我们仅对 STM32 的待机模式进行介绍,其他 2 种模式可以参考《STM32F10x 中文参考手册》-4电源控制器(PWR)章节,里面有详细的介绍。- q+ y9 @) h3 T) R+ R5 V. H4 ^/ I# b# e( ]

$ C' U. t: Y+ i0 f/ {2 x5 N(1)待机模式
3 @4 f% v! p7 h5 i; Q% [    在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设, CM3 核心的外设全都照常运行。在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其 1.8V 区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。在待机模式中, 它除了关闭所有的时钟, 还把 1.8V 区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测 BOOT 条件,从头开始执行程序。低功耗开发相关文章:STM32低功耗开发时,需要注意的GPIO配置问题。0 c6 A, T1 r8 C5 X) S
+ W; I9 v0 L9 z- K# D9 W, ]2 ~
    那么我们如何进入待机模式呢?其实很简单,只要按下图所示待机模式进入与退出步骤的步骤执行就可以了。
  E$ y2 \" y( }
& Q% j1 X' f* f5 ~: W 微信图片_20221011183445.jpg 2 R, T! G. `4 O" a) t# h

) T. h. ~' Z* c    上图还列出了退出待机模式的操作,当检测到外部复位(NRST 引脚)、
# ^9 b! B+ }5 N9 d
" y( a% {9 A3 f5 q% c9 [IWDG 复位、 WKUP 引脚上升沿、 RTC 闹钟事件的上升沿时,微控制器退出待机模式。本文我们是通过 WKUP 引脚(PA0)上升沿来退出待机模式,当然也可以直接通过芯片复位管脚 NRST退出。* X0 |7 @  M2 a+ f3 I* `$ @

8 K# n1 ^, Z' ?    从待机模式唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有的寄存器豆被复位,程序将按照复位(启动引脚采样、复位向量已获取等)后的方式重新执行。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。
+ J, h" s/ v: R6 L3 O* \2 d2 D5 ]2 G7 L6 ^6 e( O0 L# ?3 h% C& a
    在进入待机模式后,除了复位引脚以及被设置为防侵入或校准输出时的
; b: M& N( U# `% n) L
8 ]" c( S; r0 ~" \/ Y3 t9 p  rTAMPER (PC13)引脚和被使能的唤醒引脚( WK_UP 脚(PA0)),其他的 IO 引脚都将处于高阻态。
9 Q- o% Y2 y) L) r( X; E" R
1 o! I- s' I- Q2 a3 k) g6 y    由于篇幅限制,本文并没有对待机模式相关寄存器进行介绍,大家可以参考《STM32F10x 中文参考手册》-4 电源控制器(PWR)章节,里面有详细的讲解。如果看不懂的可以暂时放下,因为我们使用的是库函数开发。
! @( ~0 X# C: |$ J/ X1 M! O- l! J  x+ \" w# T$ E1 H& ?  z9 |
待机模式配置步骤7 V- J8 n) S$ T1 X6 `" K

/ D! O* i& U( T2 P( P5 {* s    接下来我们介绍下如何使用库函数进入和退出待机模式。这个也是在编写程序中必须要了解的。
# ]& k2 j: L$ p3 K% h  a, J
7 N; q: L% F7 |  w$ T    具体步骤如下:
' {4 Y3 Z  r/ k& O  [( ^
5 E; {, Q4 V9 k! ?(1)使能电源时钟$ x8 x% Z# m( C( k' E" L
) C5 E3 K0 Y: M* {
    因为低功耗模式是通过 STM32 电源(PWR)系统进行管理的,所以需要使能电源时钟,调用的库函数为:
  }8 P: g" P7 n6 w
/ d1 K7 {  m  m
  1. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能 PWR 外设时钟
复制代码

; D) Z7 n' `" F. b3 W$ ]: T: H, A(2)设置 WK_UP 引脚为唤醒源% T* r" Z+ T% y) X! I; L
0 m# P' k, |" R: V0 {% e7 m
    待机唤醒方式有很多种,我们选择 WK_UP 引脚(PA0)上升沿来退出待机模式。在库函数中,设置使能 WK_UP 用于唤醒 CPU 待机模式的函数是:# I" a7 a7 r. w* v0 j# x
  P1 c, P5 L+ J+ s8 @! ~5 Q. k
  1. PWR_WakeUpPinCmd(ENABLE);
复制代码

9 g1 s1 a+ J( E- j    因为按键 K_UP 连接在PA0 管脚上,并且是高电平有效,这样一来就可以使用 K_UP按键来退出待机模式。' y- E% a/ ^& Y
8 m7 g! c3 K2 M# W; B
(3)进入待机模式& c7 `6 f3 Q  j, q8 T3 @
& Z4 U# d! ?. B3 ]0 D; B& C( K
    进入待机模式, 首先要设置 SLEEPDEEP 位 ( 详见 《 Cortex M3 权威指南(中文)》 , chpt13 Cortex-M3 的其它特性--电源管理章节) ,接着我们通过 PWR_CR设置 PDDS 位,使得 CPU 进入深度睡眠时进入待机模式,最后执行 WFI 指令开始进入待机模式,并等待 WK_UP 中断的到来。整个操作可以通过一个库函数完成,如下:
6 N% j& }5 v( d, f, W7 D
! `. W5 t8 g3 S6 y
  1. PWR_EnterSTANDBYMode();//进入待机模式
复制代码
, }* }* v) V: o% o6 u( [4 ^2 m
    通常在进入待机模式前,我们会清除唤醒标志,以等待下次进入。清除唤醒标志库函数为:! k& K+ t% n# m: T8 O6 c# I

# Z9 J8 d, U7 {2 Y: R
  1. PWR_ClearFlag(PWR_FLAG_WU);//清除 Wake-up 标志
复制代码
; s8 n/ b3 w* }( n: c3 M5 z
    以上几步全部配置好后,我们就可以正常进入待机模式了,并且可以通过按键 K_UP或者复位按键唤醒。
7 ?9 \7 g& [. ]  F+ ^! l$ W
& S" Y7 |( Y* }    特别提醒下,如果学到 RTC 实时时钟实验的时候,需要进入待机模式,如果使能了 RTC 闹钟中断的时候,进入待机模式前,必须按如下操作处理:
+ p4 Y! ]$ }0 t5 v1 ]/ F$ V
3 N% S) A% g, H. r9 O3 v+ d1.禁止 RTC 中断( ALRAIE、 ALRBIE、 WUTIE、 TAMPIE 和 TSIE 等)。
2 ]. r! [# i4 m( j" Y+ K" M  `1 ]' d/ e' r- L
2.清零对应中断标志位。! H# q5 e& p# M

& Y- a8 ^2 X9 E; o1 H3.清除 PWR 唤醒(WUF)标志(通过设置 PWR_CR 的 CWUF 位实现)。
/ w1 a. z8 G$ e6 B! c8 g$ s" R+ i! j/ \
4.重新使能 RTC 对应中断。9 o6 [! {, o$ n/ f# }4 w
8 E% R7 D( Q8 d
5.进入低功耗模式。
3 B* T$ p) F% K. a+ e1 ]* q. o9 ~- ?, l  ^0 r# b
    本实验使用到硬件资源如下:
$ N/ G2 D2 y( B# `
. m5 N: G* t( E(1)D1 指示灯- ]. z6 n3 |1 g( ~
" t+ f- O0 ], R7 v4 R- V. e
(2)串口 1
) u  ^7 I! @% z" `
% z7 u1 l) O, }' B& v1 p0 _/ u(3)K_UP 按键
- z/ {8 h4 ^4 J. T% }. d  ^2 x7 ~* l- c& [/ o' L! ~, J
    D1指示灯、K_UP 按键、串口 1 电路在前面章节都介绍过,这里不多说。D1指示灯用来提示系统正常运行,K_UP 按键用来唤醒待机模式,串口 1 用来输出提示信息。
9 P; G; \; y5 o+ K, x# N
+ X6 F# }! F$ ~8 K' i- T    所要实现的功能是:系统运行时 D1 指示灯闪烁,5 秒后进入待机模式,D1 指示灯熄灭,同时串口 printf 输出相关提示信息,通过 K_UP 按键实现唤醒。
  s" E6 q: H- W6 S" m2 _. k$ M$ x5 x4 ]( {7 z! l/ A2 J
    程序框架如下:
8 L* N% N5 \+ ^+ o
3 E# e* c2 w2 m(1)配置进入与退出待机模式$ d9 n2 ^$ s1 L7 g

" f: K8 ]$ b; i: H(2)编写主函数: Q& I9 P- N4 H! W
: o7 z1 E; h0 X. q$ U8 j. x- U+ {
    前面介绍待机模式配置步骤时,就已经讲解如何配置。下面我们打开“待机唤醒实验”工程,在 APP 工程组中可以看到添加了wkup.c文件(里面包含了待机模式驱动程序),在 StdPeriph_Driver 工程组中添加了 stm32f10x_pwr.c 库文件。电源系统管理相关操作的库函数都放在stm32f10x_pwr.c 和 stm32f10x_pwr.h 文件中,所以使用到电源系统管理就必须加入 stm32f10x_pwr.c 文件,同时还要包含对应的头文件路径。+ O% }& R+ W9 v  x! _& u4 t6 E3 e0 A( p

% A+ z1 M' w  M1 t    这里我们分析几个重要函数,其他部分程序大家可以打开工程查看。2 z4 K0 q. }. _' b" e* J
6 {- r: r% @0 Y# F# [! z/ f# ?
待机模式配置函数
4 A+ ]7 ~% N$ t$ K
7 Q% N% n' R4 F/ z3 W% P! D$ ^    要让系统进入待机模式,我们必须对它进行配置。进入待机模式代码如下:
* H# R8 I" T% H9 m6 t( n  V
. I5 V' |) F  }8 ~/ S
  1. /****************************************************************
    - A6 B" n, j; T( t+ p2 |% e; h
  2. * 函 数 名 : Enter_Standby_Mode
    " k! u: j' f% O" V+ a, K( e# X
  3. * 函数功能 : 进入待机模式
    + v' b, K& l$ H+ v  h7 f
  4. * 输 入 : 无
    # S1 e8 j2 ^& H2 B$ `0 ]/ F0 u/ W
  5. * 输 出 : 无
    . Z  f) S7 R+ \" d- M9 `
  6. *****************************************************************/! s) Z' l* w- ~+ `
  7. void Enter_Standby_Mode(void)+ R" }8 N7 S) A. Y$ _* j% B* Q
  8. {4 m# ]* h9 c' |8 L! `& X+ ]
  9.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能 PWR 外设时钟
    9 i" W: ^8 m2 z" H1 k5 z6 X& H: h
  10.   PWR_ClearFlag(PWR_FLAG_WU);//清除 Wake-up 标志, G0 ?$ W8 Y$ ^. g
  11.   PWR_WakeUpPinCmd(ENABLE);//使能唤醒管脚 使能或者失能唤醒管脚功能
    : G1 u: v  T* g: ?
  12.   PWR_EnterSTANDBYMode();//进入待机模式
    % r9 N& c7 `7 J* A7 V
  13. }
复制代码

6 f1 _# B' s& y1 f$ z: T   该函数首先使能电源PWR时钟,然后清除唤醒标志位,并使能 WK_UP管脚为唤醒方式,最后进入待机模式。这一过程在前面步骤介绍中已经提了。
( k$ R+ A* \& M- l
: `3 l) {& F+ q2 t! K/ p4 u/ v主函数
, P; [0 O% f: K. w7 t1 K. E4 b. P
7 f3 d9 w  y: H, a7 X    配置待机模式后,我们就可以编写主函数,代码如下:  c1 I! L% T0 t0 ?
. d) r6 U, k& Q: P8 ^9 h- R
  1. /****************************************************************( c8 p# s% c* Q  _9 _# a  W3 @9 T
  2. * 函 数 名 : main; r* g0 Q/ Y* H+ o' n8 ~4 b
  3. * 函数功能 : 主函数" g  O; W" I% v7 N
  4. * 输 入 : 无
    4 ?" @$ t6 ^2 J
  5. * 输 出 : 无
    ) O! }. J1 r* Z6 P0 A5 p& U" l* W
  6. *****************************************************************/$ G1 f: Q7 f. p
  7. int main()
    6 [/ U, h& e+ _# L4 I
  8. {* m  P, J- l4 R6 O* V
  9.   SysTick_Init(72);8 J% l, p1 @  J& c/ ?/ Z) A
  10.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2 组
    % `2 f3 A, ]" j
  11.   LED_Init();' K! k2 g. e3 M+ \
  12.   USART1_Init(9600);
    7 ~* c! y* c7 V
  13.   while(1)8 I/ A; p/ `" a0 o' K: m
  14.   {
    / h' F5 }: L+ P6 B
  15.     printf("time: 5\r\n");) ^1 x, [3 B4 F3 D3 G7 v# @5 u  K
  16.     led1=0;6 j( Q% D3 `, V6 B, J7 G' j; Q
  17.     delay_ms(1000); //隔 1 秒显示计数
    ' k. X5 l# v( O( q9 F
  18.     printf("time: 4\r\n");# k8 \& j% y% s, D( I9 e) A/ q
  19.     led1=1;
    1 H1 g4 `* \9 H6 ^5 t
  20.     delay_ms(1000);
    . u3 W6 a  c/ }% T% i$ E& o
  21.     printf("time: 3\r\n");
    1 _& v8 R" O! L. {) A, S
  22.     led1=0;
    % x) O' F; t# y6 @; B% \$ `. g7 @
  23.     delay_ms(1000);
    ) t9 o' N5 c2 I
  24.     printf("time: 2\r\n");
    ' j5 E6 ]1 R! y9 I- p9 g2 c
  25.     led1=1;
    1 P8 B; f4 R" @  t+ S
  26.     delay_ms(1000);
    % I' T2 E5 `5 a. T  Z
  27.     printf("time: 1\r\n");
    4 _  q% K' ?% K
  28.     led1=0;! X6 B$ u, m! B- H0 F8 W5 n' k
  29.     delay_ms(1000);
    ! M. V* M1 n0 U. R  q+ e
  30.     printf("进入系统待机模式\r\n");
    3 Q! P1 H# O0 F+ j8 S' U
  31.     Enter_Standby_Mode();3 P# D. O' C/ a7 g) \
  32.   }
    ) k9 q$ L, ~: q3 e: b
  33. }
复制代码

0 X- U# v8 v6 }+ w9 e7 q    主函数实现的功能很简单,首先调用之前编写好的硬件初始化函数,包括
. d& k$ p! K# u0 n# ]! O2 @- y: ^8 P1 n5 h, b+ E# V. T
SysTick 系统时钟,中断分组,LED 初始化等。然后进入 while 循环,每间隔一秒让 printf 输出一个信息,同时指示灯状态发生变化。倒计 5 秒钟后,调用函数 Enter_Standby_Mode进入待机模式,此时指示灯熄灭。" D  D8 x2 I1 \; n
' P% J! ^" a6 d5 u, K2 I
    将工程程序编译后下载到开发板内,可以看到系统运行时 D1 指示灯不断闪烁,5 秒钟后进入待机模式,此时 D1 指示灯熄灭。当按下 K_UP 按键或复位按键时,待机模式被唤醒,系统重新运行,同时串口打印提示信息。如果想在串口调试助手上看到输出信息,可以打开“串口调试助手”,首先勾选下标号 1 DTR 框,然后再取消勾选。这是因为此串口助手启动时会把系统复位住, 通过 DTR 状态切换下即可。然后设置好波特率等参数后,串口助手上即会收到 printf发送过来的信息。(串口助手上先勾选下标号1 DTR框,然后再取消勾选)如下图所示。+ J# d, J( W' I
/ K5 d$ b" H8 B% m
微信图片_20221011183220.jpg ( V" l* j6 L& Y* x
% z  b% c7 v) P
    实验说明:下载待机唤醒实验程序后,若使用普中 ARM 仿真器下载其他的程序会出现报警,这是因为处于低功耗模式时,所有外设时钟都已关闭,所以需要在下载程序前先复位下系统。
3 D* n' [3 R" h" X* ^- a转载自:EE时间
! v' j, N6 [! ]- f
赞 收藏 评论0 发布时间:2022-10-11 18:35

举报

0个回答

所属标签

相似技术帖

官网相关资源

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