设计一个在裸机下使用的简单软件定时器(2):软件设计

0 前言

在RTOS中,我们经常用到软件定时器来为我们处理一些对于实时性要求不高的定时任务。在裸机开发中,我们可能也有很多需要定时执行的任务,为了优雅地执行这些定时任务,本文设计一个在裸机下使用的简单软件定时器,提供类RTOS软件定时器的功能。

1 软件设计

为了使软件定时器更加灵活,软件定时器应该具备增加、删除定时任务的功能,因此我们必须设计有增加一个定时器函数、删除一个定时器函数。在《设计一个在裸机下使用的简单软件定时器(1):框架+数据结构分析》中,我们已经知道需要一个时钟滴答获取函数和定时任务回调函数,这样分析下来,我们至少需要设计4个函数。下面是这4个函数的详细设计:

1.1 检查定时器

/*** @brief 检查定时器--中断内执行* */
void check_timer(void)
{timert *p = timerRoot.next;for (; p != NULL; p = p->next){p->tickCount++;if (p->tickCount >= p->cycle){p->runFlg = 1;p->tickCount = 0;}}
}

检查定时器函数放到1ms的定时器中断执行,主要功能是获取时钟滴答,设置定时器任务执行标志。详细流程如下:
遍历所有定时器,将所有定时器的时钟滴答+1,如果时钟滴答大于等于设置的定时器周期,则将回调执行标志置1同时时钟滴答清0,通知主循环内的任务回调函数执行相应任务。

1.2 定时任务处理

/*** @brief 定时任务处理--主循环内执行* */
void timer_task_pro(void)
{timert *last;timert *p = timerRoot.next;for (; p != NULL; p = p->next){if ((p->runFlg == 1) && (p->fun != NULL)){p->fun();p->runFlg = 0;if (p->runType == 1){p->delFlg = 1;}}}p = timerRoot.next;/* 删除无效定时器 */for (; p != NULL; p = p->next){if (p->delFlg == 1){last = p->prev;del_timer(p);p = last;if (p == NULL){break;}}}
}

定时任务处理放到主循环内执行,主要功能是执行使能的定时任务,同时删除无效的定时器。详细流程如下:
(1)执行回调任务
遍历所有定时器,查看任务执行标志是否使能和函数指针是否有效,如果任务执行标志使能且函数指针有效则执行定时任务,执行完定时任务后将任务执行标志失能,同时判断是否属于单次执行任务,如果是单次执行任务则将定时器删除标志使能
(2)删除无效定时器
遍历所有定时器,如果发现定时器的删除标志使能则将定时器从链表删除(删除定时器要失能中断,避免链表异常操作)。

1.3 添加一个定时器

timert timerRoot = {0}; /* 定时器链表根节点 */
/*** @brief 添加一个软件定时器** @param runType 执行方式:0-周期执行 1-只执行一次* @param cycle 执行周期* @param fun 回调函数* @param time 软件定时器*/
void add_timer(uint8_t runType, uint32_t cycle, funp fun, timert *time)
{timert *p = &timerRoot;timert *lastp = p;/* 进入临界区,避免链表异常操作 */__disable_irq();for (; p != NULL; p = p->next){/* 找到最后一个软件定时器 */lastp = p;if (lastp = time){return ;}}lastp->next = time;time->runType = runType;time->cycle = cycle;time->fun = fun;time->prev = lastp;time->next = NULL;time->tickCount = 0;time->runFlg = 0;time->delFlg = 0;__enable_irq();
}

添加一个定时器就是将定时器添加到链表的末尾,同时设置定时器的各项值。详细流程如下:
首先失能中断,避免链表操作被打断(任何对链表的增、删操作都应该保证不被打断),找到最后一个软件定时器,将新增的软件定时器增加到最后一个软件定时器之后,同时设置新增软件定时器的各项初值,最后使能中断。

1.4 删除一个定时器

/*** @brief 删除一个软件定时器** @param time 定时器*/
void del_timer(timert *time)
{int findFlg = 0;timert *p = &timerRoot;/* 进入临界区,避免链表异常操作 */__disable_irq();/* 判断是否还在定时器链表内 */for (; p != NULL; p = p->next){if (p == time){findFlg = 1;break;}}if (findFlg == 1){p = time->prev;if (p != NULL){p->next = time->next;}p = time->next;if (p != NULL){p->prev = time->prev;}time->prev = NULL;time->next = NULL;}__enable_irq();
}

删除一个定时器就是将定时器从链表中删除。详细流程如下:
首先失能中断,避免链表操作被打断(任何对链表的增、删操作都应该保证不被打断),判断定时器是否还在链表内,如果还在链表内则将其删除,最后使能中断。

2 总结

(1)一个简单的软件定时器软件设计主要包括检查定时器、定时任务处理、增加一个定时器、删除一个定时器四个方面。
(2)对定时器链表的增、删操作一定不要被打断,否则将可能导致异常的链表操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/195420.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPS论文写作——公式和公式序号格式化

首先新建一个表格,表格尺寸按你的需求来确定,直接 插入--》表格 即可。 然后在表格对应位置填上公式(公式要用公式编辑器)和公式序号,然后可以按照单独的单元格或者整行或整列等来设置样式,比如居中对齐、…

电脑监控软件的监控方式有哪些

电脑监控软件是一种用于监视和控制计算机操作的工具,通常用于企业或个人对计算机的使用情况进行监控和管理。本文将探讨电脑监控软件的监控方式及其存在的问题。 首先,电脑监控软件的监控方式主要包括以下几种: 1、屏幕监控:这种…

【23-24 秋学期】NNDL 作业10 BPTT

