Analysis of Two Ways of Using Software to Realize Timer in Embedded System

Table of contents

First: Introduction

Second: Linked list implementation

Third: Structure implementation


 

First: Introduction

In general embedded product design, due to cost, power consumption, etc., the selected MCU is basically limited in resources, and the number of timers inside is even more limited. In our software design, there are often various timing requirements, such as pulse output, key detection, LCD screen cut delay, etc. It is impossible for us to open a hardware timer for every timing business. First, the hardware resources may be insufficient. Second, it will make the software overly dependent on the hardware platform, resulting in poor portability.

If we have a software timer, all timing services depend on the software timer, which not only saves hardware resources, but also only needs to modify the software timer and hardware-related parts during transplantation, and other parts do not need to be moved.

Software timer implementation:

1. Realize the software timer by means of structure array

It is simpler and easier to understand with the method of structure array. Besides, it has no other advantages compared with the subsequent implementation of linked list.

But let me introduce the implementation method: define a start flag and a timing duration in the structure array, and one is the count value count. These 3 variables are the most basic 3 variables. Others can be supplemented by yourself, such as the operation mode , callback function pointer, etc. In addition, each structure array is a timer, and we need to define the size of the structure array in advance.

After the definition is complete, we set the start flag in the corresponding array when starting the timer, and in the hardware tick interrupt service function, we check whether the start flag in all structure arrays is set, and when we find that the current start is set When it is set, compare the duration and count in this array. If they are equal, it means that the timer time is up. If not, count ++, and then check the start flags of other arrays to loop infinitely.

The disadvantage of this method is very obvious, that is, in the hardware tick interrupt service function, we have to poll all arrays. If our software business requirement is 20 timing tasks, then we have to define 20 arrays in the implementation of the software timer The waste of space is second to none. The key is that the more arrays polled by the hardware tick, the longer it will take to execute to a certain array. If there are 50 or 100 timing requirements in the future, the timing will be extremely inaccurate.

2. Realize software timer with linked list

Due to the various shortcomings of using the structure array to realize the software timer above, we propose an improvement plan. After analysis, in most timing services, it is often only necessary to schedule once in a certain period of time, that is to say, the timer will start timing and end timing. Of course, the timer implemented with an array can also turn on timing and turn off timing. You only need to use the start flag to decide, but in the way of implementing with an array, even if you turn off the timer, that is, remove the start flag. Although the timer does not run, the space of the array will not decrease. The hardware tick Still have to poll all arrays.

So we need to use a linked list to implement a software timer, poll all nodes in the hardware tick, add a node when a timer is turned on, delete a node when a timer is turned off, and ensure that only the nodes that need to be timed are polled at the current moment. It can greatly guarantee the timing accuracy.

In addition, the user can choose to execute directly in the hardware tick when the timing is up, or set the built-in flag in the hardware tick, and then queue for execution in the while loop, which can effectively solve the problem of inaccurate timing of key businesses, such as the need for pulse output Timed and accurate business.

Second: Linked list implementation

H-file:

/**
 * sfor_timer_list.h
 * 链表实现的软件定时器库
 */
#ifndef __SOFT_TIMER_LIST_H
#define __SOFT_TIMER_LIST_H

/**
 * 硬件中断tick
 */
#define TIMER_HARD_TICK                      100U    //ms,硬件tick取决于硬件定时中断时间
#define TIMER_200MS_TICK                     (200U/TIMER_HARD_TICK) //TIMER_HARD_TICK * (2) = 100mS
#define TIMER_SEC_TICK                       (1000U/TIMER_HARD_TICK) //TIMER_HARD_TICK * (20) = 1S


/**
 * 定时模式选择
 */
typedef enum
{
    ONCE_MODE,                            /* 单次定时模式,即超时后自动关闭定时器 */
    CONTINUE_MODE,                        /* 持续定时模式,只要开启除非手动关闭否则永不停歇 */
    DEFINE_NUM_MODE,                      /* 定义次数的模式,运行指定的次数后关闭定时器 */
}TimerTimingModeType;

