历史上的今天
返回首页

历史上的今天

今天是:2024年10月29日(星期二)

正在发生

2021年10月29日 | stm32专题三十二:stm32功耗模式

2021-10-29 来源:eefocus

stm32功耗模式       


       按功耗由高到低排列,STM32 具有运行、睡眠、停止和待机四种工作模式。上电复位后 STM32处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式降低功耗,这三种模式中,电源消耗不同、唤醒时间不同、唤醒源不同,用户需要根据应用需求,选择最佳的低功耗模式。三种低功耗的模式说明见下表。


睡眠模式下,任何中断都可以唤醒内核,外部 / 内部高速时钟保持打开,调压器保持打开,因此,内核只要被唤醒,就能马上正常的执行程序(优点:响应速度快;缺点:功耗比较大);


停止模式下,HSE和HSI被关闭,调压器可选开启或低功耗模式(若选为低功耗模式,则还需要加上调压器从低功耗切换至正常模式下的时间),外部中断唤醒内核。当内核被唤醒时,需要重新配置系统时钟使用外部 HSE 且 PLL 正常倍频(System_Init函数),这个过程就会消耗一定时间;否则程序会直接使用 HSI(不倍频) = 8MHz 作为系统时钟,此时系统运行的相当慢,一些对时钟要求较高的函数配置会无法运行(优点:工号较小;缺点:需要重新配置系统时钟,响应速度慢);


待机模式下,整个1.8V供电区域被关闭,调压器被关闭,只能特定方式唤醒。唤醒之后程序从最开始(启动文件)执行(优点:功耗最低;缺点,每次都是复位执行);

低功耗模式的区别


关于睡眠模式 停止模式 待机模式 的区别,可以分析如下代码:


while(1)

  {

/*********执行任务***************************/

printf("rn STM32正常运行,亮绿灯rn");

LED_GREEN;

Delay(0x3FFFFF);

/*****任务执行完毕,进入睡眠降低功耗***********/

printf("rn 进入睡眠模式,按KEY1或KEY2按键可唤醒rn");

 

//使用红灯指示,进入睡眠状态

LED_RED;

//进入睡眠模式

__WFI(); //WFI指令进入睡眠

//等待中断唤醒  K1或K2按键中断

/***被唤醒,亮蓝灯指示***/

LED_BLUE;

Delay(0x1FFFFF);

printf("rn 已退出睡眠模式rn");

//继续执行while循环

  }

}


睡眠 模式


       当程序上电开始执行时,会一直执行到LED_RED,然后调用__WFI()指令进入睡眠模式,此时,内核停止工作,程序不再往下执行。而当中断来临时,内核被唤醒,程序继续执行while循环,当下一次执行到__WFI()时,再次进入睡眠状态,等待唤醒。


停止 模式


        当程序上电开始执行时,会一直执行到LED_RED,然后调用__WFI()指令进入睡眠模式,此时,内核停止工作,程序不再往下执行。而当中断来临时,内核被唤醒,等待系统时钟配置成功(消耗时间),程序继续执行while循环,当下一次执行到__WFI()时,再次进入睡眠状态,等待唤醒。


待机模式


       一旦进入待机模式,整个1.8V供电区域(内核 NVIC全部断电),只能通过几种特定的方式唤醒,此时,程序将从头开始执行(从启动文件那里开始执行)。


3种模式的详细描述和寄存器配置


1 睡眠模式(任意中断唤醒:systick中断,串口中断等...)

内核寄存器配置说明如下:

关于立即睡眠和退出后睡眠的区别(中文参考手册):

2 停止模式(外部中断唤醒),开启后会默认使用HSI作为系统时钟,通常我们为确保正常使用,还要重新开启HSE:

相关的寄存器配置:

电源控制寄存器,配置停止模式(正常 or 低功耗):


3 待机模式(WKUP[PA0引脚]、RTC、复位、IWDG看门狗),很类似于直接掉电:


相关的寄存器配置:

电源管理库函数


1 配置PVD检测函数 PWR_PVDLevelConfig ,其实就是写入PWR_CR寄存器的这几位:


标准库函数源码:


/**

  * @brief  Configures the voltage threshold detected by the Power Voltage Detector(PVD).

  * @param  PWR_PVDLevel: specifies the PVD detection level

  *   This parameter can be one of the following values:

  *     @arg PWR_PVDLevel_2V2: PVD detection level set to 2.2V

  *     @arg PWR_PVDLevel_2V3: PVD detection level set to 2.3V

  *     @arg PWR_PVDLevel_2V4: PVD detection level set to 2.4V

  *     @arg PWR_PVDLevel_2V5: PVD detection level set to 2.5V

  *     @arg PWR_PVDLevel_2V6: PVD detection level set to 2.6V

  *     @arg PWR_PVDLevel_2V7: PVD detection level set to 2.7V

  *     @arg PWR_PVDLevel_2V8: PVD detection level set to 2.8V

  *     @arg PWR_PVDLevel_2V9: PVD detection level set to 2.9V

  * @retval None

  */

