其实不是stm32啦,因为stm32流量高,这是一个通用的软件闹钟(软件实现的当然通用哈)。
实现10个闹钟,需要mcu提供时间获取函数,1分钟定时检查调用,以及flash读写函数(用来掉电不丢失闹钟信息)。
rtc_alarm.c
#include "rtc_alarm.h"
#include "debug.h"
#include <string.h>
#include "system/includes.h"
#define DBG(format,...) printf("[SOFT_ALARM]:"format, ##__VA_ARGS__) //LOG
// 记录全部闹钟
static RTC_ALARM_T soft_alarm_table[RTC_ALARM_MAX];
//打印soft_alarm_table
static void soft_alarm_printf(void)
{
for(int i = 0; i < RTC_ALARM_MAX; i++)
{
DBG("index = %d sw = %d mode = %d %d-%d-%d,%d:%d:%d\n",
soft_alarm_table[i].index, soft_alarm_table[i].sw, soft_alarm_table[i].mode,
soft_alarm_table[i].time.year, soft_alarm_table[i].time.month, soft_alarm_table[i].time.day,
soft_alarm_table[i].time.hour, soft_alarm_table[i].time.min, soft_alarm_table[i].time.sec);
}
}
//调试调用檫除
static void soft_alarm_erase(void)
{
//clear
memset(&soft_alarm_table[0].index, 0x00, sizeof(soft_alarm_table));
//write flash
syscfg_write(CFG_USER_SOFT_ALARM, &soft_alarm_table[0].index, sizeof(soft_alarm_table));
}
//更新闹钟时调用
static void soft_alarm_save(void)
{
//write flash
syscfg_write(CFG_USER_SOFT_ALARM, &soft_alarm_table[0].index, sizeof(soft_alarm_table));
//LOG
//soft_alarm_printf();
}
// 上电调用
void soft_alarm_init(void)
{
//read flash
syscfg_read(CFG_USER_SOFT_ALARM, &soft_alarm_table[0].index, sizeof(soft_alarm_table));
//LOG
soft_alarm_printf();
}
//获取时间
static void get_now_time(RTC_TIME_T *p)
{
//get time
get_sys_time(p);
//DBG("now time: %d-%d-%d,%d:%d:%d\n", p->year, p->month, p->day, p->hour, p->min, p->sec);
}
// 设置软件闹钟时间
static void soft_alarm_set(RTC_ALARM_T_P p)
{
p->time.sec = 0;//闹钟不定时秒,到分钟就可以
memcpy(&soft_alarm_table[p->index].index, &p->index, sizeof(RTC_ALARM_T));
soft_alarm_save();
}
//日期转换为星期
//蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26x(m+1)/10]+d-1
//返回周1-7
static uint8_t rtc_calculate_week_val(RTC_TIME_T *data_time)
{
RTC_TIME_T t_time;
uint32_t century, val, year;
memcpy(&t_time, data_time, sizeof(struct sys_time));
if (t_time.month < 3) {
t_time.month = t_time.month + 12;
t_time.year--;
}
year = t_time.year % 100;
century = t_time.year / 100;
val = year + (year / 4) + (century / 4) + (26 * (t_time.month + 1) / 10) + t_time.day;
val = val - century * 2 - 1;
return (uint8_t)(val % 7) == 0 ? 7 : (val % 7);
}
static void beep(uint8_t number)
{
DBG(">>>>ALARM ALARM %d\n", number);
DBG(">>>>ALARM ALARM %d\n", number);
DBG(">>>>ALARM ALARM %d\n", number);
soft_alarm_printf();//DBG
}
//1分钟 执行一次检查闹钟是否需要执行
void soft_alarm_check(void)
{
DBG("%s\n", __func__);
int i;
uint8_t week;
RTC_TIME_T nowtime;
get_now_time(&nowtime);
week = 1 << rtc_calculate_week_val(&nowtime);
for(i = 0; i < RTC_ALARM_MAX; i++)
{
if(soft_alarm_table[i].sw != TRUE) continue;
if(memcmp(&soft_alarm_table[i].time.hour, &nowtime.hour, 3) != 0) continue;
if(soft_alarm_table[i].mode == E_ALARM_MODE_ONCE)
{
soft_alarm_table[i].sw = FALSE;
soft_alarm_save();
goto ret;
}
else if(soft_alarm_table[i].mode == E_ALARM_MODE_EVERY_DAY)
{
goto ret;
}
else if((soft_alarm_table[i].mode & week ) > 0)
{
goto ret;
}
}
return;
ret:
beep(i);
}
void rtc_alarm_test(void)
{
DBG("%s\n", __func__);
//soft_alarm_init();
//soft_alarm_erase();
//soft_alarm_printf();
/*设置当前时间+1分钟的闹钟*/
RTC_ALARM_T t;
get_now_time(&t.time);
if(t.time.min < 59) t.time.min++;//暂时不考虑60分钟的情况
t.index = 1;//测试使用第一个闹钟
t.mode = E_ALARM_MODE_ONCE;//一次
t.sw = TRUE;//打开
t.time.year = 2024;
t.time.month = 1;
t.time.day = 3;
DBG("week = %d\n", rtc_calculate_week_val(&t.time));
soft_alarm_set(&t);
//打印观察
soft_alarm_printf();
}
rtc_alarm.h
#ifndef RTC_ALARM_H
#define RTC_ALARM_H
#include "typedef.h"
typedef struct rtc_time {
u16 year;
u8 month;
u8 day;
u8 hour;
u8 min;
u8 sec;
}RTC_TIME_T;
enum {
E_ALARM_MODE_ONCE = 0x00,
E_ALARM_MODE_EVERY_DAY = 0x01,
E_ALARM_MODE_EVERY_MONDAY = 0x02,
E_ALARM_MODE_EVERY_TUESDAY = 0x04,
E_ALARM_MODE_EVERY_WEDNESDAY = 0x08,
E_ALARM_MODE_EVERY_THURSDAY = 0x10,
E_ALARM_MODE_EVERY_FRIDAY = 0x20,
E_ALARM_MODE_EVERY_SATURDAY = 0x40,
E_ALARM_MODE_EVERY_SUNDAY = 0x80,
};
typedef struct __ALARM__ {
u8 index; //索引
bool sw; //开关
u8 mode; //模式
RTC_TIME_T time;//时间
} RTC_ALARM_T, *RTC_ALARM_T_P;
#define RTC_ALARM_MAX (10) //当前10个闹钟
void rtc_alarm_test(void);
extern void soft_alarm_init(void);
extern void soft_alarm_check(void);
#endif