/**
 * 定时超时后运行的回调函数可以选择在中断直接运行或者挂起任务轮询执行
 * 只要在定时需求准确的时候才建议选择中断模式执行,类似无磁传感器脉冲测量
 * 像一些超时判断类的应用以轮询的方式进行执行
 * 中断执行模式越多,其他定时器越不准,毕竟中断允许占时间,查询其他定时器时
 * 会有延时
 */
typedef enum
{
    RUN_IN_LOOP_MODE,                      /* 轮询执行模式 */
    RUN_IN_INTERRUPT_MODE,                 /* 中断实时执行模式 */
}TimerRunModeType;

/**
 * 软件定时器基本类型
 */
typedef struct SoftTimer
{
    unsigned long counter;                /* 计数              */
    unsigned long duration;               /* 定时时长          */
    unsigned long run_num;                /* 自定义的定时次数  */
    BOOL start_flag;                      /* 启动标志          */
    BOOL loop_flag;                       /* 轮询标志          */
    TimerRunModeType run_mode;
    TimerTimingModeType timing_mode;
    void (*callback_function)(void);      /* 回调函数          */
    struct SoftTimer *next;
}SoftTimer;

/*
 * 初始化软件定时器的硬件tick
 */
extern void soft_timer_tick_init(void);

/*
 * 创建一个只运行一次的软件定时器并立刻开始计时
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
extern void creat_single_soft_timer(SoftTimer *p, TimerRunModeType mode, unsigned long duration, void(*timeout_handler)(void));

/*
 * 创建永远运行的软件定时器并立刻开始计时
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
extern void creat_continue_soft_timer(SoftTimer *p, TimerRunModeType mode, unsigned long duration, void(*timeout_handler)(void));

/*
 * 创建指定次数运行的软件定时器并立刻开始计时
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        run_num:要定时的次数,比如1就是定时1次,5就是定时5次以后自动关闭定时器
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
extern void creat_limit_num_soft_timer(SoftTimer *p, TimerRunModeType mode,unsigned long run_num, unsigned long duration, void(*timeout_handler)(void));


/*
 * 重启指定的单次软件定时器
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
extern void restart_single_soft_timer(SoftTimer *p, TimerRunModeType mode, unsigned long duration, void(*timeout_handler)(void));

/**
 * 删除一个软件定时器
 */
extern void stop_timer(SoftTimer *p);


/**
 * 系统main循环进程,用于执行轮询模式的回调函数
 */
extern void soft_timer_main_loop(void);


/**
 * 此函数为tick中断服务函数,需要挂载在外部硬件定时器上
 * 因此软件定时器的定时精度由此函数挂载的硬件定时时间决定,
 * 比如此函数挂载在定时50ms的外部定时器上,那么定时dutation
 * 为20时定时时间就是20*50ms=1S
 */
extern void system_tick_IrqHandler(void);

#endif /* !1__SOFT_TIMER_LIST_H */

C file:

/**
 * sfor_timer_list.c
 * 链表实现的软件定时器库
 */
#define NULL ((void *)0)
typedef enum {FALSE = 0, TRUE = !FALSE} BOOL;

#include "meter_include.h" //包含用户的硬件定时器初始化函数
#include "soft_timer_list.h"

/**
 * 软件定时器内部变量
 */
static SoftTimer *head_point = NULL;

static struct SoftTimer *creat_node(SoftTimer *node);
static char delete_node(SoftTimer *node);
static BOOL is_node_already_creat(SoftTimer *node);


/**
 * 初始化软件定时器的硬件tick
 */
void soft_timer_tick_init(void)
{
    R_IT_Create(); /* 由用户初始化一个硬件定时器,当前tick 100ms */
    R_IT_Start();
}

/**
 * 系统main循环进程,用于执行轮询模式的回调函数
 */
