你可以拖延,但时间不会。本杰明·富兰克林
时间的唯一原因是一切都不会一下子发生。艾尔伯特爱因斯坦
我们所要做的就是决定如何处理给我们的时间。JRR托尔金
我不能说比这些伟大的人更好!
在我们的草图中管理时间是我们需要经常做的事情,通过明智地使用计时器,我们能够有效地设计、管理和处理时间驱动的事件。
本文提供了一种在您的草图中使用任意数量的计时器的技术(方法),每个计时器都是独立的、非阻塞的,并且它们都可以同时运行。该技术易于理解,易于实现,不使用 delay() 函数,也不需要最终用户实现定时器中断服务程序 (ISR)。
很多时候我们需要定期做一些事情,例如每 1/100 秒读取一次传感器,跟踪和处理超时,每 1/2 秒处理一次心跳,等等。在这种情况下,我们需要使用一个或多个计时器来确保我们可以做所有我们需要做的事情。这就是本文提供的技术 (ez_timers) 非常有用的地方。
在这篇文章中,一个草图定义了您在草图中实现 ez_timers 提供的技术所需的所有数据和功能,您可以在此基础上进行草图设计、决策控制和流程。
为了展示该技术的简单性和强大功能,提供了一个基于多个 LED(八个)的示例,每个 LED 由各自的定时器控制,以不同的时间间隔打开和关闭它们。正如将要看到的,该技术以直接和简洁的方式实现。它很容易扩展到很多很多用途。
在我们开始看示例草图之前,让我们看一下 ez_timers 技术和代码的组成部分。
ez_timers 有两个部分:
1. 其数据结构和数据要求,以及
2. 一些终端用户可访问的简单功能。
让我们来看看其中的每一个:
一、数据结构和数据要求
#define max_timers 8
#define elapsed true
#define not_elapsed !elapsed
#define active true
#define not_active !active // double defined for user preference
#define inactive not_active // double defined for user preference
uint8_t timer; // general variable for use dealing with timers
// timer control struct(ure)
struct timer_control {
bool timer_status; // records status of a timer - active or not active
uint32_t start_time;// records the millis time when a timer is started
} timers[max_timers];// declare an entry for each timer - 0:(max_timers-1)
我们首先注意到的是宏' max_timers
'。在“开箱即用”(OOTB)草图中,它设置为 8,因此草图将在编译时将自身配置为 8 个计时器。然后这些将可从 0 到 7 引用。使用此宏定义您希望在草图中配置多少个计时器。
接下来,我们将看到 ez_timer 函数使用的许多宏,最终用户代码也可以/应该使用这些宏来测试特定条件的状态。不过,在这一点上,我只观察到其中两个宏可以相同地使用,具体取决于最终用户的偏好。它们是 ' not_active
' 和 ' inactive
' - 它们是同一个东西。当我们讨论 ez_functions 时,更多关于使用这些宏的上下文。
下一个声明只是一个无符号字节,timer
可以在整个草图中用作工作变量来引用任何计时器(最多 255 个),例如,在 for 循环等中。
ez_timers 的核心是数据结构(ure)' timer_control
'。这定义了两个数据项/类型,它们是 ' timer_status
' ( bool
) 和 ' start_time
' ( uint32_t
- 无符号 32 位整数)。每个配置的计时器在此结构中都有自己的条目,从 0 到 (' max_timers
' -1)。' timer_control
' 数据类型 struct(ure) 然后被声明为 ' timers
'。此数据结构(ure)使用' timers
'引用,例如' timers[2].timer_status
'、' timers[timer].start_time
'等。
2.ez_timerFunctions
只有三个 ez_timer 函数:
//
// set the given timer active and note start time in milliseconds
//
void start_timer(uint8_t timer) {
if (timer < max_timers) {
// valid timer
timers[timer].timer_status = active; // mark this timer as active
timers[timer].start_time = millis(); // record time this timer is started
}
}
//
// cancel (stop) the given timer
//
void stop_timer(uint8_t timer) {
if (timer < max_timers) {
// valid timer
timers[timer].timer_status = inactive; // mark this timer as inactive
}
}
//
// Function determines if the time has elapsed for given timer, if active.
// The elapsed_time parameter is in milliseconds.
//
bool timer_elapsed(uint8_t timer, uint32_t elapsed_time) {
if (timer < max_timers) {
// valid timer
if (timers[timer].timer_status == active) {
// timer is active so check elapsed time
if (millis() - timers[timer].start_time >= elapsed_time) {
// this timer has elapsed
timers[timer].timer_status = inactive; // mark this timer no longer active
return elapsed;
}
}
}
return not_elapsed;
}
让我们更详细地看一下这些函数:
1. ' ' - 将给定的计时器设置为活动并以毫秒为单位记录开始时间。唯一的参数是要启动的定时器编号:0 到(' '-1)。start_timer
max_timers
2. ' ' - 将给定的计时器标记为非活动/非活动。唯一的参数是要停止的定时器编号:0 到 (' '-1)。stop_timer
max_timers
3. ' ' - 应尽可能定期调用此函数,以检查给定的计时器是否已过,如果已过,应遵循哪些操作。该函数返回两个值之一 -如果计时器已完成,则返回“ ”,否则返回“ ”。请注意,如果计时器未激活,此函数还将返回值 ' '(与 ' ' 相同)。timer_elapsed
elasped
not_elapsed
not_elapsed
not_active
该函数有两个参数,第一个是要检查的计时器编号:0 到 (' max_timers
'-1),第二个是要检查的经过时间(以毫秒为单位)。例如:
if (timer_elasped(5, 10000) == elapsed){...} else{...}
检查计时器 5 以查看自启动以来是否已过 10 秒。
该函数最适合用于遍历所有已配置计时器(0 到 (' max_timers
' -1))的 for 循环。还要注意的是,一旦给定的计时器已经过去,如果它是连续发生的需求,则需要立即重新启动。
已经向 OOTB 提供了 ez_timers 草图,并提供了如何使用它的示例。该示例配置了八个 LED 并为每个 LED 使用一个计时器,以不同的时间间隔使它们闪烁。为了定义和控制 LED,还使用了 struct(ure) 数据类型,该数据类型很容易根据最终用户的需求进行修改(减少或增加 LED 的数量或改变闪光率)。
提供的示例是一种简单的方法,可以处理 LED 以提供定时光效果。但是,对于处理经过的计时器结果的更通用的方法,switch-case 构造会特别好用,例如:
...
for (timer = 0;time < max_timers; timer++){
if (timer_elasped(timer, 10000) == elapsed){
switch (timer){
case 0: // timer 0
// restart this timer and process the event
start_timer(timer);
...
break;
case 1: // timer 1
// do not restart this timer, just process the event
...
break;
case 2: // timer 2
...etc
break;
...
}
}
}
...
在上面的示例代码中,已经创建了许多从 0、1、2、...、(- max_timers
1) 引用的计时器,每个经过的计时器事件都由相应的案例段处理。
ez_timers 技术可以提供一种易于实现的方法,用于在您的草图中运行多个计时器。但是,如果您需要一个更全面、更复杂的计时器解决方案,它不仅可以容纳经过时间的计时器,还可以容纳实时计时器,那么请查看同一作者的REM_SYS (见下文),它给出了一个更工业化和完全异步的解决方案。
REM_SYS 支持经过时间和实时计时器(提醒)。可以将所有计时器类型定义为一次性事件、重复发生而没有结束或重复发生直到达到/经过给定时间。不仅如此,对于每种类型,可以定义子类型以帮助决策控制,还可以为每个定义的计时器(提醒)提供用户定义参数的“有效负载”,这些参数在达到计时器事件时返回(经过或实时)。REM_SYS 甚至可以在 UNO 微控制器上运行,并且可以配置有或没有实时时钟。
您可能还会发现同一作者的这些贡献有趣且有用:
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !