一个好用的软件定时器模块MultiTimer

在嵌入式软件中,常常采用顺序式的编程结构。有一些需要定时执行的逻辑在主程序中不断的进行轮询时间,时间到了执行程序。这样程序中会存在大量的时间变量不方便统一处理,以一种比较分散的方式进行计时以及时间清零的操作。本文介绍一个好用的定时器模块,将计时服务进行统一管理,通过回调函数的方式执行定时的相关逻辑。

原作者0x1abin,源代码https://github.com/0x1abin/MultiTimer

致敬原作者!

本文在arduino UNO开发板上试用了定时模块代码,进行了略微的修改,模块代码包含一个.h一个.cpp文件,如下:

.h文件


#ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_

#include <stdint.h>
#include <stddef.h>

 /*
 It means 1 tick for 1ms.
 Your can configurate for your tick time such as 5ms/10ms and so on.
 */
#define CFG_TIMER_1_TICK_N_MS   1

typedef struct Timer {
    uint32_t        cur_ticks;          /* Record current timer start tick */
    uint32_t        cur_expired_time;   /* Record current timer expired time */
    uint32_t        timeout;    /* Delay (xx ms) time to start tiemr */
    uint32_t        repeat;     /* Timer interval expired time (xx ms) */
    void*           arg;        /* Input argument for timeout_cb function */
    void            (*timeout_cb)(void* arg); /* Timer expired callback function */
    struct Timer* next;       /* Pointer to next timer */
} Timer;

#ifdef __cplusplus  
extern "C" {
#endif  

    typedef void(*Timeout_CB)(void* arg);
    /**
      * @brief  Initializes the timer struct handle.
      * @param  handle: the timer handle strcut.
      * @param  timeout_cb: timeout callback.
      * @param  timeout: delay to start the timer.
      * @param  repeat: repeat interval time.
      * @param  arg: the input argument for timeout_cb fucntion.
      * @retval None
      */
    void timer_init(struct Timer* handle, Timeout_CB, \
        uint32_t timeout, uint32_t repeat, void* arg);

    /**
      * @brief  Start the timer work, add the handle into work list.
      * @param  btn: target handle strcut.
      * @retval 0: succeed. -1: already exist.
      */
    int  timer_start(struct Timer* handle);

    /**
      * @brief  Stop the timer work, remove the handle off work list.
      * @param  handle: target handle strcut.
      * @retval 0: succeed. -1: timer not exist.
      */
    int timer_stop(struct Timer* handle);

    /**
      * @brief  background ticks, timer repeat invoking interval nms.
      * @param  None.
      * @retval None.
      */
    void timer_ticks(void);

    /**
      * @brief  main loop.
      * @param  None.
      * @retval None
      */
    void timer_loop(void);

#ifdef __cplusplus
}
#endif

#endif

.cpp文件:

#include <stdio.h>
#include "MultiTimer.h"

//timer handle list head.
static struct Timer* head_handle = NULL;

//Timer ticks
//static uint32_t _timer_ticks = (1 << 32)- 1000; // only for test tick clock overflow
static uint32_t _timer_ticks = 0;

/**
  * @brief  Initializes the timer struct handle.
  * @param  handle: the timer handle strcut.
  * @param  timeout_cb: timeout callback.
  * @param  timeout: delay to start the timer.
  * @param  repeat: repeat interval time.
  * @param  arg: the input argument for timeout_cb fucntion.
  * @retval None
  */
void timer_init(struct Timer* handle, Timeout_CB timeout_cb, \
    uint32_t timeout, uint32_t repeat, void* arg)
{
    // memset(handle, sizeof(struct Timer), 0);
    handle->timeout_cb = timeout_cb;
    handle->timeout = timeout;
    handle->repeat = repeat;
    handle->cur_ticks = _timer_ticks;
    handle->cur_expired_time = handle->timeout;
    handle->arg = arg;
    //printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u, timeout: %u\r\n", 
    //  handle->cur_ticks, handle->cur_expired_time, _timer_ticks, timeout);
}

/**
  * @brief  Start the timer work, add the handle into work list.
  * @param  btn: target handle strcut.
  * @retval 0: succeed. -1: already exist.
  */
