MultiTimer|一款可无限扩展的软件定时器

嵌入式大杂烩 2022-05-04 21:34

前言

嵌入式开源项目精选专栏之前发布过一篇关于MultiTimer的文章, MultiTimer | 一款可无限扩展的软件定时器,这周有小伙伴在群里提醒我 MutilTimer 和文章写的不太一样,第一反应是重构了,大佬们技术水平提升一个段位后都喜欢重构项目,去github看看发生了什么。

master分支上还是之前的v1版本,和文章是一样的:



development分支上果然重构了项目,发布了v2版本:



同步更新下教程。

一、MultiTimer

本期给大家带来的开源项目是 MultiTimer,一款可无限扩展的软件定时器,作者0x1abin,目前收获 399 个 star,遵循 MIT 开源许可协议。

MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。

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

二、移植MultiTimer

1. 移植思路

开源项目在移植过程中主要参考项目的readme文档,一般只需两步:

  • ① 添加源码到裸机工程中;
  • ② 实现需要的接口;

本文中我使用的是小熊派IoT开发套件,主控芯片为STM32L431RCT6:

移植之前需要准备一份裸机工程,我使用STM32CubeMX生成,需要初始化以下配置:

  • 配置一个串口用于打印信息
  • printf重定向

2.MDK移植

① 复制MultiTimer源码到工程中:


② 在keil中添加 MultiTimer的源码文件:


③ 将MultiTimer头文件路径添加到keil中:

3. gcc移植

① 复制MultiTimer源码到工程中:


② 在 Makefile 中添加 MultiTimer的源码文件:


③ 添加MultiTimer头文件路径:

三、使用MultiTimer

使用时包含头文件:

#include "multi_timer.h"

1. 提供Timer时基信号

MultiTimer中的时基信号需要安装,API如下:

/**
 * @brief Platform ticks function.
 * 
 * @param ticksFunc ticks function.
 * @return int 0 on success, -1 on error.
 */

int MultiTimerInstall(PlatformTicksFunction_t ticksFunc);

PlatformTicksFunction_t 函数指针定义如下:

typedef uint64_t (*PlatformTicksFunction_t)(void);

本文中使用的是STM32HAL库,所以通过Systick来提供,无需设置额外的定时器。

编写获取系统 tick 的函数:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint64_t PlatformTicksGetFunc(void)
{
  return (uint64_t)HAL_GetTick();
}
/* USER CODE END 0 */

在main函数中安装该tick函数:

/* USER CODE BEGIN 2 */
printf("MultiTimer v2 Port on BearPi board by mculover666!\r\n");
MultiTimerInstall(PlatformTicksGetFunc);
/* USER CODE END 2 */

2. 创建Timer对象

软件定时器抽象为 MultiTimer 结构体:

struct MultiTimerHandle {
    MultiTimer* next;
    uint64_t deadline;
    MultiTimerCallback_t callback;
    void* userData;
};

typedef struct MultiTimerHandle MultiTimer;

所以直接使用 MultiTimer 类型创建软件定时器:

/* USER CODE BEGIN PV */
MultiTimer timer1;
/* USER CODE END PV */

3. Timer回调函数

回调函数类型定义如下:

typedef void (*MultiTimerCallback_t)(MultiTimer* timer, void* userData);

按照回调函数格式,创建超时回调函数:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void timer1_callback(MultiTimer* timer, void* userData)
{
    printf("timer1 timeout!\r\n");
}
/* USER CODE END 0 */

4. 初始化并启动Timer

启动定时器的API如下:

/**
 * @brief Start the timer work, add the handle into work list.
 * 
 * @param timer target handle strcut.
 * @param timing Set the start time.
 * @param callback deadline callback.
 * @param userData user data.
 * @return int 0: success, -1: fail.
 */

int MultiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData);

初始化定时器对象,注册定时器回调处理函数,设置超时时间(ms):

/* USER CODE BEGIN 2 */
printf("MultiTimer v2 Port on BearPi board by mculover666!\r\n");
MultiTimerStart(&timer1, 1000, timer1_callback, NULL);
/* USER CODE END 2 */

5. Timer对象处理

Timer对象处理函数API定义如下:

/**
 * @brief Check the timer expried and call callback.
 * 
 * @return int The next timer expires.
 */

int MultiTimerYield(void);

在主循环中调用Timer对象处理函数,处理函数会判断链表上的每个定时器是否超时,如果超过,则拉起注册的回调函数:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  MultiTimerYield();
}
 /* USER CODE END 3 */

接下来编译下载,看在串口助手中看到打印的日志:

四、如何循环触发

在定时器超时函数中,重启定时器即可。

void timer1_callback(MultiTimer* timer, void* userData)
{
    printf("timer1 timeout!\r\n");

    // restart
    MultiTimerStart(&timer1, 1000, timer1_callback, NULL);
}

五、设计思想解读

相对于v1版本,v2版本明显涉及简洁很多,c文件实现只有4个函数,82行代码。

v2版本中使用注册机制由用户提供tick,这样设计有个好处是,可移植性更强,无需干预系统tick中断,只有MultiTimer得到调度的时候,它才可以通过我们安装的API获取到系统tick,以此为基准来判断定时器是否超时。

