STM32L0系列之02 RTC唤醒待机模式
前言
使用芯片:STM32L051R8T6
软件平台:KEIL V5、STM32CubeL0
库函数:HAL
一、硬件介绍
1、单片机的系统时钟为:32Mhz,由PLL时钟提供
2、PLL通过8MHz的高速外部晶振(HSE)经过8倍频,2分频后得到
3、RTC始终源选择32.768KMz的石英晶体振荡器(LSE),是的RTC在停机和待机两种低功耗模式下工作,并可以用作唤醒源;
4、如果 RTC 的时钟由 LSE 提供,则 RTC 在系统复位后仍可获得时钟并保持正常工作。
二、待机模式介绍
1、待机模式下I/O状态
在待机模式下,除以下各部分以外,所有 I/O 引脚都处于高阻态:
(1) 复位引脚
(2)唤醒引脚(WKUP1、 WKUP2、 WKUP3)
(3)以下 I/O 上的 RTC 功能(入侵、时间戳、 RTC 闹钟输出、 RTC 时钟校准输出):
– 类别 3: PC13、 PA0
– 类别 5: PC13、 PA0、 PE6
2、进入待机模式
PDDS 位 +SLEEPDEEP 位 +WFI,从 ISR 返回或 WFE
3、退出待机模式
WKUP 引脚上升沿、RTC 闹钟(闹钟 A 或闹钟 B)、 RTC 唤醒事件、RTC 入侵事件、RTC 时间戳事件、NRST 引脚外部复位、IWDG 复位
三、程序代码
1、 系统时钟配置
void SystemClock_Config(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_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
//RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
2、 RTC时钟配置
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/*##-1- Configue the RTC clock soucre ######################################*/
#ifdef RTC_CLOCK_SOURCE_LSE
/* -a- Enable LSE Oscillator */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
while(1);
}
/*##-2- Enable the RTC peripheral Clock ####################################*/
/* Enable RTC Clock */
__HAL_RCC_RTC_ENABLE();
/*##-3- Configure the NVIC for RTC Alarm ###################################*/
HAL_NVIC_SetPriority(RTC_IRQn, 0x0, 0);
HAL_NVIC_EnableIRQ(RTC_IRQn);
}
3、 RTC初始化配置配置
void SystemPower_Config(void)
{
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWREx_EnableUltraLowPower();
/* Enable the fast wake up from Ultra low power mode */
HAL_PWREx_EnableFastWakeUp();
/* Configure RTC */
RTCHandle.Instance = RTC;
/* Set the RTC time base to 1s */
/* Configure RTC prescaler and RTC data registers as follow:
- Hour Format = Format 24
- Asynch Prediv = Value according to source clock
- Synch Prediv = Value according to source clock
- OutPut = Output Disable
- OutPutPolarity = High Polarity
- OutPutType = Open Drain */
RTCHandle.Init.HourFormat = RTC_HOURFORMAT_24;
RTCHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
RTCHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
RTCHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
HAL_RTC_Init(&RTCHandle) ;
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // 清除唤醒标志
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); // 清除待机标志
HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, 8192, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
}
写程序的时候忘记配置 __HAL_RCC_PWR_CLK_ENABLE(); 导致RTC不能正常工作
4、 进入待机模式
void LowPower_enter_standby(void)
{
printf("=== Power standby ===\r\n");
HAL_Delay(50);
//UART1; 减少16uA
HAL_UART_MspDeInit(&huart);
HAL_UART_MspDeInit(&huart2);
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
__HAL_RCC_GPIOH_CLK_DISABLE();
// 禁用 调试端口 少800uA,下面2句函数功能一样!
//HAL_DBGMCU_DisableDBGStandbyMode();
HAL_DBGMCU_DBG_DisableLowPowerConfig(DBGMCU_SLEEP | DBGMCU_STOP | DBGMCU_STANDBY);
// 若需要在低功耗模式下调试程序,可以打开此函数
//HAL_DBGMCU_DBG_EnableLowPowerConfig(DBGMCU_SLEEP | DBGMCU_STOP | DBGMCU_STANDBY);
// PIN1 连接到 PWR->CR 的 PWR_FLAG_WU 标记
// 用于待机模式IO唤醒,唤醒后判断WKUP按钮状态
// WKUP pin 1 (PA00) if enabled.
// WKUP pin 2 (PC13) if enabled.
// WKUP pin 3 (PE06) if enabled, for stm32l07xxx and stm32l08xxx devices only.
// WKUP pin 3 (PA02) if enabled, for stm32l031xx devices only.
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // 清除唤醒标志
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); // 清除待机标志
/*## Setting the RTC Wake up time ########################################*/
/* RTC Wakeup Interrupt Generation:
Wakeup Time Base = (RTC_WAKEUPCLOCK_RTCCLK_DIV /(LSE or LSI))
Wakeup Time = Wakeup Time Base * WakeUpCounter
= (RTC_WAKEUPCLOCK_RTCCLK_DIV /(LSE or LSI)) * WakeUpCounter
==> WakeUpCounter = Wakeup Time / Wakeup Time Base
To configure the wake up timer to 4s the WakeUpCounter is:
RTC_WAKEUPCLOCK_RTCCLK_DIV = RTCCLK_Div16 = 16
Wakeup Time Base = 16 /(~32768Hz) = ~488.3us
Wakeup Time = ~4s = 0,410ms * WakeUpCounter
==> WakeUpCounter = 4s/488.3us = 8192 */
#ifdef __rtc_H
// 该功能可以用Cubme RTC内配置,代码可以参考rtc.c文件内
// rtc 唤醒采用LSE时钟,第一参数,计数溢出唤醒;第二参数:进行16分配
HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, 8192, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
#endif
/* Enter Standby Mode */
HAL_PWR_EnterSTANDBYMode();
}