int timer_start(struct Timer* handle)
{
    struct Timer* target = head_handle;

    while (target) {
        if (target == handle) {
            return -1;  //already exist.
        }
        target = target->next;
    }
    handle->next = head_handle;
    head_handle = handle;

    return 0;
}

/**
  * @brief  Stop the timer work, remove the handle off work list.
  * @param  handle: target handle strcut.
  * @retval 0: succeed. -1: timer not exist.
  */
int timer_stop(struct Timer* handle)
{
    struct Timer** curr;

    for (curr = &head_handle; *curr;) {
        struct Timer* entry = *curr;
        if (entry == handle) {
            *curr = entry->next;
            //free(entry);
            return 0; // found specified timer
        }
        else {
            curr = &entry->next;
        }
    }

    return 0;
}

/**
  * @brief  main loop.
  * @param  None.
  * @retval None
  */
void timer_loop(void)
{
    struct Timer* target;
    for (target = head_handle; target; target = target->next) {
        if (_timer_ticks - target->cur_ticks >= target->cur_expired_time) {
            //printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u\r\n", 
            //        target->cur_ticks, target->cur_expired_time, _timer_ticks);
            if (target->repeat == 0) {
                timer_stop(target);
            }
            else {
                target->cur_ticks = _timer_ticks;
                target->cur_expired_time = target->timeout;
            }
            target->timeout_cb(target->arg);
        }
    }
}

/**
  * @brief  background ticks, timer repeat invoking interval nms.
  * @param  None.
  * @retval None.
  */
void timer_ticks(void)
{
    _timer_ticks += CFG_TIMER_1_TICK_N_MS;
}

模块提供的接口如下:

定时器的注册:

    void timer_init(struct Timer* handle, Timeout_CB, \
        uint32_t timeout, uint32_t repeat, void* arg);

定时器启动和停止:

    int  timer_start(struct Timer* handle);
    int timer_stop(struct Timer* handle);

和底层代码的接口:

将timer_ticks放在1ms中断中执行,驱动定时器模块的计数

void timer_ticks(void);

定时器任务:

将timer_loop放在主程序中执行,检查链表中的所有定时器是否触发即使周期。

void timer_loop(void);

使用示例,本文在arduino开发板上使用:

创建一个定时器timer1,编写一个定时器回调函数

#include "userLed.h"
#include "MultiTimer.h"

struct Timer timer1;

void Timer1CallBack(void* arg)
{
	static	unsigned char state = HIGH;
	digitalWrite(LED, state);
	state = (HIGH == state) ? LOW : HIGH;
}

在任务初始化中注册timer1,并打开定时器,主程序中调用timer_loop

void TaskTimer::setup() {
    MsTimer2::set(1, timer_ticks); 
    MsTimer2::start(); 
	timer_init(&timer1, Timer1CallBack, 500, 500,0);
	timer_start(&timer1);
}

void TaskTimer::loop() {
	timer_loop();
}

该定时器模块通过链表来定时器的管理,可以很方便的添加定时器。需要注意的是,定时器的更新和回调函数的执行都是在timer_loop函数中实现的,回调函数中不应该有过于复杂的逻辑或者延时逻辑,否则将可能出现某些定时器无法正常更新,栈空间的资源占用过多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用和引用中的内容,CH582开发板中使用的定时器是TIM2,并且推荐使用systick定时器来进行精确的延时。所以,CH582的定时器延时函数的使用步骤如下: 1. 配置定时器和延时函数:首先需要配置定时器(可以是基本定时器,也可以是TIM2)和串口的配置,同时还需要配置延时函数(推荐使用systick定时器)来实现精确的延时功能。 2. 编写程序:在程序中定义两个IO口,将其连接到Trig引脚上,用于触发定时器。然后,通过调用定时器延时函数,设置需要延时的时间,然后执行延时操作。 需要注意的是,具体的定时器延时函数的编写可能会因为不同的开发板和开发环境而有所不同。因此,在使用定时器延时函数之前,建议查阅开发板的相关文档和资料,以了解具体的函数接口和使用方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [CH582使用MultiTimer软件定时器](https://blog.csdn.net/gg1658608470/article/details/128054432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [STM32单片机 关于超声波模块的学习(1)](https://download.csdn.net/download/weixin_38590520/14032857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值