0%

超精简的软件定时器:multitimer

概括

在裸机开发中,经常要使用定时器来实现某些定时功能,面对需要比较多定时器的场合,以前都是使用一个吻硬件定时器作为提供时间基准,然后使用计数器+标志位的方法来实现,其实就是采用时间片的方法。

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while(1)
{
// 2ms执行 软件时钟系统
if(1 == sys_var._1msFlag)
{
sys._1msFlag = 0; // 该标志由定时器中断置位

clock_system(); // 管理各种时间标志(将各个时钟标志置位)
}

// 200ms执行
if(1 == sys_var.System200msFlag)
{
sys_var.System200msFlag = 0;
// 执行各种任务
}
}

现在发现了某位大佬开源的软件定时器multi_timer项目,令人耳目一新。
很棒的是,软件定时器multi_timer 将上面的方法抽象出来,同样也是基于一个硬件定时器,但是无需自己在while循环上加各种判断语句,让程序看起来更加简洁,更加好维护。

multi_timer的使用方法

1、定义一个multi_timer结构体变量

1
Timer timer1 ;

2、注册并初始化multi_timer定时器
1
timer_init(&timer1, timer1_callback, TIMER_TIMEOUT_500MS, TIMER_TIMEOUT_500MS);

3、启动multi_timer定时器
1
timer_start(&timer1);

4、设置1ms硬件定时器循环调用计数器以提供时基
1
2
3
4
void xxx_callback(void)
{
timer_ticks();
}

5、在while循环中循环调用multi_timer的后台处理函数
1
2
3
4
5
while(1)
{
//....
timer_loop();
}

项目源代码和个人的注释

multi_timer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_

#include "stdint.h"

typedef struct Timer {
uint32_t timeout; // 超时时间(用来与定时器心跳比较)
uint32_t repeat; // 循环定时触发时间(周期定时设置),为0时代表单次定时
void (*timeout_cb)(void); // 定时器回调处理函数
struct Timer* next; // 指向下一个定时器节点
}Timer;

#ifdef __cplusplus
extern "C" {
#endif

void timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat);
int timer_start(struct Timer* handle);
void timer_stop(struct Timer* handle);
void timer_ticks(void);
void timer_loop(void);

#ifdef __cplusplus
}
#endif

#endif


multi_timer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#include "multi_timer.h"
//timer handle list head.
static struct Timer* head_handle = NULL;
//Timer ticks
static uint32_t _timer_ticks = 0;

/**
* @brief Initializes the timer struct handle.
* @param handle: the timer handle strcut.
* @param timeout_cb: timeout callback.
* @param repeat: repeat interval time.
* @retval None
*/
void timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat)
{
handle->timeout_cb = timeout_cb;
handle->timeout = _timer_ticks + timeout;
handle->repeat = repeat;
}

/**
* @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 None
*/
void timer_stop(struct Timer* handle)
{
struct Timer** curr;
for(curr = &head_handle; *curr; ) {
struct Timer* entry = *curr;
if (entry == handle) {
*curr = entry->next; // 将当前节点脱离队列
} else
curr = &entry->next; // 二级指针curr不断后移
}
}

/**
* @brief main loop.
* @param None.
* @retval None
*/
void timer_loop() // 在While循环中使用,定时器才会起作用
{
struct Timer* target;
for(target=head_handle; target; target=target->next) {
if(_timer_ticks >= target->timeout) {
if(target->repeat == 0) {
timer_stop(target);
} else {
target->timeout = _timer_ticks + target->repeat;
}
target->timeout_cb();
}
}
}

/**
* @brief background ticks, timer repeat invoking interval 1ms.
* @param None.
* @retval None.
*/
void timer_ticks() // 在定时器中断中调用该函数
{
_timer_ticks++;
}

项目的仓库地址:https://github.com/0x1abin/MultiTimer