stm32L151开发心得(一)
前言
最近结束了一个STM32L151的项目,项目基本条件就是电池供电、物联化,还有一堆通讯式的外设。我以前主要以榨干单片机性能的项目为主,这个项目刚好相反,要求低功耗,而且STM32L151我也是第一次使用,写几篇文章纪念一下。
这个项目在启动之初,照旧还是各路神仙争夺硬件配置制高点的批斗大会。对于单片机的选型,要么是NXP的LPC系列,要么是ST的L1系列,最后为减少我自己的学习量,还是选了L1系列的单片机。
STM32低功耗的三种模式
STM32,包括F1和L1系列(其他系列没研究过低功耗部分),低功耗模式有三种:
(1) 睡眠模式:Cortex-M3内核停止,外围器件保持运行状态,比如RTC一直运行。
(2) 停机模式:所有的时钟停止,电源低功耗运行。
(3)待机模式:内核断电。
三种模式我都对比功耗,待机模式应该是功耗最低的模式。但是,停机模式下,任意的外部中断都能唤醒单片机,而且唤醒后内存内的数据依然保存为停机前的值,这两点对我的项目而言非常重要,我最终的选择就是使用停机模式。
进入停机模式前,还是有很多工作要做的,包括:
(1)停止所有不含唤醒所需外部中断的外部设备的供电,诸如关闭LED、停止给电机IC、通信模块供电等等。
(2)片上外设在唤醒时用不上的全部关闭并且DeInit。
(3)把唤醒时用不上的GPIO管脚全部改为输入,这一点很重要。STM32的管脚原理图如下:
(4)如果有需要,在停机前要先设置RTC的唤醒时间。
(5)最后一步才是执行停机指令。
/*系统进行停机模式以及唤醒后的时钟操作*/
void sys_sleep_wakeup(void)
{
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; /* 关闭滴答定时器 */
portENTER_CRITICAL();
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);
//唤醒后
RCC_HSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)== RESET);
RCC_HSEConfig(RCC_HSE_OFF);
if(RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET ){
while(1);
}
/*确保系统时钟为HSI,唤醒后默认为MSI*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
while (RCC_GetSYSCLKSource() != 0x04);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 使能滴答定时器 */
portEXIT_CRITICAL();
}
void SetRtcWakeUpTime(uint32_t Second)
{
RTC_WakeUpCmd(DISABLE);
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);
RTC_SetWakeUpCounter(Second);
RTC_WakeUpCmd(ENABLE);
}
void EnterAndExitStopMode(void)
{
bsp_LedOff(1);
bsp_LedOff(2);
bsp_LedOff(3);
bsp_LedOff(4);
bsp_MoterStop();
SPI_Cmd(SPI1 , DISABLE);
SPI_DeInit(SPI1);
USART_Cmd(USART1, DISABLE);
USART_DeInit(USART1);
USART_Cmd(USART2, DISABLE);
USART_DeInit(USART2);
USART_Cmd(USART3, DISABLE);
USART_DeInit(USART3);
ADC_Cmd(ADC1,DISABLE);
ADC_DeInit(ADC1);
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_DeInit(DMA1_Channel1);
tmp=GPIOA->MODER;
GPIOA->MODER = 0xffffffff;
// GPIOB->MODER = 0xffff3f3f;
// GPIOC->MODER = 0xfcfffcff;
//设定唤醒时间(秒)
SetRtcWakeUpTime(43200);
sys_sleep_wakeup();
/*从这里开始是唤醒后的恢复函数*/
GPIOA->MODER=tmp;
bsp_InitUart(); /* 初始化串口 */
bsp_InitLed(); /* 初始LED指示灯端口 */
bsp_InitKey(); /* 初始化按键 */
bsp_InitMotor(); /* 初始化电机*/
bps_SpiInit();
bsp_InitRtc(); /* 初始化RTC */
bsp_AdcInit();
}
低功耗的硬件设计
要做到低功耗是需要软硬件互相配合的,我的项目有差不多两三个月都在折腾休眠功耗的问题,在这里给大家抛砖引玉:
(1)上述程序实质上只能保证单片机在休眠期间的功耗,至于电路板上的其他IC、电阻、电容的功耗不是单片机程序能控制的,所以首先要在电路板上实现一个单片机最小系统来做测试。具体就是电路板只贴单片机及其最小依赖的外围元器件,把程序灌入单片机,观察单片机的休眠功耗。
我的项目上,单片机的休眠功耗大概在20ua左右(因为开了几个中断,达不到手册上的水平)
(2)ADC上使用的分压电阻,一定要使用高阻值的(M级),避免ADC电路电流过大。这一点在我的项目里有深刻教训。
(3)控制电路板上外设的供电IC一定要留意其静态电流。