void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel)

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

  assert_param(IS_PWR_PVD_LEVEL(PWR_PVDLevel));

  tmpreg = PWR->CR;

  /* Clear PLS[7:5] bits */

  tmpreg &= CR_PLS_MASK;

  /* Set PLS[7:5] bits according to PWR_PVDLevel value */

  tmpreg |= PWR_PVDLevel;

  /* Store the new value */

  PWR->CR = tmpreg;

}

2 WFI 与 WFE 命令:


/* ###################  Compiler specific Intrinsics  ########################### */

 

#if defined ( __CC_ARM   ) /*------------------RealView Compiler -----------------*/

/* ARM armcc specific functions */

 

#define __enable_fault_irq                __enable_fiq

#define __disable_fault_irq               __disable_fiq

 

#define __NOP                             __nop

#define __WFI                             __wfi

#define __WFE                             __wfe

#define __SEV                             __sev

#define __ISB()                           __isb(0)

#define __DSB()                           __dsb(0)

#define __DMB()                           __dmb(0)

#define __REV                             __rev

#define __RBIT                            __rbit

#define __LDREXB(ptr)                     ((unsigned char ) __ldrex(ptr))

#define __LDREXH(ptr)                     ((unsigned short) __ldrex(ptr))

#define __LDREXW(ptr)                     ((unsigned int  ) __ldrex(ptr))

#define __STREXB(value, ptr)              __strex(value, ptr)

#define __STREXH(value, ptr)              __strex(value, ptr)

#define __STREXW(value, ptr)              __strex(value, ptr)



3 进入停止模式


配置PWR_CR寄存器的这两个位,以及SLEEPDEEP位。

/**

  * @brief  Enters STOP mode.

  * @param  PWR_Regulator: specifies the regulator state in STOP mode.

  *   This parameter can be one of the following values:

  *     @arg PWR_Regulator_ON: STOP mode with regulator ON

  *     @arg PWR_Regulator_LowPower: STOP mode with regulator in low power mode

  * @param  PWR_STOPEntry: specifies if STOP mode in entered with WFI or WFE instruction.

  *   This parameter can be one of the following values:

  *     @arg PWR_STOPEntry_WFI: enter STOP mode with WFI instruction

  *     @arg PWR_STOPEntry_WFE: enter STOP mode with WFE instruction

  * @retval None

  */

void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

  assert_param(IS_PWR_REGULATOR(PWR_Regulator));

  assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));

  

  /* Select the regulator state in STOP mode ---------------------------------*/

  tmpreg = PWR->CR;

  /* Clear PDDS and LPDS bits */

  tmpreg &= CR_DS_MASK;

  /* Set LPDS bit according to PWR_Regulator value */

  tmpreg |= PWR_Regulator;

  /* Store the new value */

  PWR->CR = tmpreg;

  /* Set SLEEPDEEP bit of Cortex System Control Register */

  SCB->SCR |= SCB_SCR_SLEEPDEEP;

  

  /* Select STOP mode entry --------------------------------------------------*/

  if(PWR_STOPEntry == PWR_STOPEntry_WFI)

  {   

    /* Request Wait For Interrupt */

    __WFI();

  }

  else

  {

    /* Request Wait For Event */

    __WFE();

  }

  

  /* 以下的程序是当重新唤醒时才执行的,清除 SLEEPDEEP 位的状态 */

  SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);  

}

在执行最后一句代码前,系统由于调用了__WFI 或 __WFE,已经进入了停止模式,因此,这句清除SLEEPDEEP 位并不会执行。而当内核重新被唤醒时,才会清除SLEEPDEEP位,方便使用。


SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); 

4 进入待机模式(很简单):


/**

  * @brief  Enters STANDBY mode.

  * @param  None

  * @retval None

  */

void PWR_EnterSTANDBYMode(void)

{

  /* Clear Wake-up flag */

  PWR->CR |= PWR_CR_CWUF;

  /* Select STANDBY mode */

  PWR->CR |= PWR_CR_PDDS;

  /* Set SLEEPDEEP bit of Cortex System Control Register */

  SCB->SCR |= SCB_SCR_SLEEPDEEP;

/* This option is used to ensure that store operations are completed */

#if defined ( __CC_ARM   )

  __force_stores();

#endif

  /* Request Wait For Interrupt */

  __WFI();

}