void soft_timer_main_loop(void)
{
    struct SoftTimer *p1 = head_point;

    while (p1 != NULL) //下一个节点如果不为空
    {
        if(p1->loop_flag == TRUE)
        {
            p1->loop_flag= FALSE;
            p1->callback_function();
            if(p1->start_flag != TRUE)
                delete_node(p1);   /* 如果定时器被删除就删除节点 */
        }
        /*  寻找下一个有意义的节点  */
        p1 = p1->next;
    }
}

/*
 * 创建一个只运行一次的软件定时器并立刻开始计时
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
void creat_single_soft_timer(SoftTimer *p, TimerRunModeType mode, unsigned long duration, void(*timeout_handler)(void))
{
    if ((p == NULL)||(timeout_handler == NULL) || duration == 0) return;

    p->start_flag = TRUE;
    p->counter = 0;
    p->loop_flag = FALSE;
    p->duration = duration;
    if(mode == RUN_IN_LOOP_MODE)
        p->run_mode = RUN_IN_LOOP_MODE;
    else
        p->run_mode = RUN_IN_INTERRUPT_MODE;
    p->callback_function = timeout_handler;
    p->timing_mode = ONCE_MODE;
    p->run_num = 0; /* 只有在自定义运行次数的情况下此值才有效 */
    head_point = creat_node(p);
}

/*
 * 创建永远运行的软件定时器并立刻开始计时
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行(除非实在必要)还是置起标志在while循环内轮询执行
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
void creat_continue_soft_timer(SoftTimer *p, TimerRunModeType mode, unsigned long duration, void(*timeout_handler)(void))
{
    if ((p == NULL)||(timeout_handler == NULL) || duration == 0) return;

    p->start_flag = TRUE;
    p->counter = 0;
    p->loop_flag = FALSE;
    p->duration = duration;
    if(mode == RUN_IN_LOOP_MODE)
        p->run_mode = RUN_IN_LOOP_MODE;
    else
        p->run_mode = RUN_IN_INTERRUPT_MODE;
    p->callback_function = timeout_handler;
    p->timing_mode = CONTINUE_MODE;
    p->run_num = 0;       /* 只有在自定义运行次数的情况下此值才有效 */
    head_point = creat_node(p);
}



/*
 * 创建指定次数运行的软件定时器并立刻开始计时
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        run_num:要定时的次数,比如1就是定时1次,5就是定时5次以后自动关闭定时器
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
void creat_limit_num_soft_timer(SoftTimer *p, TimerRunModeType mode,unsigned long run_num, unsigned long duration, void(*timeout_handler)(void))
{
    if ((p == NULL)||(timeout_handler == NULL) || duration == 0) return;
    p->start_flag = TRUE;
    p->counter = 0;
    p->loop_flag = FALSE;
    p->duration = duration;
    if(mode == RUN_IN_LOOP_MODE)
        p->run_mode = RUN_IN_LOOP_MODE;
    else
        p->run_mode = RUN_IN_INTERRUPT_MODE;
    p->callback_function = timeout_handler;
    p->timing_mode = DEFINE_NUM_MODE;
    p->run_num = run_num;       /* 只有在自定义运行次数的情况下此值才有效 */
    head_point = creat_node(p);
}


/*
 * 重启指定的单次软件定时器
 * 参数表:p: 定时器结构体指针,由用户创建
 *        mode: 选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在while循环内轮询执行
 *        duration: 要计时的时长,单位为硬件中断的tick
 *        timeout_handler: 定时到了之后要执行的函数指针
 * return:无
 */
void restart_single_soft_timer(SoftTimer *p, TimerRunModeType mode, unsigned long duration, void(*timeout_handler)(void))
{
    if ((p == NULL)||(timeout_handler == NULL) || duration == 0) return;

    p->start_flag = TRUE;
    p->counter = 0;
    p->loop_flag = FALSE;
    p->duration = duration;
    if(mode == RUN_IN_LOOP_MODE)
        p->run_mode = RUN_IN_LOOP_MODE;
    else
        p->run_mode = RUN_IN_INTERRUPT_MODE;
    p->callback_function = timeout_handler;
    p->timing_mode = ONCE_MODE;
    p->run_num = 0; /* 只有在自定义运行次数的情况下此值才有效 */
    if (is_node_already_creat(p) != TRUE) /* 若之前的节点已被删除就重新创建 */
        head_point = creat_node(p);
}


