我们知道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"
#define RTC_ENABLE (0X5679)
#define RTC_DISABLE (0X3265)
#define ADDR_RTC BKP_DR1
#define ADDR_UPDATE BKP_DR2
#define ADDR_STD BKP_DR3
#define ADDR_STD_TIME1 BKP_DR4
#define ADDR_STD_TIME2 BKP_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); //设置中断优先级分组2
delay_init(); //延时函数初始化
uart_init(9600); //串口初始化为9600
RCC_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() ;//开启备份区域写入权限 和 配置时钟)。

3204

被折叠的 条评论
为什么被折叠?