习题6-1P 推导RNN反向传播算法BPTT. 习题6-2 推导公式(6.40)和公式(6.41)中的梯度. 习题6-3 当使用公式(6.50)作为循环神经网络的状态更新公式时, 分析其可能存在梯度爆炸的原因并给出解决方法. 习题6-2P 设计简单RNN模型,分别…

洛谷P1044 [NOIP2003 普及组] 栈 递归方法

目录 核心: 问题转化: 状态转化:(你得先读懂题,理解我们要干什么) 对应不同情况下的状态转化:(比如栈空就不能出栈,,) AC代码: 题…

【每日OJ —— 110. 平衡二叉树】

每日OJ —— 110. 平衡二叉树 1.题目:110. 平衡二叉树2.解法2.1.算法讲解2.2.代码实现2.3.提交通过展示 1.题目:110. 平衡二叉树 2.解法 2.1.算法讲解 1.这道题中的平衡二叉树的定义是:二叉树的每个节点的左右子树的高度差的绝对值不超过 11…

Android12之MediaCodec硬编解码调试手段(四十九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

发送xml格式的http请求工具类

发送xml格式的http请求 package com.yannis.utils;import com.google.gson.Gson; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; import…

继续画图带你学习TCP 其他 7 大特性

四、滑动窗口机制 五、流量控制 六、拥塞控制 (安全机制) 七、延迟应答 (效率机制) 八、捎带应答 (效率机制) 九、粘包问题 十、保活机制 TCP总结 四、滑动窗口机制 滑动窗口机制,是在可靠性的前提下,进一步地提高传输效率 认识滑动窗口 一发一收…

vscode的eslint检查代码格式不严谨的快速修复

问题: 原因:复制的代码,esLint检查代码格式不正确。或者写的代码位置不严谨,总是提示 解决 设置在Ctrl S保存时自动格式化代码 1、vscode设置 2、点击右上角,切换json模式 3、添加设置 "editor.codeActionsOn…

JavaScript中使用JSON的基本操作示例

简介 JSON(JavaScript Object Notation)是一种数据交换格式,也是JavaScript中处理数据的常见方式之一。JSON是一种轻量级的数据交换格式,易于阅读和编写,同时也易于解析和生成。在JavaScript中,可以使用内…

Linux gdb调试(总结)

1 gdb的作用 gdb 是 GNU 发布的一个强大的程序调试工具,也是 Linux 程序员不可或缺的一大利器。 2 gdb的使用: (1) 调试讲解的代码 //---------addsub.h--------- #pragma once int jfx_addition (int* a, int* b); int jfx_subtraction (int* a, int* b);//---------adds…

Rust UI开发(五):iced中如何进行页面布局(pick_list的使用)?(串口调试助手)

注:此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库,用于为rust语言程序构建UI界面。 这是一个系列博文,本文是第五篇,前四篇链接: 1、Rust UI开发(一):使用iced构建UI时…

【零基础入门Python】Python If Else流程控制

✍面向读者:所有人 ✍所属专栏:零基础入门Pythonhttps://blog.csdn.net/arthas777/category_12455877.html Python if语句 Python if语句的流程图 Python if语句示例 Python If-Else Statement Python if else语句的流程图 使用Python if-else语句 …

JVM 运行时内存篇

面试题: 讲一下为什么JVM要分为堆、方法区等?原理是什么?(UC、智联) JVM的分区了解吗,内存溢出发生在哪个位置 (亚信、BOSS) 简述各个版本内存区域的变化&#xff1…

木质家具行业分析:我国市场规模总资产达1669.19亿元

木质家具是指以天然木材和木质人造板为主要材料,配以其他辅料(如油漆、贴面材料、玻璃、五金配件等)制作各种家具的生产活动。 近年来实木家具越来越受到广大消费者的青睐。继板式家具、板式定制家具之后,板木家具与整木定制家具渐渐走进人们的视野。但目…

酵母双杂交服务专题(四)

关于酵母双杂交服务的常见问题 问题1:酵母双杂交的筛选流程? 研究者将特定基因作为钓饵,在一个精心挑选的cDNA文库中进行筛选,目的是找到与该钓饵蛋白发生相互作用的蛋白质。通过这种筛选,可以从阳性反应的酵母菌株中…

python处理的例子

例子一(咖啡列表的处理) 把 coffee_list [ 32Latte, _Americano30,/34Cappuccino, Mocha35]输出为: 1 Latte 2 Americano 3 Cappuccino 4 Mocha def clean_list(lst):cleaned_list []for item in lst:for c in item:if c.isalpha() ! Tr…

Cesium 顶点吸附和区域拾取

Cesium 顶点吸附和区域拾取 基于深度实现可以自定义拾取范围大小 // 顶点吸附// const result pickAreaHelper.pickNearest(viewer.scene, movement.endPosition, 32, 32);// 区域拾取const result pickAreaHelper.pickArea(viewer.scene, movement.endPosition, 32, 32);顶…

新生儿规避感染的完全指南

引言: 新生儿的免疫系统尚处于发育阶段,对外界环境的抵抗力相对较弱。因此,规避感染成为父母在新生儿护理中至关重要的一环。本文将深入探讨新生儿规避感染的注意事项,为父母提供详尽的指南,以确保宝宝健康成长。 第一…

树莓派Python程序开机自启动(Linux下Python程序开机自启动)

前一阵子用python编写了一个驱动I2C程序读写屏幕,输出IP的小程序,程序编好后需要树莓派使能程序开机自启动。其实这些方法对任何Linux系统都适用。 方法一:此方法的缺点是不进入默认pi的账号,甚至不开hdmi开启桌面的话&#xff0…