STM32CubeMX(stm32L151C8T6) 之RTC闹钟唤醒停机模式
基本知识介绍
1、37kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/
待机模式下自动唤醒系统
2、LSI时钟
LSI RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行,为独立看门狗和
自动唤醒单元提供时钟。 LSI时钟频率大约40kHz(在30kHz和60kHz之间)。
3、LSI RC可以通过控制/状态寄存器(RCC_CSR)里的LSION位来启动或关闭。
4、注意: 只有大容量和互联型产品可以进行LSI校准
低功耗模式
在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功
耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间
和可用的唤醒源等条件,选定一个最佳的低功耗模式。
STM32F10xxx有三种低功耗模式:
● 睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时
钟(SysTick)等仍在运行)
● 停止模式(所有的时钟都已停止)
● 待机模式(1.8V电源关闭)
停止模式
停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压
调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和
HSE RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。
在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态
进入停止模式
关于如何进入停止模式。
在停止模式下,通过设置电源控制寄存器(PWR_CR)的LPDS位使内部调节器进入低功耗模式,
能够降低更多的功耗。
如果正在进行闪存编程,直到对内存访问完成,系统才进入停止模式。
如果正在进行对APB的访问,直到对APB访问完成,系统才进入停止模式。
电源控制(PWR)
● 独立看门狗(IWDG):可通过写入看门狗的键寄存器或硬件选择来启动IWDG。一旦启动了
独立看门狗,除了系统复位,它不能再被停止。详见17.3节。
● 实时时钟(RTC):通过备份域控制寄存器 (RCC_BDCR)的RTCEN位来设置。
● 内部RC振荡器(LSI RC):通过控制/状态寄存器 (RCC_CSR)的LSION位来设置。
● 外部32.768kHz振荡器(LSE):通过备份域控制寄存器 (RCC_BDCR)的LSEON位设置。
在停止模式下,如果在进入该模式前ADC和DAC没有被关闭,那么这些外设仍然消耗电流。通
过设置寄存器ADC_CR2的ADON位和寄存器DAC_CR的ENx位为0可关闭这2个外设。
进入STOP模式,好像是手动进入的,RTC只是唤醒
待机模式
待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个
1.8V供电区域被断电。 PLL、 HSI和HSE振荡器也被断电。 SRAM和寄存器内容丢失。只有备份
的寄存器和待机电路维持供电。
可以通过设置独立的控制位,选择以下待机模式的功能:
● 独立看门狗(IWDG):可通过写入看门狗的键寄存器或硬件选择来启动IWDG。一旦启动了
独立看门狗,除了系统复位,它不能再被停止。详见17.3节。
● 实时时钟(RTC):通过备用区域控制寄存器(RCC_BDCR)的RTCEN位来设置。
● 内部RC振荡器(LSI RC):通过控制/状态寄存器(RCC_CSR)的LSION位来设置。
● 外部32.768kHz振荡器(LSE):通过备用区域控制寄存器(RCC_BDCR)的LSEON位设置。
退出待机模式
当一个外部复位(NRST引脚)、 IWDG复位、 WKUP引脚上的上升沿或RTC闹钟事件的上升沿发
生时(见图154: 简化的RTC框图),微控制器从待机模式退出。从待机唤醒后,除了电源控制/状
态寄存器(PWR_CSR)(见第4.4.2节),所有寄存器被复位。
从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚、读取复位向量等)。 电源
控制/状态寄存器(PWR_CSR)(见第4.4.2节)将会指示内核由待机状态退出
低功耗模式下的自动唤醒(AWU)
RTC可以在不需要依赖外部中断的情况下唤醒低功耗模式下的微控制器(自动唤醒模式)。 RTC提
供一个可编程的时间基数,用于周期性从停止或待机模式下唤醒。通过对备份区域控制寄存器
(RCC_BDCR)的RTCSEL[1:0]位的编程,三个RTC时钟源中的二个时钟源可以选作实现此功
能。
● 低功耗32.768kHz外部晶振(LSE)
该时钟源提供了一个低功耗且精确的时间基准。 (在典型情形下消耗小于1µA)
● 低功耗内部RC振荡器(LSI RC)
使用该时钟源,节省了一个32.768kHz晶振的成本。但是RC振荡器将少许增加电源消耗。
为了用RTC闹钟事件将系统从停止模式下唤醒,必须进行如下操作:
● 配置外部中断线17为上升沿触发。
● 配置RTC使其可产生RTC闹钟事件。(其实就是闹钟事件)
如果要从待机模式中唤醒,不必配置外部中断线17。(但是好像用的就是中断线17)
开始深入学习
这里我们选用LSI,这个项目没有加外部低速时钟,
这里我还要使能中断
选择1HZ就是1s 如果你要5s唤醒一次只需要在wake up counter 填入 (5-1)
进入睡眠模式
WFI(等待中断) WFE (是等待事件)
接下来,我们看代码
先看看生成的rtc初始化代码,,这里面不用动都可以
/**
******************************************************************************
* File Name : RTC.c
* Description : This file provides code for the configuration
* of the RTC instances.
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#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};
/** 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 = 0x8;
sTime.Minutes = 0x0;
sTime.Seconds = 0x0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x8;
sDate.Year = 0x18;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
//HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);
/** Enable the WakeUp
*/
//修改这里就可以修改唤醒时间
if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 4, RTC_WAKEUPCLOCK_CK_SPRE_16BITS) != 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);
/* 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);
/* USER CODE BEGIN RTC_MspDeInit 1 */
/* USER CODE END RTC_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
接下来就是进入停止模式
进入之前需要把所有的io口设置成模拟输入,不然即使你进了停止模式,电流还是有300ua
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0
|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_1|GPIO_PIN_10
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 |GPIO_PIN_11
|GPIO_PIN_15|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5
|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI); //直接进入停止模式,中断唤醒。然后时间到了就会唤醒
唤醒stop模式后,需要重新配置时钟,因为停止模式会关掉除低频时钟外的其他时钟,比如MSI、HSI、 HSE、 PPL这些,都会关闭。停止模式唤醒后,默认是用MSI时钟,假如你用的不是MSI,就要重新配置时钟。停止模式,就是让CPU停在那里,唤醒后,继续执行,所以配置时钟要放在停止模式函数的后面。这样就行了
SystemClock_Config();
因为上面我们把所有io的模式设置成了模拟输入,所以我们还得初始化io
//把使用到的外设io在初始化一遍
HAL_UART_MspInit(&huart1);
HAL_ADC_MspInit(&hadc);
HAL_SPI_MspInit(&hspi2);
MX_GPIO_Init();
就上面的所有设置我做到了 7ua 供大家参考
这里我还使用了nrf24l01
也把nrf24l04低功耗了,,,功耗也才7.9ua
//让他进入低功耗模式
HAL_GPIO_WritePin(NRF2401_CE_GPIOX,NRF2401_CE_PIN,0);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x02);
但是光上面的两行代码,还不够,功耗还是有350ua 带pa的
还需要设置io口
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_15|GPIO_PIN_14|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
多次尝试发现这么设置,才能把功耗降下去
这里STM32L151的软件我已经全部告知,不用谢