个人简介
- 作者简介:大家好,我是喜欢记录零碎知识点的小菜鸟。
- 个人主页:欢迎访问我的 Ethernet_Comm 博客主页
- 支持我:点赞+收藏⭐️+留言
- 系列专栏:嵌入式C编程- 格言:写文档啊不是写文章,重要的还是直白!
MultiTimer 的代码少,非常适合拿来学习单链表的操作,用此实例学习大佬是如何操作单链表的。
MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
目录
- 1. 软件设计思路
- 1.1 MultiTimer 结构体
- 1.2 main函数解析
- 1.3 MultiTimerStart() 函数解析
- 1.4 MultiTimerStop()函数解析
- 1.5 MultiTimerYield() 函数解析
- 2. 参考资料
- 3. 链表的操作
- 3.1 链表尾部增加一个节点
- 3.2 链表头部插入一个新节点
- 3.3 链表的删除
解析:MultiTimer
定义为 单链表 的形式; 链表的节点设计为一个软件定时器,所以理论上支持的定时器数量只受内存限制
每个 MultiTimer
都有一个 deadline
,以开发板系统的tick
为基准周期,时间到达 deadline
,就执行其对应的 callback
MultiTimer
中所有的结点都是定时器,每个定时器之间相互独立,不存在先后次序关系
typedef void (*MultiTimerCallback_t)(MultiTimer* timer, void* userData);
typedef struct MultiTimerHandle {
MultiTimer* next;
uint64_t deadline; // 超时时间
MultiTimerCallback_t callback; // 到达超时时间,就执行 callback
void* userData;
}MultiTimer;
1️⃣ : 【使用步骤】
MultiTimerInstall()
,如使用STM32HAL库,所以通过Systick来提供,无需设置额外的定时器。timer1 / 2 / 3
,注册定时器回调处理函数,设置超时时间(ms)2️⃣ : 【思路解析】
获取系统的当前时间 单位:ms (移植到开发板中时,这个时间可以是开发板的硬件定时器中断)
初始化三个定时器,分别为
timer1
是 1s
执行一次回调,周期执行;
timer2
是 5s
执行一次,单次;
timer3
是 延迟3.456s
开始执行,执行周期为 4567ms
MultiTimerYield()
遍历链表,执行到达 deadline
的链表的callback
MultiTimer timer1;
MultiTimer timer2;
MultiTimer timer3;
int main(int argc, char *argv[])
{
MultiTimerInstall(PlatformTicksGetFunc); // 获取系统的当前时间 单位:ms (移植到开发板中时,这个时间可以是开发板的硬件定时器中断)
MultiTimerStart(&timer1, 1000, exampleTimer1Callback, "1000ms CYCLE timer");
MultiTimerStart(&timer2, 5000, exampleTimer2Callback, "5000ms ONCE timer");
MultiTimerStart(&timer3, 3456, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE timer");
while (1) {
MultiTimerYield();
}
}
timer
时,先判断链表中是否有同样的节点,若有则先移除(避免插入同样的 timer
节点)
int MultiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData)
{
if (!timer || !callback ) {
return -1;
}
MultiTimer** nextTimer = &timerList;
/* Remove the existing target timer. */
while(*nextTimer!=NULL){
if (timer == *nextTimer) {
*nextTimer = timer->next; /* remove from list */
break;
}
nextTimer = &(*nextTimer)->next
}
/* add by me 为了便于理解*/
/*MultiTimer *preTimer = timer; //要插入的节点
MultiTimer *currentTimer = timer->next; // 插入 节点的下一个节点
while(timer->next!=NULL){
if(timer == currentTimer){
timer = currentTimer->next; // remove from list
break;
}
preTimer = currentTimer;
currentTimer = currentTimer->next;
}*/
/* Init timer. */
timer->deadline = platformTicksFunction() + timing;
timer->callback = callback;
timer->userData = userData;
/* Insert timer. */
for (; nextTimer = &timerList; nextTimer = &(*nextTimer)->next) {
if (*nextTimer!=NULL) {
timer->next = NULL;
*nextTimer = timer;
break;
}
/*通过超时时间排序插入*/
if (timer->deadline < (*nextTimer)->deadline) {
timer->next = *nextTimer;
*nextTimer = timer;
break;
}
}
return 0;
}
链表的删除,没啥可说的,上章节已经讲过
二级指针不好理解的,可以自定义用一级指针
因为链表插入时是按照 deadline
时间顺序从小到大插入的,因此循环遍历链表时,按照 deadline
,到时间则执行 callback
,不到时间则继续循环遍历
int MultiTimerYield(void)
{
MultiTimer* entry = timerList;
for (; entry; entry = entry->next) {
/* Sorted list, just process with the front part. */
if (platformTicksFunction() < entry->deadline) {
return (int)(entry->deadline - platformTicksFunction());
}
/* remove expired timer from list */
timerList = entry->next;
/* call callback */
if (entry->callback) {
entry->callback(entry, entry->userData);
}
}
return 0;
}
第6期 | MultiTimer,一款可无限扩展的软件定时器
MultiTimer | 一款可无限扩展的软件定时器
项目地址:https://github.com/0x1abin/MultiTimer
data1
的位置data1
指向的下一个节点 data2
的地址data0->next
指向 data2
data1
的内存释放掉