测试完基于STM32的CC1101通信,后期需要低功耗配置。查阅关于STM32低功耗的资料,可参考
http://www.ichanging.org/stm32-power.html
,在此,也非常感谢上述博主的无私分享!!!
1.stm32低功耗
(1)进入stop模式
由于项目需要在睡眠时也保留RAM的数据,顾考虑采用stop模式以减少STM32 的功耗,进入stop的方法很简单,直接调用库函数中的 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); 此处,我选择了关闭电压转换器以进一步降低功耗,使用指令WFI进入,关于STOP进入方式的选择,可参考前文提供的博客。
(2)STM32的唤醒
由于,应用中采用发送完数据变进入休眠,并定时唤醒发送,且STOP模式下RTC正常工作,所以在本应用中采用了RTC闹钟周期中断唤醒,对于RTC的使用即配置可如下:
void RTC_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
#ifdef RCC_LSE
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
#else
RCC_LSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
{
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
#endif
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_ALR, ENABLE);
RTC_WaitForLastTask();
RTC_Alarm_Interrupt(DISABLE);
}
以上,主要注意RTC时钟的选择,选择RCC_LSE ,时间比较精确,但会产生相对长一点的唤醒时延选择;RCC_LSI,时间则不那么准确,且功耗要多一点,但产生的唤醒时延较小,具体可查阅STM32使用手册关于低功耗部分的介绍。
2.CC1101低功耗
(1)进入掉电模式
CC1101进入IDEL状态 一> 使用掉电模式(SPWD)即可。
(2)唤醒
直接操作拉低CS管脚即可。
3.调试低功耗
前期调试,只分别测试了STM32和CC1101在休眠功能上的实现,即是否能进入休眠以及是否能够成功进行唤醒,未对实际功耗进行测试(由于硬件的特殊性)。
后期第一次测试STM32+CC1101整体模块低功耗模式下功耗为4点几mA,顿时就无语了;然后果断挑断模块上的所有LED灯,再次测试,功耗直接降到1mA左右,此时虽然有所下降,但离手册上的几uA真不是一个档次的,但对于菜鸟的我此时根本不知道怎么继续减少功耗了,好吧,我只有去茫茫网络中寻找低功耗的蛛丝马迹了,果然在http://www.openedv.com/posts/list/18372.htm#116532里找到了希望,真心感谢博主的分享,于是赶紧把用到的SPI管脚以及串口管脚安装博主提供的修改,并关闭所有不用的PIN,但最终测试功耗依然未降低,这就纳闷了,为啥还是每降低呢,突然想起了不久前看过的STM32L系列低功耗的芯片,同时在有个低功耗经验师兄的提醒下,果断参考了其官方提供的超低功耗代码,并在自己的项目中进行如下操作:
在每次进入休眠前:
#关闭所有时钟以及外设(如本项目中用到的串口、SPI、timer)
#将所有I/O口改为GPIO_Mode_AIN状态
void DisableGPIO(void)
{
GPIO_InitTypeDef GPIO_InitStructure
;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC\
|RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE);
//Configure all GPIO port pins in Analog Input mode (floating input trigger OFF)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_Init(GPIOE, &GPIO_InitStructure);
//GPIOs Periph clock disable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC
|RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, DISABLE);
}
在每次唤醒后:
#开启休眠前所关闭的对应时钟以及外设
#初始化使用到的GPIO口
添加了如上的处理后,再次测试低功耗,终于让我看见了uA级别的功耗,但功耗最低时在40uA左右,与根据芯片手册提供的低功耗数据相比,还是有很大的距离,不过至此,通过软件进一步实现低功耗,我已经无法再想到其他的方法,外设该关的都已经关掉,功耗在40uA左右,目前能想到的就是硬件上功耗降降低,毕竟测试平台的硬件是自己同学做的,对于硬件上的功耗降低超出了我的工作范围,对于软件上的低功耗也只能到这儿,如果大牛们有更多在软件上实现低功耗的建议,也非常希望给我留言,将感激不尽,毕竟没有做到理想的低功耗,还是有很多遗憾。
对于STM32和CC1101低功耗的联合使用,无非是先让CC1101休眠,接着关闭外设,然后STM32进入休眠;中断唤醒STM32后,开启所有外设,然后再唤醒CC1101就OK了。
个人愚见:
(1) 在STM32与其他设备(例如本文的CC1101)联合休眠时,在休眠前,将所有GPIO管脚配置为GPIO_Mode_AIN状态,并不是每一个项目都合适,例如有的外设会应为其与MCU的通信的管脚被配置为GPIO_Mode_AIN状态而被唤醒,在此种情况下,我们需要保留该进入休眠外设用到GPIO,只将其他GPIO口配置为GPIO_Mode_AIN状态。
(2)很多论坛中对STM32的唤醒时间有很多探讨,觉得RTC定时唤醒后,在去开启外设、时钟以及初始化GPIO口会产生一些列时延,本文在初始化GPIO时,直接将该函数放到了STM32醒来后,重新配置系统时钟时的等待时钟稳定的while语句前,最后再开启GPIO时钟,这样可一定程度上减少时延。