stm32L1xx系列低功模式配置+STOP模式+RTC唤醒
低功耗介绍
本文主要介绍超低功耗STM32L151xC和STM32L152xC支持动态电压缩放,以优化其在运行模式下的功耗。
- CPU频率范围取决于动态电压缩放::
- ·Range1(VDD范围限制在1.71V-3.6V);CPU运行在32MHz·。
- Range2(全VDD范围);最大CPU频率为16MHz。
- Range3(全VDD范围);最大CPU频率限制在4MHz(仅与多速度内部RC振钟源产生)。
提供七种低功耗模式,以实现低功耗、短启动时间和可用唤醒源之间的最佳折中:
- 睡眠模式
在睡眠模式下,只停止CPU。 所有外围设备继续操作,并可以在发生中断/事件时唤醒CPU。
在16MHz的睡眠模式功耗约为1mA,所有外围设备都关闭。
- 低功耗运行模式
这种模式是通过将内部(MSI)RC振荡器设置为MSI范围0或MSI范围1时钟范围(最大131kHz)、
从SRAM或Flash存储器执行以及在低功耗模式下的内部调节器来最小化调节器的工作电流
来实现的。 在低功耗运行模式下,时钟频率和启用外围设备的数量都是有限的。
- 低功耗睡眠模式
这种模式是通过在低功耗模式下与内部电压调节器进入睡眠模式来实现的,以最小化调节
器的工作电流。 在低功耗睡眠模式下,时钟频率和启用外围设备的数量都是有限的;一个
典型的例子是有一个计时器运行在32kHz。当唤醒被事件或中断触发时,系统恢复到运行
模式,并打开调节器。
- 带RTC的stop模式
停止模式在保持RAM和寄存器内容和实时时钟的同时达到最低的功耗。 停止VCORE域中
的所有时钟,禁用PLL、MSIRC、HSIRC和HSE晶体振荡器。 LSE或LSI仍在运行。 电压
调节器处于低功耗模式。 设备可以在8µs内由任何EXTI线从停止模式唤醒。 EXTI线源可以
是16条外部线之一。 它可以是PVD输出、比较器1事件或比较器2事件(如果内部参考电压
打开),可以是RTC警报、USB唤醒、RTC篡改事件、RTC时间戳事件或RTC唤醒。
- 不带RTC的stop模式
停止模式在保留RAM和寄存器内容的同时达到最低的功耗。 所有时钟停止,PLL、MSIRC、
HSI和LSIRC、LSE和HSE晶体振荡器被禁用。 电压调节器处于低功耗模式。 设备可以在
8µs内由任何EXTI线从停止模式唤醒。 EXTI线源可以是16条外部线之一。 它可以是PVD
输出,比较器1事件或比较器2事件(如果内部参考电压打开)。 它也可以被USB唤醒。
- 带RTC的待机模式
采用待机模式,实现最低功耗和实时时钟。 内部电压调节器被关闭,以便整个VCORE域被
关闭。 锁相环、MSIRC、HSIRC和HSE晶体振荡器也被关闭。 LSE或LSI仍在运行。 进入
待机模式后,除了待机电路中的寄存器(唤醒逻辑、IWDG、RTC、LSI、LSE晶体32KOSC、
RCC_CSR)外,RAM和寄存器内容丢失)。 当外部复位(NRST引脚)、IWDG复位、三个WKUP
引脚之一的上升边缘、RTC报警(报警A或报警B)、RTC篡改事件、RTC时间戳事件或RTC
唤醒事件发生时,设备在60µs内退出待机模式。
- 不带RTC的待机模式
采用待机模式,实现最低功耗。 内部电压调节器被关闭,以便整个VCORE域被关闭。 锁相环、
MSIRC、HSI和LSIRC、HSE和LSE晶体振荡器也被关闭。 进入待机模式后,除了待机电路
中的寄存器(唤醒逻辑、IWDG、RTC、LSI、LSE晶体32KOSC、RCC_CSR)外,RAM和寄
存器内容丢失)。 当发生外部复位(NRST引脚)或三个WKUP引脚之一的上升边缘时,设备在
60µs内退出待机模式。
注意:通过进入停止或待机模式,RTC、IWDG和相应的时钟源不会自动停止。
RTC时钟配置
stm32cobemx 配置RTC,唤醒采用RTC中断唤醒,选择RTC_alarm_A闹铃中断,参数配置如下
- RTC参数配置如下:
- 打开alarm 中断
- 时钟配置有外部RTC时钟晶振LSE(32.768Khz),没有外部晶振就用内部晶振(LSE):
- 使用stmcubemx生成project.
RTC代码如下:
#include "rtc.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
RTC_HandleTypeDef hrtc;
/* RTC init function */
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
RTC_AlarmTypeDef sAlarm = {0};
rtc_time_t tim = {0};
RTC_GetTime(&tim);
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Check_RTC_BKUP */
/* USER CODE END Check_RTC_BKUP */
/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 0x0;
sTime.Minutes = 0x0;
sTime.Seconds = 0x0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x1;
sDate.Year = 0x15;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
/** Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 0x0;
sAlarm.AlarmTime.Minutes = 0x0;
sAlarm.AlarmTime.Seconds = 0x1e;
sAlarm.AlarmTime.SubSeconds = 0x0;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS |RTC_ALARMMASK_MINUTES;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 0x1;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_MspInit(&hrtc);
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
/** Enable the WakeUp
*/
if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
{
Error_Handler();
}
}
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
/* USER CODE END RTC_MspInit 0 */
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();
/* RTC interrupt Init */
HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
/* USER CODE BEGIN RTC_MspInit 1 */
/* USER CODE END RTC_MspInit 1 */
}
}
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspDeInit 0 */
/* USER CODE END RTC_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_RTC_DISABLE();
/* RTC interrupt Deinit */
HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn);
HAL_NVIC_DisableIRQ(RTC_Alarm_IRQn);
/* USER CODE BEGIN RTC_MspDeInit 1 */
/* USER CODE END RTC_MspDeInit 1 */
}
}
/**
* @brief This function get RTC time and date.
*/
void RTC_GetTime(rtc_time_t* time) //获取时间和日期
{
HAL_RTC_GetTime(&hrtc, (RTC_TimeTypeDef *)&time->Hours, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, (RTC_DateTypeDef *)&time->WeekDay, RTC_FORMAT_BIN);
}
/**
* @brief This function set RTC time and date.
*/
void RTC_SetTime(rtc_time_t* time) //设置时间和日期
{
HAL_RTC_SetTime(&hrtc, (RTC_TimeTypeDef *)&time->Hours, RTC_FORMAT_BIN);
HAL_RTC_SetDate(&hrtc, (RTC_DateTypeDef *)&time->WeekDay, RTC_FORMAT_BIN);
}
/**
* @brief This function set RTC salarm.
* @day:星期;hours:时;mintues:分;seconds:秒
*/
HAL_StatusTypeDef BSP_RTC_Set_alarm(RTC_HandleTypeDef* hrtc,uint8_t day,uint8_t hours,uint8_t mintues,uint8_t seconds)//设置闹铃时间
{
RTC_AlarmTypeDef sAlarm={0};
rtc_time_t tim = {0};
RTC_GetTime(&tim);
//设置星期
if((tim.WeekDay+day)>7)
{
sAlarm.AlarmDateWeekDay = day-(7-tim.WeekDay);
}
else
{
sAlarm.AlarmDateWeekDay = tim.WeekDay +day;
}
// 设置闹铃小时
if((tim.Hours+hours)>=24)
{
if((tim.WeekDay+1)>7)
{
sAlarm.AlarmDateWeekDay = 1;
}
else
{
sAlarm.AlarmDateWeekDay = tim.WeekDay +1;
}
sAlarm.AlarmTime.Hours = hours-(24-tim.Hours);
}
else
{
sAlarm.AlarmTime.Hours = tim.Hours+hours;
}
//设置闹铃分钟
if((tim.Minutes+mintues)>=60)
{
if((tim.Hours+1)==24)
{
if((tim.WeekDay+1)>7)
{
sAlarm.AlarmDateWeekDay = 1;
}
else
{
sAlarm.AlarmDateWeekDay = tim.WeekDay +1;
}
sAlarm.AlarmTime.Hours =0;
}
else
{
sAlarm.AlarmTime.Hours =tim.Hours+1;
}
sAlarm.AlarmTime.Minutes = mintues-(60-tim.Minutes);
}
else
{
sAlarm.AlarmTime.Minutes = tim.Minutes+mintues;
}
//设置闹铃秒钟
if((tim.Seconds +seconds)>=60)
{
if((tim.Minutes+1)==60)
{
if((tim.Hours+1)==24)
{
if((tim.WeekDay+1)>7)
{
sAlarm.AlarmDateWeekDay = 1;
}
else
{
sAlarm.AlarmDateWeekDay = tim.WeekDay +1;
}
sAlarm.AlarmTime.Hours =0;
}
else
{
sAlarm.AlarmTime.Hours =tim.Hours+1;
}
sAlarm.AlarmTime.Minutes = 0;
}
else
{
sAlarm.AlarmTime.Minutes = tim.Minutes+1;
}
sAlarm.AlarmTime.Seconds = seconds-(60-tim.Seconds);
}
else
{
sAlarm.AlarmTime.Seconds = tim.Seconds+seconds;
}
//选择闹铃A
sAlarm.Alarm = RTC_ALARM_A;
if(HAL_RTC_SetAlarm_IT(hrtc,&sAlarm,RTC_FORMAT_BIN) !=HAL_OK) //获取闹钟定时
{
Error_Handler();
}
return HAL_OK;
}
/*RTC 回调函数*/
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef* hrtc)
{
if(BSP_RTC_Set_alarm(hrtc,0,0,0,30)!=HAL_OK)//继续向后推迟秒
{
Error_Handler();
}
if(LowPowerstatus_value == DEFLAUT_MODE)
{
LowPowerstatus_value = WAIT_MDOE;
}
else
{
LowPowerstatus_value = WAKEUP_MODE;
}
printf(" HAL_RTC_AlarmAEcentCallback\r\n");
}
低功耗配置
进入低功耗之前,需要将耗电外设关闭后进入低功耗
*Low power mode config 时钟配置*/
/**
* @brief config clock lse.
* @retval None
*/
void SystemClock_Config_Stop(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL3;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/*!
* \brief
* \note 使能使用到得外设电源控制
* \retval
*/
void BSP_PWR_Enable(void)
{
BSP_RS232_PWR_ENABLE(); //关闭232供电
BSP_RS485_PWR_ENABLE(); //关闭485供电
BSP_FLASH_PWR_ENABLE(); //关闭flash供电
BSP_SD_PWR_ENABLE(); //关闭SD供电
BSP_LORA_PWR_ENABLE(); //关闭lora供电
BSP_NB_PWR_ENABLE(); //关闭NB供电
BSP_SENSOR_PWR_ENABLE();//关闭sensor供电
}
/*Low power mode config*/
/*!
* \brief
* \note 失能使用到得外设电源控制
* \retval
*/
void BSP_PWR_Disable(void)
{
BSP_RS232_PWR_DISABLE();//关闭232供电
BSP_RS485_PWR_DISABLE();//关闭485供电
BSP_FLASH_PWR_DISABLE();//关闭flash供电
BSP_SD_PWR_DISABLE(); //关闭SD供电
BSP_LORA_PWR_DISABLE(); /关闭lora供电
BSP_NB_PWR_DISABLE(); //关闭NB供电
BSP_SENSOR_PWR_DISABLE();/关闭sensor供电
}
/*!
* \brief
* \note 进入低功耗模式
* \retval
*/
void BSP_Enter_Stop_Mode(void)
{
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWREx_EnableUltraLowPower();
HAL_PWREx_DisableFastWakeUp();
//HAL_Serial_MspDeInit();
// HAL_485_MspDeInit();
// HAL_PWR_ADC1_MspDeInit();
// HAL_SDCard_MspDeInit();
// HAL_Flash_MspDeInit();
// HAL_Lora_MspDeInit();
// HAL_NB_MspDeInit();
// HAL_TIM_Base_MspDeInit(&htim2);
BSP_PWR_Disable();
BSP_RUN_LED_DISABLE();
BSP_PWR_LED_DISABLE();
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI); //进入低功耗模式
SystemClock_Config_Stop();
/*
注意:通过执行 WFI(等待中断)或WFE(等待事件)指令进入睡眠状态。(这没有进行IO模拟输出设置)
*/
}
/*!
* \brief
* \note 退出低功耗模式
* \retval
*/
void BSP_Wakeup(void)
{
if(LowPowerstatus_value == WAKEUP_MODE)
{
LowPowerstatus_value = DEFLAUT_MODE;
}
SystemClock_Config();
MX_GPIO_Init();
BSP_PWR_Enable();
MX_DMA_Init();
MX_TIM2_Init();
BSP_LED_Init();
BSP_485_init();
BSP_Serial_UART_Init();
BSP_NB_Init();
BSP_Adc_Init();
//BSP_SDCard_Init();
//BSP_Lora_Init();
BSP_Flash_Init();
//MX_RTC_Init();
BSP_W25QXX_Init();
}
mian.c
int main(void)
{
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM2_Init();
BSP_LED_Init();
BSP_485_init();
BSP_Serial_UART_Init();
BSP_NB_Init();
BSP_Adc_Init();
//BSP_SDCard_Init();
//BSP_Lora_Init();
BSP_Flash_Init();
MX_RTC_Init();
//flash init
BSP_W25QXX_Init();
// MX_FATFS_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
/*Configure GPIO pin Output Level */
// uint8_t test[] = "hello world\r\n";
// uint8_t rxtest[256] = "";
while (1)
{
/* USER CODE END WHILE */
// BSP_W25QXX_Write(test,W25Q128JV_FLASH_SIZE-1000,sizeof(test));
// HAL_Delay(500);
// BSP_W25QXX_Read(rxtest,W25Q128JV_FLASH_SIZE-1000,sizeof(test));
switch((uint8_t)LowPowerstatus_value)//状态机跳转
{
case LOWPOWER_MODE: //低功耗
BSP_Enter_Stop_Mode();
//LowPowerstatus_value=WAIT_MDOE;
break;
case WAKEUP_MODE: //唤醒
BSP_Wakeup();
SystemClock_Config();
//LowPowerstatus_value=WAIT_MDOE;
break;
case WAIT_MDOE: //等待
LowPowerstatus_value=LOWPOWER_MODE;
break;
default: //运行
BSP_system_time();
getSensorData();
HAL_Delay(2000);
break;
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
总结:本文章使用stm32L151xx系列,完成配置之后,在stop模式下耗电,由于硬件方便得耗电有些必要得,可以参考,不足得地方可以提出来.