/**
 * 封装后给用户使用
 */
void stop_timer(SoftTimer *p)
{
    if (p != NULL) {
        p->counter = 0;
        p->start_flag = FALSE;
        delete_node(p);
    }
}


static struct SoftTimer *creat_node(SoftTimer *node)
{  
    struct SoftTimer *p1;   //p1保存当前需要检查的节点的地址
    if(node == NULL)
        return head_point;

    if(is_node_already_creat(node)!=FALSE) {
        delete_node(node);  /* 当节点已经存在的时候在这里选择退出还是删除后重新创建,目前重新创建 */
    }
    //当头节点为空时,将传入的节点作为头节点,返回头节点  
    if (head_point == NULL)         {    
        head_point = node; 
        node->next = NULL;
        return head_point;
    }
    p1 = head_point;  
    while(p1->next != NULL)  
    {  
        p1 = p1->next;       //后移一个节点  
    }  
 
    if(p1->next == NULL)  //将该节点插入链表的末尾
    {  
        p1->next = node;
        node->next = NULL;
    }  
    else
    {
        
    }
    return head_point;  
}


static char delete_node(SoftTimer *node)
{  
    struct SoftTimer *p1;   //p1保存当前需要检查的节点的地址  
    struct SoftTimer *temp;
    if(node == NULL)
       return 1;

    p1 = head_point;
    if(node == head_point) {
        head_point = head_point->next;    /* 如果要删除头指针,就将头指针后移  */
    } else {
        while (p1 != NULL) /*头节点如果不为空 */
        {
            temp = p1;     /* 记录当前节点 */
            p1 = p1->next; /* 检索的是下一个节点  */
            if (p1 == NULL) {
                return 1;
            }
            if (p1 == node) {
                temp->next = p1->next; /* 删除此节点 */
                return 0;
            }
        }
    }
    return 0;
}


static BOOL is_node_already_creat(SoftTimer *node)
{  
    struct SoftTimer *p1;   //p1保存当前需要检查的节点的地址  
    if(node == NULL)
       return FALSE;

    p1 = head_point;  
    while(p1 != NULL)  
    {  
        if(p1 == node)
            return TRUE;
        p1 = p1->next;       //后移一个节点  
    }
    return FALSE;
}


/**
 * 此函数为tick中断服务函数,需要挂载在外部硬件定时器上
 * 因此软件定时器的定时精度由此函数挂载的硬件定时时间决定,
 * 比如此函数挂载在定时50ms的外部定时器上,那么定时dutation
 * 为20时定时时间就是20*50ms=1S
 */
void system_tick_IrqHandler(void)
{
    struct SoftTimer *p1 = head_point;
    close_global_ir();  //关闭中断,根据硬件平台修改
    while (p1 != NULL) //下一个节点如果不为空
    {
        if(p1->start_flag != FALSE)    /* 判断当前定时器是否被开启  */
        {
            if(++p1->counter >= p1->duration)  /* 判断当前计时有没有到达 */
            {
                switch (p1->timing_mode)
                {
                case ONCE_MODE:
                    p1->start_flag = FALSE;
                    break;
                case CONTINUE_MODE:
                    break;
                case DEFINE_NUM_MODE:
                    if (p1->run_num > 0)
                    {
                        if (--p1->run_num == 0)
                        {
                            p1->start_flag = FALSE;
                        }
                    }
                default:
                    break;
                }
                if(p1->run_mode == RUN_IN_INTERRUPT_MODE)
                {
                    p1->callback_function();   /* 中断内直接运行回调函数,用于实时性比较高的程序 */
                    if(p1->start_flag != TRUE)
                        delete_node(p1);
                }
                else
                    p1->loop_flag = TRUE;
                p1->counter = 0;
            }
        }
        /*  寻找下一个有意义的节点  */
        p1 = p1->next;
    }
    open_global_ir();  //打开中断,根据硬件平台修改
}

