stm32f407待机功耗
发布网友
发布时间:2023-03-07 16:04
我来回答
共1个回答
热心网友
时间:2023-10-08 19:57
疑问
在做待机唤醒实验时,会有这样的疑问:只有进入待机模式的代码,那么唤醒是如何唤醒的?
原理
(此节主要针对待机唤醒原理进行简单介绍,可以根据自己情况自动略过)
STM32F4待机模式
在系统或电源复位以后,微控制器处于运行状态。运行状态下的 HCLK 为 CPU 提供时钟,内核执行程序代码。当 CPU不需继续运行时,可以利用多个低功耗模式来节省功耗,例如等待某个外部事件时。
STM32F4 的 3 种低功耗模式
在这三种低功耗模式中,最低功耗的是待机模式,在此模式下,最低只需要 2.2uA 左右的 电流。停机模式是次低功耗的,其典型的电流消耗在350uA 左右。最后就是睡眠模式了。
进入/退出待机模式
拓展:
在进入模式的第三步:将WUF位清零,查看寄存器PWR_CSR。
清零需要通过PWR_CR进行配置:CWUF位置1。
退出模式
根据图1及下面stm32部分时钟树可知,在待机的状态下,PLL、HSI 和 HSE 振荡器被断电、1.2V供电区别断电,可以认为只有LSI、LSE振荡器在工作,因此RTC、独立看门狗可以工作,从而进行待机唤醒。(还有WKUP上升沿、NRST复位)
代码
#include "wkup.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
//系统进入待机模式
void Sys_Enter_Standby(void)
{
while(WKUP_KD);//等待WK_UP按键松开(在有RTC中断时,必须等WK_UP松开再进入待机)
RCC_AHB1PeriphResetCmd(0X04FF,ENABLE);//复位所有IO口
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能PWR时钟
PWR_BackupAccessCmd(ENABLE);//后备区域访问使能
//这里我们就直接关闭相关RTC中断
RTC_ITConfig(RTC_IT_TS|RTC_IT_WUT|RTC_IT_ALRB|RTC_IT_ALRA,DISABLE);//关闭RTC相关中断,可能在RTC实验打开了。
RTC_ClearITPendingBit(RTC_IT_TS|RTC_IT_WUT|RTC_IT_ALRB|RTC_IT_ALRA);//清楚RTC相关中断标志位。
PWR_ClearFlag(PWR_FLAG_WU);//清除Wake-up 标志
PWR_WakeUpPinCmd(ENABLE);//设置WKUP用于唤醒
PWR_EnterSTANDBYMode();//进入待机模式
}
//检测WKUP脚的信号
//返回值1:连续按下3s以上
// 0:错误的触发
u8 Check_WKUP(void)
{
u8 t=0;
u8 tx=0;//记录松开的次数
LED0=0; //亮灯DS0
while(1)
{
if(WKUP_KD)//已经按下了
{
t++;
tx=0;
}else
{
tx++;
if(tx>3)//超过90ms内没有WKUP信号
{
LED0=1;
return 0;//错误的按键,按下次数不够
}
}
delay_ms(30);
if(t>=100)//按下超过3秒钟
{
LED0=0; //点亮DS0
return 1; //按下3s以上了
}
}
}
//中断,检测到PA0脚的一个上升沿.
//中断线0线上的中断检测
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中断标志位
if(Check_WKUP())//关机?
{
Sys_Enter_Standby(); //进入待机模式
}
}
//PA0 WKUP唤醒初始化
void WKUP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);//PA0 连接到中断线0
EXTI_InitStructure.EXTI_Line = EXTI_Line0;//LINE0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE0
EXTI_Init(&EXTI_InitStructure);//配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//外部中断0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置NVIC
//(检查是否是正常开)机
if(Check_WKUP()==0)
{
Sys_Enter_Standby();//不是开机,进入待机模式
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
此处为wkup.c代码,比较简单,这里不再进行阐述,下面主要针对上述疑问进行解释。(通过查阅资料,自行理解的逻辑)
理解
首先,开机后,从int main()函数进行初始化,进行到WKUP_Init();对PA0进行相关配置,检查是否长按开机键,没有,进入Sys_Enter_Standby()函数,在函数内最后进入待机模式:PWR_EnterSTANDBYMode()。
PWR_EnterSTANDBYMode()配置在原理中已经进行介绍,不再重复,主要针对函数内的WFI进行介绍:
WFI: wait for Interrupt 等待中断,即下一次中断发生前都在此hold住不干活
也就是说:当前大环境是正常运行状态,当运行于此处时,卡住不进行后续代码执行,相当于进行待机处理。
所以在初始化时,运行到WFI就卡在了一个地方
当按键wkup被按下时,其实已经进行了待机唤醒处理,(从按下时,灯光亮了一下就可以看出来,程序已经开始运行了,没有继续卡在原处),此时是从int main()函数第一行开始重新运行。进行到WKUP_Init();对PA0进行相关配置,检查是否长按开机键。
没有按够3s,重复上述1、2步骤;
当按键达到3s后,跳过WKUP_Init()函数中的ifCheck_WKUP()函数,程序正常运行,从而达到唤醒功能。并配置PA0中断方式。
当再次按键达到3s后,进入中断,判断有没有按够3s。时间不够,继续运行正常状态;时间达到3s,Sys_Enter_Standby()
再次进入待机模式。
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中断标志位
if(Check_WKUP())//关机?
{
Sys_Enter_Standby(); //进入待机模式
}
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8