我们知道stm32f103有很好的低功耗模式,可以使用rtc的闹钟用于定时的唤醒。但很难在IWDOG的使用情况下,设置低功耗。我为了处理这个问题,我们需要设置掉电标志位,因为stm32复位重启后看门狗会失效,在配置看门狗前去检查低功耗标志是否使能,如果使能则直接进入低功耗。从而避免了看门狗的重启困扰。BKP区域用于掉电标志非常安全合适。
直接上代码(测试板子stm32f103)
首先是rtc.c文件,包含掉电备用数据读写(BKP区域用作设置掉电标志位最合适了,有20个16位寄存器),RTC时钟初始化函数,时间设置函数,开机检测是否闹钟唤醒函数,配置开启低功耗模式函数
rtc.c文件
#include "rtc.h"#define PWR_BackupAccessCmd_ENABLE() {RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE); PWR_BackupAccessCmd(ENABLE);}//开启备份区域写入权限和 配置时钟#define PWR_BackupAccessCmd_DISABLE() {PWR_BackupAccessCmd(DISABLE);}//关闭备份区域写入权限/* 写BKP寄存器 */void PWR_BackupAccessCmd_WRITE(uint16_t BKP_DR, uint16_t DataA){PWR_BackupAccessCmd_ENABLE();//开启备份区域写入权限BKP_WriteBackupRegister(BKP_DR, DataA);PWR_BackupAccessCmd_DISABLE();//关闭备份区域写入权限}/* RTC时钟初始化函数 */void RCC_Config(void){//时间配置函数PWR_BackupAccessCmd_ENABLE();//开启备份区域写入权限if(BKP_ReadBackupRegister(ADDR_RTC) != RTC_ENABLE){//检查用户标志/* 配置晶振 */RCC_LSEConfig(RCC_LSE_ON);/* 使能LSE */ while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {} /* 等待启动完成 */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);/* 将 RTC时钟设置为LSE这个32.768KHZ的晶振*/ /* 同步数据 */RCC_RTCCLKCmd(ENABLE);/* 使能RTC Clock */ RTC_WaitForSynchro();/* 等待同步 */ RTC_WaitForLastTask();/* 等待对RTC寄存器最后的写操作完成*/ /* 配置分频 */RTC_SetPrescaler(32767); //设置了预分频值: 设置RTC时钟周期为1s *//* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)RTC_WaitForLastTask(); /* 配置标识 */BKP_WriteBackupRegister(ADDR_RTC, RTC_ENABLE);}else{/* 同步数据 */RTC_WaitForSynchro();/* 等待同步 */ RTC_WaitForLastTask();/* 等待对RTC寄存器最后的写操作完成*/ }PWR_BackupAccessCmd_DISABLE();//关闭备份区域写入权限}/* 时间设置函数 */void RTC_Set(uint32_t time){if(BKP_ReadBackupRegister(ADDR_RTC) == RTC_ENABLE){//检查用户标志PWR_BackupAccessCmd_ENABLE();//开启备份区域写入权限RTC_SetCounter(time); //设置RTC初始值RTC_WaitForLastTask();PWR_BackupAccessCmd_DISABLE();//关闭备份区域写入权限}}/* 开机检测是否闹钟唤醒 */void STD_RESET_START(void){if(BKP_ReadBackupRegister(ADDR_RTC) == RTC_ENABLE&&BKP_ReadBackupRegister(ADDR_STD) == RTC_ENABLE){u32 STD_time = (BKP_ReadBackupRegister(ADDR_STD_TIME1)<<16)+BKP_ReadBackupRegister(ADDR_STD_TIME2);//获取STD时间if(STD_time > (RTC_GetCounter()+5) && GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0){PWR_BackupAccessCmd_ENABLE();//开启备份区域写入权限/* 中断配置 */RTC_ITConfig(RTC_IT_ALR, ENABLE);RTC_WaitForLastTask();/* 闹钟时间配置 */RTC_SetAlarm(STD_time);RTC_WaitForLastTask();PWR_BackupAccessCmd_DISABLE();//关闭备份区域写入权限/* 进入低功耗 */PWR_WakeUpPinCmd(ENABLE);RCC_APB2PeriphResetCmd(0X01FC,DISABLE); //复位IO口时钟,可选择RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外设时钟PWR_EnterSTANDBYMode();}PWR_BackupAccessCmd_WRITE(ADDR_STD,RTC_DISABLE);//配置关闭低功耗模式}}/* 配置开启低功耗模式 */void RTC_ALARM_Set(uint32_t time){if(BKP_ReadBackupRegister(ADDR_RTC) == RTC_ENABLE){//检查用户标志PWR_BackupAccessCmd_WRITE(ADDR_STD_TIME1,time>>16);//PWR_BackupAccessCmd_WRITE(ADDR_STD_TIME2,time&0x0000FFFF);//PWR_BackupAccessCmd_WRITE(ADDR_STD,RTC_ENABLE);//}}
头文件rtc.h
#ifndef __RTC_H#define __RTC_H#include "stm32f10x.h"#defineRTC_ENABLE(0X5679)#defineRTC_DISABLE(0X3265)#defineADDR_RTCBKP_DR1#defineADDR_UPDATEBKP_DR2#defineADDR_STDBKP_DR3#defineADDR_STD_TIME1BKP_DR4#defineADDR_STD_TIME2BKP_DR5/* *** */#define RTC_Get(x) RTC_GetCounter(x)//时间获取函数void RTC_Set(uint32_t time);//时间设置函数void RTC_ALARM_Set(uint32_t time);//闹钟设置函数void RCC_Config(void);//时间初始化函数void STD_RESET_START(void);//低功耗模式检测函数/* BKP区域 */void PWR_BackupAccessCmd_WRITE(uint16_t BKP_DR, uint16_t Data);#endif
下面是测试用main函数
#include "led.h"#include "delay.h"#include "sys.h"#include "usart.h"#include "rtc.h"int main(void){NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组2delay_init(); //延时函数初始化 uart_init(9600); //串口初始化为9600RCC_Config();//时钟初始化函数;STD_RESET_START();//判断是否是低功耗状态while(1){u32 sss = RTC_Get();printf("rtc= 0x%x\r\n",sss);RTC_ALARM_Set(sss+20);delay_ms(1000); };}
配合weak_up引脚测试唤醒,可以有很好的效果
注意:在每次(PWR_BackupAccessCmd_DISABLE();//关闭备份区域写入权限)后
都需要重新开启时钟,在这里写成宏定义
( PWR_BackupAccessCmd_ENABLE() ;//开启备份区域写入权限 和 配置时钟)。