Third: Structure implementation

Finally, attach the software timer implemented with the structure array for reference.

H-file:

/**
 * sfor_timer_array.h
 * 数组实现的软件定时器库
 * 一个软件定时器解决整个项目中所有的定时需求,回调函数可根据应用
 * 自动切换中断实时操作或者不实时的轮询操作,可以有效解决硬件资源
 * 不足或者软件定时器定时不准的问题,定时误差就几个C语言语句,倘若
 * 配置最大10个软件定时器,误差就是最多10个for循环的时间
 */
#ifndef __SOFT_TIMER_ARRAY_H
#define __SOFT_TIMER_ARRAY_H


/**
 * 定义最大的可用的软件定时器数量
 * 理论上可以无限大,但是数量越大定时误差越大,所以用几个开几个
 * 误差在于轮询检测所有定时器,定时器越多轮询到自己的定时器就越慢,
 * 此外,数量增多亦会带来空间增大
 */
#define MAX_TIMER_NUM                       10


/**
 * 定时模式选择
 */
typedef enum
{
    ONCE_MODE,                            /* 单次定时模式,即超时后自动关闭定时器 */
    CONTINUE_MODE,                        /* 持续定时模式,只要开启除非手动关闭否则永不停歇 */
    DEFINE_NUM_MODE,                      /* 定义次数的模式,运行指定的次数后关闭定时器 */
}TimerTimingModeType;


/**
 * 定时超时后运行的回调函数可以选择在中断直接运行或者挂起任务轮询执行
 * 只要在定时需求准确的时候才建议选择中断模式执行,类似无磁传感器脉冲测量
 * 像一些超时判断类的应用以轮询的方式进行执行
 * 中断执行模式越多,其他定时器越不准,毕竟中断允许占时间,查询其他定时器时
 * 会有延时
 */
typedef enum
{
    RUN_IN_LOOP_MODE,                      /* 轮询执行模式 */
    RUN_IN_INTERRUPT_MODE,                 /* 中断实时执行模式 */
}TimerRunModeType;


/**
 * 软件定时器基本类型
 */
typedef struct 
{
    unsigned long counter;                /* 计数           */
    unsigned long duration;               /* 定时时长       */
    unsigned long run_num;                /* 自定义的定时次数  */
    unsigned char start_flag;             /* 启动标志       */
    unsigned char loop_flag;              /* 轮询标志       */
    TimerRunModeType run_mode;
    TimerTimingModeType timing_mode;
    void (*callback_function)(void);      /* 回调函数 */
}SoftTimer;



/**
 * 删除一个软件定时器
 */
extern void stop_timer(void (*callback_function)(void));



/*
 * 创建一个软件定时器并立刻开始计时
 * return:没有空闲定时器时返回1,创建成功时返回0
 */
extern char soft_timer_start(TimerTimingModeType timing_mode, 
                                   TimerRunModeType run_mode,
                                       unsigned long run_num, 
                                      unsigned long duration,
                              void (*callback_function)(void));



/**
 * 系统main循环进程,用于执行轮询模式的回调函数
 */
extern void soft_timer_main_loop(void);



/**
 * 此函数为tick中断服务函数,需要挂载在外部硬件定时器上
 * 因此软件定时器的定时精度由此函数挂载的硬件定时时间决定,
 * 比如此函数挂载在定时50ms的外部定时器上,那么定时dutation
 * 为20时定时时间就是20*50ms=1S
 */
extern void system_tick_IrqHandler(void);



#endif /* !1__SOFT_TIMER_LIB_H */

C file:

/**
 * sfor_timer_array.c
 * 数组实现的软件定时器库
 * 一个软件定时器解决整个项目中所有的定时需求,回调函数可根据应用
 * 自动切换中断实时操作或者不实时的轮询操作,可以解决硬件资源
 * 不足或者软件定时器定时不准的问题
 */
