????????最近遇到stm32f系列看门狗不能关闭的事情,需要开启RTC闹钟定时唤醒喂狗。这里给RTC闹钟打一个标签把,我设置为每20秒开启一次闹钟。
?首先是HAL库的配置
配置时钟:
选择下载方式
选择时钟和选择闹钟A
?闹钟配置
开启中断
?设置时钟
?我的是 外部晶振为25MHz
项目文件设置
?完成之后生成工程
我用的是STM32F4的芯片,RTC的时间都在HAL里面设置完成之后生成。
生成的代码段
时间日期设置
//闹钟和时间结构体用全局变量设置
RTC_AlarmTypeDef sAlarm = {0};
RTC_TimeTypeDef sTime = {0};
/* USER CODE END 0 */
RTC_HandleTypeDef hrtc;
/* RTC init function */
void MX_RTC_Init(void)
{
/* USER CODE BEGIN RTC_Init 0 */
HAL_LockTypeDef rtc_time={0};
/* USER CODE END RTC_Init 0 */
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
RTC_AlarmTypeDef sAlarm = {0};
/* USER CODE BEGIN RTC_Init 1 */
/* USER CODE END RTC_Init 1 */
/** 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 = 12;
sTime.Minutes = 12;
sTime.Seconds = 0;
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 = 1;
sDate.Year = 0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
闹钟和时间结构体用全局变量设置
闹钟时间设置
/** Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 12;
sAlarm.AlarmTime.Minutes = 12;
sAlarm.AlarmTime.Seconds = 10;
sAlarm.AlarmTime.SubSeconds = 5;
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 = 1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
闹钟的配置有不懂的可以看下面的注释
/**
* @brief RTC Alarm structure definition
*/
typedef struct
{
RTC_TimeTypeDef AlarmTime; //设置时间
uint32_t AlarmMask; //闹钟掩码设置
//RTC_ALARMMASK_NONE,闹钟比较时匹配所有比较项目,包括日期(日/星期)、时、分、秒,完全匹配才会产生闹钟中断/事件
//RTC_ALARMMASK_DATEWEEKDAY,屏蔽日期(日/星期),闹钟比较时将不关心日期(日/星期)
//RTC_ALARMMASK_HOURS,屏蔽时钟,闹钟比较时将不关心小时数
//RTC_ALARMMASK_MINUTES,屏蔽分钟,闹钟比较时将不关心分钟数
//RTC_ALARMMASK_SECONDS,屏蔽秒钟,闹钟比较时将不关心秒钟数
//RTC_ALARMMASK_ALL,屏蔽所有,设置后将不会产生闹钟中断/事件
uint32_t AlarmSubSecondMask; //亚秒掩码设置
//在RTC_Alarm_Sub_Seconds_Masks_Definitions中设置亚秒匹配规则
uint32_t AlarmDateWeekDaySel; //日期(日/星期)选择,此位只有当AlarmMask中不设置RTC_ALARMMASK_DATEWEEKDAY时才有效
//RTC_ALARMDATEWEEKDAYSEL_DATE,选择匹配日期
//RTC_ALARMDATEWEEKDAYSEL_WEEKDAY,选择匹配星期
uint8_t AlarmDateWeekDay; //日期(日/星期)设置,此位只有当AlarmMask中不设置RTC_ALARMMASK_DATEWEEKDAY时才有效
//如果AlarmDateWeekDaySel选择RTC_ALARMDATEWEEKDAYSEL_DATE,该值范围【1-31】,代表设置一个月当中的第几号
//如果AlarmDateWeekDaySel选择RTC_ALARMDATEWEEKDAYSEL_WEEKDAY,该值范围在RTC_WeekDay_Definitions定义,代表设置一周当中的星期几
uint32_t Alarm; //设置闹钟
//RTC_ALARM_A,选择闹钟A
//RTC_ALARM_B,选择闹钟B
}RTC_AlarmTypeDef;
下一次闹钟时间
这里我建立了新的dev_rtc.c\dev_rtc.h文件,专门放中断和设置闹钟时间
闹钟中断函数
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
HAL_RTC_GetTime(hrtc,&sTime,RTC_FORMAT_BIN); // 获取当前时间
dev_wdt_feed();
sAlarm_flag=1;//闹钟标志位
// 再次启动闹钟中断事件
if (HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
HAL_RTC_SetAlarm_IT(hrtc,&sAlarm,RTC_FORMAT_BIN);
}
中断不能放太多代码,“sAlarm_flag”作为一个标志位来闹钟事件来开启下一次闹钟时间
设置闹钟时间结构体
在dev_rtc.h里面建立闹钟时、分、秒结构体
/*定义闹钟时、分、秒结构体*/
typedef struct
{
uint8_t Hourss;
uint8_t Minutess;
uint8_t Secondss;
} nTime;
引用结构体的时候一定要在全局变量里面用
?sAlarm_flag标志位不能放在第一个,不然会出现进入中断后标志位直接清零的现象,小编因为这个debug了好久。
?设置闹钟时间
?由于代码较长,看起来不美观,这里我是建立了函数来单独设置时间“dev_set_alarm_time”;在20一次闹钟(可以根据自己的需要设置,分钟闹的话就把秒钟去掉就好了)
/****************************************************************************
**Description: 设置闹钟时间
**Input parameters:
**Output parameters: 无
**Returned value:
**Created by:
**Modified by:
**Remark: time_flag=1表示第二次闹钟时间
*****************************************************************************/
void dev_set_alarm_time(void)
{
if(second_time_flag==1) 设置第二次闹钟时间,此标志位只进来一次
{
Time.Hourss=12;
Time.Minutess=12;
Time.Secondss=20;
second_time_flag=0;
}
Time.Secondss+=20; //每20秒进入一次
if(Time.Secondss>= 60)
{
Time.Minutess+=1;
if(Time.Minutess>=60)
{
Time.Hourss+= 1;
if(Time.Hourss >= 24)
{
Time.Hourss = 0;
}
Time.Minutess= 0;
}
Time.Secondss= 0;
}
}
进入下一次闹钟函数
/****************************************************************************
**Description: 闹钟函数
**Input parameters:
**Output parameters: 无
**Returned value:
**Created by:
**Modified by:
**Remark: 闹钟掩码和日期选择是不可避免的
*****************************************************************************/
void dev_rtc_alarm(void)
{
if(sAlarm_flag==1)//收到闹钟标志位
{
HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN); // 获取当前时间
dev_set_alarm_time();//时间设置
sAlarm.AlarmTime.Hours =Time.Hourss;
sAlarm.AlarmTime.Minutes = Time.Minutess;
sAlarm.AlarmTime.Seconds = Time.Secondss;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS
|RTC_ALARMMASK_MINUTES; //闹钟掩码设置
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;//日期(日/星期)选择,此位只有当AlarmMask中不设置RTC_ALARMMASK_DATEWEEKDAY时才有效
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
sAlarm_flag=0;//清除闹钟标志位
dev_alarm_wdt_feed();//喂狗
}
}
开启闹钟
当下载代码后中断会自动开启第一次闹钟,而第二次和后面的闹钟在while(1)里面启用“dev_rtc_alarm()”函数就可以了
?总体dev_rtc.c代码
#include "dev_wdt.h"
#include "dev_rtc.h"
#include "rtc.h"
static s8 sAlarm_flag=0;//闹钟事件
static s8 second_time_flag=1;//第二次事件
extern RTC_AlarmTypeDef sAlarm ;//声明闹钟结构体
extern RTC_TimeTypeDef sTime ;//声明时间结构体
nTime Time;
/****************************************************************************
**Description: 闹钟函数
**Input parameters:
**Output parameters: 无
**Returned value:
**Created by:
**Modified by:
**Remark: 闹钟掩码和日期选择是不可避免的
*****************************************************************************/
void dev_rtc_alarm(void)
{
dev_eeprom_read(SLEEP_FLAG_ADDR,&sAlarm_sleeps_flag,SLEEP_FLAG_LEN);
if(sAlarm_flag==1)//收到闹钟标志位
{
HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN); // 获取当前时间
dev_set_alarm_time();//时间设置
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS
|RTC_ALARMMASK_MINUTES; //闹钟掩码设置
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;//日期(日/星期)选择,此位只有当AlarmMask中不设置RTC_ALARMMASK_DATEWEEKDAY时才有效
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
sAlarm_flag=0;//清除闹钟标志位
dev_alarm_wdt_feed();//喂狗
}
}
/****************************************************************************
**Description: 设置闹钟时间
**Input parameters:
**Output parameters: 无
**Returned value:
**Created by:
**Modified by:
**Remark: time_flag=1表示第二次闹钟时间
*****************************************************************************/
void dev_set_alarm_time(void)
{
if(second_time_flag==1)
{
Time.Hourss=12;
Time.Minutess=12;
Time.Secondss=20;
second_time_flag=0;
}
Time.Secondss+=20; //每20秒进入一次
if(Time.Secondss>= 60)
{
Time.Minutess+=1;
if(Time.Minutess>=60)
{
Time.Hourss+= 1;
if(Time.Hourss >= 24)
{
Time.Hourss = 0;
}
Time.Minutess= 0;
}
Time.Secondss= 0;
}
sAlarm.AlarmTime.Hours =Time.Hourss;
sAlarm.AlarmTime.Minutes = Time.Minutess;
sAlarm.AlarmTime.Seconds = Time.Secondss;
}
/****************************************************************************
**Description: 喂狗且再次进入睡眠
**Input parameters:
**Output parameters: 无
**Returned value:
**Created by:
**Modified by:
**Remark:
*****************************************************************************/
void dev_alarm_wdt_feed(void)
{
dev_wdt_feed();
if(sAlarm_sleeps_flag==1)
{
dev_charger_sleep();
}
}
/****************************************************************************
**Description: 闹钟中断函数
**Input parameters:
**Output parameters: 无
**Returned value:
**Created by:
**Modified by:
**Remark:
*****************************************************************************/
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
HAL_RTC_GetTime(hrtc,&sTime,RTC_FORMAT_BIN); // 获取当前时间
dev_wdt_feed();
sAlarm_flag=1;//钟标志位闹
// 再次启动闹钟中断事件
if (HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
HAL_RTC_SetAlarm_IT(hrtc,&sAlarm,RTC_FORMAT_BIN);
}
实验现象
我用的是debug调试
下面是两次闹钟现象
?以上就是小编针对RTC闹钟得出的结果,写得不好还请多多包涵!!!
|