PVD电源监控


       实际上,PVD监测的是VDD的电压,也就是stm32的供电电压。当我们调节(降低VDD电压)时,PVD一旦监测到小于设置的阈值,就会产生PVD中断。

标准库中,关于PVD的函数:


1 监测电压等级配置


/**

  * @brief  Configures the voltage threshold detected by the Power Voltage Detector(PVD).

  * @param  PWR_PVDLevel: specifies the PVD detection level

  *   This parameter can be one of the following values:

  *     @arg PWR_PVDLevel_2V2: PVD detection level set to 2.2V

  *     @arg PWR_PVDLevel_2V3: PVD detection level set to 2.3V

  *     @arg PWR_PVDLevel_2V4: PVD detection level set to 2.4V

  *     @arg PWR_PVDLevel_2V5: PVD detection level set to 2.5V

  *     @arg PWR_PVDLevel_2V6: PVD detection level set to 2.6V

  *     @arg PWR_PVDLevel_2V7: PVD detection level set to 2.7V

  *     @arg PWR_PVDLevel_2V8: PVD detection level set to 2.8V

  *     @arg PWR_PVDLevel_2V9: PVD detection level set to 2.9V

  * @retval None

  */

void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel)

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

  assert_param(IS_PWR_PVD_LEVEL(PWR_PVDLevel));

  tmpreg = PWR->CR;

  /* Clear PLS[7:5] bits */

  tmpreg &= CR_PLS_MASK;

  /* Set PLS[7:5] bits according to PWR_PVDLevel value */

  tmpreg |= PWR_PVDLevel;

  /* Store the new value */

  PWR->CR = tmpreg;

}

2 PVD监测使能函数


/**

  * @brief  Enables or disables the Power Voltage Detector(PVD).

  * @param  NewState: new state of the PVD.

  *   This parameter can be: ENABLE or DISABLE.

  * @retval None

  */

void PWR_PVDCmd(FunctionalState NewState)

{

  /* Check the parameters */

  assert_param(IS_FUNCTIONAL_STATE(NewState));

  *(__IO uint32_t *) CR_PVDE_BB = (uint32_t)NewState;

}

整个配置的过程其实很简单:


/**

  * @brief  配置PVD.

  * @param  None

  * @retval None

  */

void PVD_Config(void)

推荐阅读

史海拾趣

FUJITSU(富士通)公司的发展小趣事

富士通(Fujitsu)在电子行业的五个发展故事

故事一:从电话交换机到ICT巨头的起步

富士通的故事始于1935年,当时它作为一家电信设备制造商在日本成立,首款产品是电话交换机,这标志着富士通成为日本首家生产此类设备的公司。这一里程碑不仅奠定了富士通在通信领域的基础,也为其后续在信息技术(IT)和通信技术(CT)领域的多元化发展铺平了道路。随着技术的不断进步,富士通逐渐扩展其业务范围,从单一的通信设备制造商转变为全球领先的ICT企业。

故事二:FACOM 100——日本首台计算机的诞生

1954年,富士通成功研发出日本第一台中继式自动计算机FACOM 100,这一成就不仅标志着富士通在计算机领域的突破,也为其后续在计算机硬件和软件领域的深入发展奠定了坚实基础。FACOM 100的问世,不仅提升了富士通在业界的知名度,也推动了日本乃至全球计算机技术的快速发展。

故事三:全球化战略的推进

自20世纪70年代以来,富士通积极实施全球化战略,通过在全球各地设立研发中心、生产基地和销售网络,不断拓展其国际业务。在中国,富士通自1979年起便开始了其业务布局,从最初的设备销售到后来的技术研发、生产制造和解决方案提供,富士通在中国的发展历程见证了其全球化战略的深入实施。如今,富士通的产品和服务已遍布全球80多个国家和地区,服务超过百万家客户。

故事四:云计算与数字化转型的引领

进入21世纪,随着云计算和数字化转型的兴起,富士通迅速调整战略方向,加大在云计算领域的投入。通过提供全方位的云计算服务和解决方案,富士通帮助客户实现业务的数字化转型和升级。同时,富士通还积极与微软等国际巨头合作,共同开拓全球云计算市场,进一步巩固了其在ICT行业的领先地位。

故事五:技术创新与可持续发展

富士通始终将技术创新作为企业发展的核心驱动力。近年来,富士通在人工智能、物联网、大数据等新兴技术领域取得了显著成就,推出了一系列具有自主知识产权的创新产品和解决方案。同时,富士通还积极履行企业社会责任,通过提供绿色、环保的ICT产品和服务,推动社会的可持续发展。这些努力不仅提升了富士通在全球市场的竞争力,也为其赢得了广泛的赞誉和尊重。