v2版本还优化了链表插入机制,之前是简单粗暴直接单链表插入节点,现在通过超时时间排序插入,更加优雅:

除了插入的更加优雅之外,这样做还有两个对于软件定时器性能的提升,在调度的时候:

  • 超时时间近的定时器总能得到优先处理
  • 前面的定时器还未超时,可以直接结束调度

软件定时器实现思想可以参考之前v1版本的教程。

猜你喜欢:

分享嵌入式软件调试方法及几个有用的工具!

嵌入式大杂烩周记 | 第 6 期 FlexibleButton

在公众号聊天界面回复1024,可获取嵌入式资源;回复 ,可查看文章汇总。

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论 (0)
  • 概述        TC10 为OPEN Alliance 中的一个技术委员会小组,专注于研究基于车载以太网的休眠唤醒机制,旨在为汽车应用场景提供灵活的休眠唤醒解决方案。该小组提出的休眠唤醒规范(《TC10 Sleep/Wake-up Specification》,以下简称TC10规范)作为对IEEE 802.3系列规范的补充,详细定义了以太网PHY的休眠唤醒过程、新增服务原语和接口、时间参数、指令描述等内容。目前,TC10已经发布了适配10Ba
    经纬恒润 2025-02-18 14:30 164浏览
  • 引言:为什么THA6能成为“国产芯”的破局者?当全球汽车行业因芯片短缺陷入“卡脖子”困境时,紫光同芯的THA6系列车规MCU横空出世,不仅填补了国产高端MCU的空白,更凭借“功耗控制”与“热管理”两大杀手锏,直接对标国际大厂英飞凌TC387。北京贞光科技作为授权代理商,提供硬件、软件SDK及技术支持,并可现场协助芯片选型和定制服务,助力客户项目高效落地。从动力域控制到智能驾驶系统,THA6的足迹遍布新能源汽车核心场景。数据显示,其主频高达400MHz,算力超4000 DMIPS,却能在-40℃至
    贞光科技 2025-02-19 17:17 112浏览
  • 故障现象 一辆2013款奔驰S300L车,搭载272 946发动机,累计行驶里程约为15万km。车主反映,将挡位置于D挡,稍微释放一点制动踏板,车辆蠕动时车身明显抖动,类似气缸失火时的抖动,又类似手动变速器,离合器片不平,起步半离合时的那种抖动;完全释放制动踏板后,抖动现象消失,且车辆行驶无明显异常。为此更换过火花塞、点火线圈,清洗过燃油管路,故障依旧;接着又大修了自动变速器,并更换了液力变矩器,但故障依然存在,于是将车开至我厂进行检修。 故障诊断 接车后试车,确认故障现象与车主所述一
    虹科Pico汽车示波器 2025-02-19 14:14 129浏览
  • 嘿,大家好!在高压电子世界里摸爬滚打的朋友们,你们有没有遇到过这样的难题?那就是,如何选择适合高压环境的光颉精密电阻? 这可不是一个简单的问题,毕竟在高压环境下,电阻不仅要顶得住电压的“压力”,还得保证精度和稳定性,这要求可真不低。想想看,如果选错了电阻,就像给跑车装了个自行车轮,那能行吗?肯定不行!轻则电路性能大打折扣,重则电阻直接“罢工”,甚至引发更严重的后果。所以说,在高压应用中,选择一款靠谱的光颉精密电阻,那可是至关重要的。别担心,今天咱们就来好好聊聊,如何选择适合高压环境的光
    贞光科技 2025-02-18 17:28 157浏览
  • 故障现象 一辆2010款路虎揽胜车,搭载5.0 L发动机,累计行驶里程约为16万km。车主反映,接通空调开关后,有时出风忽大忽小,有时不出风,有时要等2 min左右才出风;有时两三天出现一次,有时好几天才出现一次,故障没有规律。 故障诊断接车后试车,故障现象并未出现。使用故障检测仪检测,在空调控制单元(HVAC)中存储有故障代码“U1000-00 固态驾驶员保护微活-驾驶员已禁用”。查看该故障代码相关说明,可能的原因为中央接线盒输出电路对搭铁或电源短路,这与空调出风故障没有关联。如图1
    虹科Pico汽车示波器 2025-02-19 13:49 95浏览
  • 概述        在上一篇文章中,我们了解了TC10规范的内容,并掌握了基于以太网链路的物理层休眠唤醒机制。为了确保不同厂商的设备在以太网休眠唤醒功能上的互操作性,OPEN Alliance制定了详细的测试规范。测试规范        针对以太网休眠唤醒机制的测试,包含在各个以太网速率下的IOP测试规范中,具体如下:《10BASE-T1S Interoperability Test Suite》《100BASE-T
    经纬恒润 2025-02-19 13:20 139浏览
  • 清晨,闹钟准时响起,窗帘自动拉开,床灯随之亮起,音箱中则自动传出每日的早间新闻,从而唤醒熟睡中的你,而这只是智能家居中的冰山一角。作为人类群体追求更高生活品质的居住空间,智能家居正飞速普及至我们的日常生活之中,极大地提升了生活的便利性与舒适度。然而,随着单品智能向全屋智能的快速发展,不同智能家居设备的工作电压与通信频率等运行参数存在差异,它们共同运行在一个智能家居系统之中,其所产生的电气噪声与电磁干扰会互相影响,并形成潜在的安全隐患。例如,电气噪声可能导致线路过热,增加电气火灾的发生风险;电磁干
    华普微HOPERF 2025-02-18 10:48 112浏览
  • 过去一年,厨电行业的AI竞赛进入“大模型时代”,各大品牌纷纷亮出了自己的杀手锏。老板电器的“食神大模型”、方太的“Healthy CookingGPT”轮番登场,两者都立志要用AI“重新定义厨房”。新的一年,大模型技术的不断成熟与迭代,AI将不再仅仅是概念上的炒作,而是真正融入到每一个厨房场景中。这场在厨电领域内悄然进行的“科技革命”无疑将步入一个更为深入且广泛的实践应用阶段,AI厨电狂欢开始了。AI厨电“燃”起来了众所周知,厨电行业的发展与房地产市场密切相关。随着房地产市场的调整,新房装修需求
    刘旷 2025-02-19 10:51 135浏览
  •  电磁铁的磁芯材质:软铁还是硬铁电磁铁的磁芯通常采用软铁材质,因其具有高磁导率和低矫顽力,使得电磁铁能够在通电时迅速产生强磁场,断电后磁场又能迅速消失。一、电磁铁与磁芯材质电磁铁是一种利用电流产生磁场的装置。其核心部件——磁芯,对电磁铁的性能有着至关重要的影响。在选择磁芯材质时,需要考虑多种因素,如磁导率、矫顽力、饱和磁化强度等。这些因素直接关系到电磁铁的工作效率、响应速度和能耗等方面。二、软铁与硬铁的特性软铁和硬铁是两种常见的磁性材料。软铁具有高磁导率和低矫顽力的特点,这意味着它容易
    锦正茂科技 2025-02-18 10:32 86浏览
  • 如何更有效地融合竞争、可持续与协作策略,从而彻底革新晶圆制造厂与半导体生产方式,进而提升效率与性能?这正是与electronica 2024同期举办的晶圆厂管理论坛所探讨的核心议题。该论坛堪称欧洲电子制造业领域最具影响力的盛会。艾迈斯欧司朗 “移动与照明” 业务线高级副总裁Wolfgang Lex与众多来自欧洲半导体及电子产业界的代表及论坛委员会成员齐聚一堂,共同分享行业洞见。在“汽车光子技术之旅”主题演讲中,Lex深入探讨了光智能(简称OI)在弥补人工智能与机器和、人之类间“最后一公里”距离中
    艾迈斯欧司朗 2025-02-19 19:23 71浏览
  • 随着国内市场的逐渐稳固,华为将目光投向了广阔的海外市场,开启了一段充满挑战与机遇的国际化征程。然而,华为在拓展海外市场时,遭遇了重重困难。文化差异带来的挑战不同国家和地区有着不同的文化背景、商业习惯和价值观,这使得华为在与当地客户、合作伙伴沟通和合作时面临诸多障碍。在欧洲,一些客户对产品的认证标准和售后服务有着非常严格的要求,并且注重商务活动中的礼仪和沟通方式。在机上欧洲通信市场竞争激烈,爱立信、诺基亚等本土企业在技术、品牌和市场份额上具有优势。而且欧洲各国的通信标准和监管政策不同,华为需要满足
    韭菜财经 2025-02-18 14:11 233浏览
  • 这是一个3.3V 的供电开关,给WIFI模块供电。目的是能控制WIFI模块通电或断电。VCC_3V3 是电源,当WLENN为低时,Q1打开输出VCCW 给WIFI模块供电。实际使用时,当控制WLENN为低给模块供电时,MCU异常程序跑飞。不安装模块时不会跑飞。测试MCU的 3.3V供电,发现在WLENN为低时,3.3V会拉低到2V左右时间5uS。判断认为是瞬间电压过低引起程序跑飞。而WIFI模块通电瞬间电流较大,引起3.3V供电不稳。试着将电路更改一下。将连接到输出端VCCW的电容移动到输入端V
    southcreek 2025-02-20 13:35 82浏览
  • 新技术的快速发展,其实与企业的管理机制、企业文化,甚至团队氛围、职场理念等方面非常相关!最近看到某平台有人吐槽00后实习生难带,进而又说到正常的工作安排被实习生莫名拉黑了。我就在人家的笔记评论区里写了我的观点(劝架风格),当然不出意料的就被更多的陌生人给围攻了!说起应届生的事情,可能是我一直长得年轻、又是个很较真很技术的人,我在多家企业里总被不同性格的老板拉去管“校企打杂”(所谓的领先企业应尽的社会责任,是连HR们都看不上的义务工作,给大学讲行业的意义和专业的意义)。我早就习惯了一种常见现象,像
    牛言喵语 2025-02-20 02:23 114浏览
我要评论
0
2
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