#include "soft_timer_array.h"


/**
 * 软件定时器内部变量
 */
static SoftTimer soft_timer[MAX_TIMER_NUM];


/*
 * 创建一个软件定时器并立刻开始计时
 * return:没有空闲定时器时返回1,创建成功时返回0
 */
char soft_timer_start(TimerTimingModeType timing_mode, TimerRunModeType run_mode, unsigned long run_num, unsigned long duration,
                      void (*callback_function)(void))
{
    unsigned char i = 0;

    if(!callback_function) return 1;
    stop_timer(callback_function);     /* 先判断有没有一样的定时器,有的话先删除  */
    for(i =0; i<MAX_TIMER_NUM;i++)
    {
        if(soft_timer[i].start_flag == 0)    /* 查询空闲的定时器 */
        {
            soft_timer[i].start_flag = 1;
            soft_timer[i].counter = 0;
            soft_timer[i].loop_flag = 0;
            soft_timer[i].duration = duration;
            soft_timer[i].run_mode = run_mode;
            soft_timer[i].callback_function = callback_function;
            if ((soft_timer[i].timing_mode = timing_mode) == DEFINE_NUM_MODE)
                soft_timer[i].run_num = run_num;                     /* 只有在自定义运行次数的情况下此值才有效 */ 
            break;
        }
        if (i == MAX_TIMER_NUM )    /* 没有空闲定时器 */
            return 1;
    }
    return 0;
}


/**
 * 删除一个软件定时器
 */
void stop_timer(void (*callback_function)(void))
{
    unsigned char i;
    for(i = 0; i <MAX_TIMER_NUM; i++)
    {
        if(soft_timer[i].callback_function == callback_function)
        {
            soft_timer[i].start_flag = 0;
            soft_timer[i].loop_flag = 0;
        }
    }
}

/**
 * 系统main循环进程,用于执行轮询模式的回调函数
 */
void soft_timer_main_loop(void)
{
    unsigned char i;
    for(i = 0; i <MAX_TIMER_NUM; i++)            /*  轮询执行回调函数  */
    {
        if(soft_timer[i].loop_flag == 1)
        {
            soft_timer[i].loop_flag= 0;
            soft_timer[i].callback_function();
            // return;                              /*  运行一次任务后就退出去等跑一轮后运行下个程序,防止任务堆积在一起运行  */
        }
    }
}



/**
 * 此函数为tick中断服务函数,需要挂载在外部硬件定时器上
 * 因此软件定时器的定时精度由此函数挂载的硬件定时时间决定,
 * 比如此函数挂载在定时50ms的外部定时器上,那么定时dutation
 * 为20时定时时间就是20*50ms=1S
 */
void system_tick_IrqHandler(void)
{
    unsigned char i = 0;
    
    for(i =0 ;i <MAX_TIMER_NUM; i++)
    {
        if(soft_timer[i].start_flag !=0 )   /* 判断当前定时器是否被开启  */
        {
            if(++soft_timer[i].counter >= soft_timer[i].duration)  /* 判断当前计时有没有到达 */
            {
                switch (soft_timer[i].timing_mode)
                {
                case ONCE_MODE:
                    soft_timer[i].start_flag = 0;
                break;
                case CONTINUE_MODE:
                    break;
                case DEFINE_NUM_MODE:
                    if (soft_timer[i].run_num > 0)
                    {
                        if (--soft_timer[i].run_num == 0)
                        {
                            soft_timer[i].start_flag = 0;
                        }
                    }
                default:
                    break;
                }
                if(soft_timer[i].run_mode == RUN_IN_INTERRUPT_MODE)
                    soft_timer[i].callback_function();   /* 中断内直接运行回调函数,用于实时性比较高的程序 */
                else
                    soft_timer[i].loop_flag = 1;
                soft_timer[i].counter = 0;
            }
            // else
            // {
            //     soft_timer[i].counter++;
            // }
            
        }
    }
}

Guess you like

Origin blog.csdn.net/weixin_41114301/article/details/130549497