Gamma Microelectronics ( APM )公司的发展小趣事

G24i的成立可以追溯到2006年,它自称是世界上首家生产商业化应用等级DSSC的公司。公司的技术根基源自瑞士洛桑联邦理工学院的M. Gratzel团队,该团队是DSSC技术的先驱。G24i由美国Kanorka Technologies公司投资,而Kanorka则得到了美国军方的资助。这一强大的技术背景为G24i的商业化之路奠定了坚实的基础。公司成立后不久,便致力于将实验室级别的DSSC技术推向市场,开启了其商业化探索的征程。

博通集成(BEKEN)公司的发展小趣事

博通集成自成立以来,始终致力于无线通讯技术的研发与创新。公司团队不断攻克技术难关,推出了多款具有市场竞争力的产品。其中,公司自主研发的首款Wi-Fi宽带收发样片在2015年成功通过测试,这一技术突破为公司在无线通讯领域的发展奠定了坚实基础。此后,公司不断推出创新产品,涵盖无线数传芯片和无线音频芯片等多个领域,广泛应用于智能家居、智能交通等领域。

EMBEST公司的发展小趣事

随着国内市场的逐步稳固,EMBEST开始寻求更广阔的发展空间。XXXX年,EMBEST的开发工具成功进入国际市场,并获得了多家芯片公司的认可,成为他们的第三方工具伙伴。这一举措不仅提升了EMBEST的品牌影响力,也为其带来了更多的商业机会。EMBEST凭借过硬的技术实力和优质的服务,逐渐在国际市场上崭露头角。

AnalogicTech公司的发展小趣事

为了进一步扩大市场份额,AnalogicTech积极寻求与全球范围内的合作伙伴建立战略合作关系。公司通过参加国际电子展会、建立海外销售网络等方式,成功将产品推向全球市场。同时,AnalogicTech还加大了对亚洲市场的投入,在香港等地设立了分支机构,进一步提升了公司在全球市场的竞争力。

Box Enclosures公司的发展小趣事

在市场竞争日益激烈的背景下,Box Enclosures公司意识到单打独斗难以取得更大的突破。于是,公司开始积极寻求与其他企业的战略合作。通过与一家知名电子设备制造商的合作,Box Enclosures成功将其产品集成到对方的产品中,共同开拓市场。这种合作不仅提升了公司的知名度,还为其带来了更多的商业机会和合作伙伴。

问答坊 | AI 解惑

C++入门

入门级教程,写的很好,不怕你是初学者…

查看全部问答>

历年全国大赛试题集

本帖最后由 paulhyde 于 2014-9-15 09:15 编辑 这是为了备战新一届全国电子设计大赛,收集到得题目。 大家可以参考一下!  …

查看全部问答>

2个并排的轮子的怪异摩托车

信任你没有见过这样的摩托车,从侧面看就像是一个轮子,其实它有2个并排的轮子,左右平衡容易控制一些,但这样的怪异摩托车前后平衡感到还是很难节制的,看到这个摩托车的第一感到就是担心在快速行进当中,因为平衡没有控制好而向前栽倒。这款叫Uno ...…

查看全部问答>

wince5.0 USB HOST 只能插入两个U盘,怀疑是wince驱动的问题,希望探讨一下!

    如题,我在wince5.0下接两个U盘可以正常工作,但接第三个U盘时会跳出输入驱动名称的对话框,而且供电电流是足够的,现在在研究wince的USB HOST驱动,还没发现什么问题,希望有研究过的可以指点一下!…

查看全部问答>

抢答:51里怎样用pwm产生正弦信号?

51里怎样用pwm产生正弦信号呢?…

查看全部问答>

.NET Compact Framework

.NET Compact Framework的经典解释.…

查看全部问答>

atr711只接32.768K晶振可以工作吗

                                 如题…

查看全部问答>

STM32的任何端口都可以作为外部中断输入么?

                                 比如说像51里的INT0,在STM32里面这样的中断引脚是怎么定位的?另外最多可以有多少个外部中断输入?…

查看全部问答>

请不要做浮躁的嵌入式工程师

1. 不要看到别人的回复,第一句话就说:给个代码吧!你应该想想为什么。当你自己想出来再参考别人的提示,你就知道自己和别人思路的差异。 2. 初学者请不要看太多的书那会误人子弟的。先找一本好书系统的学习。很多人用了很久都是只对部分功能熟悉 ...…

查看全部问答>

今天试着申请了下“金刚狼”

还是XMS的标号。 试着申请MSP430FR5969,但是可能是样品库还没有货的原因不能添加 …

查看全部问答>