Implementation of alarm clock (timing) task based on freeRTOS timer

Implementation of alarm clock (timing) task based on freeRTOS timer

In the hardware of intelligent hardware products, the alarm clock timing task is a basic requirement. Generally, the scheduled task is set through the APP, and the alarm clock task is saved in the hardware flash from the cloud or the APP directly connected to the hardware, and the alarm clock task will be processed when the hardware is running.

The simplest implementation is to continuously judge whether the current time is equal to the alarm clock setting time in the loop or timer processing function, and if it is equal, the corresponding action will be generated.

This works, but it does too many useless calculations. We can set a corresponding timer according to the current time and the next alarm activation time. When the timer is activated, it is the alarm time, and then continue to set a new timer according to the next activation time, which can reduce unnecessary time comparisons. .

Representation of the alarm clock task

The representation of the alarm task includes the following and some parts: alarm time, repetition type, response action.

The local representation of the alarm clock task can be defined according to the cron format, of course, you can also DIY one, as long as it includes the above three aspects.

The time in cron format is represented as follows:

Character Descriptor Acceptable Values
1 Minute 0~59, * (no specific value)
2 Hour 0~23, * (no specific value)
3 Day of month 1~31, * (no specific value)
4 Month 1~12, * (no specific value)
5 Day of week 0~7, * (no specific value)

For example, for an alarm clock at 7:00 in the morning from Monday to Friday, it can be expressed as: 0 7 * * 1,2,3,4,5.

I have defined the alarm task as follows in the code:

/* cron 格式时间表示 */
typedef struct
{
    int     min;    // minute,          0xFFFFFFFF表示*
    int     hour;   // hour,           0xFFFFFFFF表示*
    int     wday;   // day of week,    0xFFFFFFFF表示*,bit[0~6]  表示周一到周日,如周一到周五每天响铃,则0x1F
    int     mday;   // day of month,   0xFFFFFFFF表示*, bit[0~31] 表示1~31日,每月1,3,5号响铃,则0x15
    int     mon;    // month,          0xFFFFFFFF表示*,bit[0~11] 表示1~12月
} cron_tm_t;

/* 闹钟任务 */
typedef struct
{
    int             id;         // 任务ID
    cron_tm_t       cron_tm;    // cron格式时间
    int             action;     // 响应操作,对于灯控产品来说,action可以表示开关、颜色、场景等等
    TimerHandle_t   xTimer;     // 定时器句柄
    list_node_t     node;       // 节点,用于将一系列定时任务组织成list
} alarm_task_t;

The next time the alarm will fire

The principle of implementing an alarm clock based on a timer is to calculate the interval time from the next trigger each time the alarm clock is set, and then set a timer with the corresponding time.

First, you need to calculate the time of the next excitation according to the cron format time

/* 距离闹钟下一次激发的时间(min) */
int get_expiry_time(alarm_task_t  *alarm_task)
{
   /* 首先获取当前时间 */
   
   time_t    t;
   struct tm now;

   time(&t);
   localtime_r(&t, &now);

   int ret = 0;

   if(alarm_task->cron_tm.min != 0xFFFFFFFF)
   {
        ret += cron_tm.min - now.tm_min;
   }

   if(alarm_task->cron_tm.hour != 0xFFFFFFFF)
   {
        int flag = 0;

        for(int i=0; i<24; i++)
        {
            if(i == alarm_task->cron_tm.hour){
                flag=1;
                break;
            }
        }

        if(flag){
            ret += 60*(i-now.tm_hour);
        }
   }

   /* 找到wday或者mday中距离今天最近的一天 */
   int t = ret<0?1:0;
   
   int d_wday=0;
   int d_mday=0;

   for(int i=0; i<7; i++)
   {
        int wday = now.tm_wday + t +i;
        if(1<<(wday%7) & alarm_task->cron_tm.wday){
            d_wday=i+t;
            break;
        }
   }

   for(int i=0; i<30; i++)
   {
        int mday = now.tm_mday + t +i;

        if(1<<(mday%30) & alarm_task->cron_tm_.mday){
            d_mday = i+t;
            break;
        }
   }

   int d = d_mday<d_wday?d_mday:d_wday;

   ret += d*24*60;
  
   return ret;
}

set timer

Every time the hardware is powered on, or when the alarm clock is fired, a timer must be set according to the next firing time.

int set_timer(alarm_task_t  *alarm_task)
{
    int t = get_expiry_time(alarm_task);
    if(t <= 0) return -1; // 不需要设置下一次闹钟,不重复的闹钟,且时间已过

    alarm_task->xTimer = xTimerCreate( "timer",
                                        t / portTICK_RATE_MS,
                                        1,
                                        (void*)alarm_task,
                                        timer_task_callback );

    if(alarm_task->xTimer == NULL)
    {
        printf("!!! timer created failed\n");
        return -1;
    }
    else
    {
        xTimerStart(alarm_task->xTimer, 0);
    }

    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324845199&siteId=291194637