STM32三种低功耗模式的代码分享

2019-07-20 04:55发布

搞了快两天的32的低功耗模式,刚学的时候很多东西都是一知半解,看了原子哥的停止模式的例程,想把另外两种的模式也做一下,在论坛上搜索了下关于停止和睡眠模式的资料,资料并不多而且也有一些人遇到和我差不多的问题,于是乎就有了接下来一天的摸索,且听我慢慢道来(我是菜鸟如果有什么不对的地方,请各位大神指正,老是在论坛上索取,所以希望自己也能分享的东西)

1.睡眠模式
首先打开STM32的中文参考手册到P40找到睡眠模式,从这里就知道要进入睡眠模式要设置SLEEPNOEXIT来决定是马上睡眠还是等待事件结束后睡眠这个还是要比停止模式操作稍微简单,这里就取SLEEP-NOW模式吧,那么如何找到并设置SLEEPONEXIT这一位呢,原子哥的例程上有讲并且它是在固件库中的函数PWR_EnterSTANDBYMode();中操作了SLEEPONEXIT,那是不是固件库中也应该有睡眠模式的函数呢,我查看了下好像没有,于是我就追踪停止模式函数PWR_EnterSTANDBYMode()的发现这个函数是通过这一句  SCB->SCR |=SCB_SCR_SLEEPDEEP;来操作的SCB是在内核中的寄存器于是在M3权威指南中我找到
我们只要清除SCR中的第二位然后执行WFI命令就可以让芯片进入睡眠模式,于是可以自己编写一个Sys_Sleepy函数如下 [mw_shl_code=c,true]void Sys_Sleepy(void) { SCB->SCR |=0X00; #if defined ( __CC_ARM ) //这个我用jtag仿真发现停止函数也有执 行所以也加了上去 还请大神指教这句话的意思 __force_stores(); #endif /* Request Wait For Interrupt */ __WFI(); }[/mw_shl_code] 为了降低功耗我们最好在进入待机模式前尽量把所有开启的外设全部关闭
接下来就是要退出睡眠模式。在32手册找到  可以看到如果是执行WFI命令按这里所说是只要有一个中断就能把处理器唤醒,但是实际上我实验的时候没能唤醒,后来我在M3权威指南中P182找到这样一句话  幡然醒悟,我当时是用一个IO来控制处理器进出睡眠模式的,而这里是要求唤醒时要比当前优先级高,至于BASEPRI是 中断屏蔽寄存器默认的优先级是低的。所以我又开了个中断果然优先级比之前的优先级高时候就唤醒了。为了用一个IO来控制进出睡眠我在中断中写了这个代码 [mw_shl_code=c,true]void EXTI2_IRQHandler(void) { EXTI_ClearITPendingBit(EXTI_Line2); // 清除LINE10上的中断标志位 SCB->SCR |=SCB_SCR_SEVONPEND; // Sys_Enter_Sys_Sleepy(); if(E2==0)//关机? { delay_ms(10000); if(E2==0) { LED0=0; Sys_Enter_Sys_Sleepy(); } } else LED1=0; } [/mw_shl_code] 本来时想用按键延时检测来选择是唤醒还是睡眠,结果吧延时加到1000还是进入睡眠,想了下这可能是因为中断保护现场的原因吧,具体详细的怎么保护不清楚,在什么地方有讲中断保护现场的,今天有点晚了就不深究这个了,还请大神们指教

再来说说第二执行WFE唤醒,这个我没有遇到问题是能唤醒的我想如果没有唤醒的话是因为没有使能SEVONPEND位可以加一句SCB->SCR |=SCB_SCR_SEVONPEND(0x10),NVIC通道挂起位是当有一个中断在执行这时候来了一个比这个中断优先级低的中断,所以这个中断不被执行,而在NVIC中被挂起,我想没这么巧会这样,不过要怎么清除呢这个我还没弄懂32中断确实有点杂,还请大神指教,感激不敬!  并且睡眠模式和停止模式不一样进入睡眠模式所有IO保持原来的状态

2.停止模式
上图

可以看到停止模式和待机模式唯一的不同就是PDDS位设置相反,然后就是选择是否要开启电压调节器,并且这个和停止模式一样在固件库中有函数可以调用,进入停止模式还是简单的,接下来是退出同样也是只要一个中断都可以唤醒处理器,和前面差不多。论坛上说唤醒后处理器速度很慢,唤醒后我也遇到这个问题led闪烁的频率变慢很多,
就是说唤醒后变成内部时钟,所以我们要做的是在唤醒后就把时钟想复位那样的初始化一遍,于是我想用已经有的系统初始化函数,来初始化时钟来达到目的,所以要做的是在唤醒处理器的那个中断服务函数中加入初始化函数,我照搬system_stm32x.c中的函数写了一下函数 [mw_shl_code=c,true]void clock(void) { __IO uint32_t StartUpCounter = 0, HSEStatus = 0; /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ /* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON); /* Wait till HSE is ready and if Time out is reached exit */ do { HSEStatus = RCC->CR & RCC_CR_HSERDY; StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); if ((RCC->CR & RCC_CR_HSERDY) != RESET) { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { /* Enable Prefetch Buffer */ FLASH->ACR |= FLASH_ACR_PRFTBE; /* Flash 2 wait state */ FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); /* Enable PLL */ RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Select PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* Wait till PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { } } else { /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */ } } [/mw_shl_code]
因为我是一只用库函数写的这里有些寄存器看不懂不过还好能达到目的,看来要真正的掌握32,对寄存器操作也要了解,我这样的菜鸟是心有余力不足,最后附上我用写的停止和睡眠模式代码,因为是直接改原子哥的代码的有些地方注释是没有改的,我是通过LED灯来反应现象的.
眠模式如何实现一个IO来控制进出随眠模式,NVIC的通道挂起位如何清除?这两个问题为能搞清除希望各位能给点提示,以上所说肯定有不对的地方还请大神们批评指正。
3.大家来谈谈低功耗的应用吧,在论坛上我看到http://www.openedv.com/posts/list/18372.htm这篇帖子非常好,让还是学生的我感觉任重道远啊,低功耗还是很有搞头的,这篇贴学到了好多东西就比如不用的IO不要不管,往往他也会耗电
最后顶下原子哥
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。