购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.2 RT-Thread定时器应用开发

定时器在嵌入式系统中是一种常见的机制,用于在一定的时间间隔内执行特定的任务。定时器通常用于处理周期性任务、轮询、事件调度等。在不同的环境中,定时器有不同的实现方式和应用场景。RT-Thread提供了灵活且功能丰富的定时器机制,RT-Thread的定时器可分为:

(1)软件定时器:RT-Thread支持软件定时器,这是通过系统时钟的滴答定时器(Tick Timer)来实现的,允许用户在应用程序中创建基于时间的事件。

(2)硬件定时器:RT-Thread还支持硬件定时器,硬件定时器通常是由微控制器上的硬件定时器或定时器模块实现的。

本节的要求如下:

➲ 了解硬件定时器的基本概念。

➲ 学习定时器的工作原理。

➲ 掌握定时器的管理方式。

➲ 掌握RT-Thread定时器的应用。

2.2.1 原理分析

2.2.1.1 定时器的基本概念

通俗地讲,定时器是指从指定的时刻开始,经过一定的时间后触发一个事件。定时器有硬件定时器和软件定时器之分。

(1)硬件定时器。硬件定时器是芯片本身提供的定时器,一般采用由外部晶振提供给芯片的输入时钟,芯片向软件模块提供一组配置寄存器,在到达设定的时间值后芯片的中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级,并且采用中断触发方式。

(2)软件定时器。软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器的基础之上,使系统能够提供不受数目限制的定时器服务。

RT-Thread提供了软件定时器,以系统时钟的时间长度为单位,即定时数值必须是系统时钟时间长度的整数倍。例如,如果系统时钟的时间长度是10 ms,那么软件定时器只能是10 ms、20 ms、100 ms等的定时器,而不能是为15 ms的定时器。RT-Thread的软件定时器也是基于系统时钟的,提供了基于系统时钟时间长度整数倍的定时能力,本节的系统时钟时间长度为1 ms。

RT-Thread的定时器提供两类定时器机制:第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止;第二类是周期触发定时器,这类定时器会周期性地触发定时器事件,直到用户手动停止为止,否则将继续执行下去。

另外,根据超时函数执行时所处的上下文环境,RT-Thread定时器的工作模式可分为HARD_TIMER模式与SOFT_TIMER模式,如图2.6所示。

图2.6 RT-Thread定时器的工作模式

1)HARD_TIMER模式

在HARD_TIMER模式下,定时器超时函数在中断上下文环境中执行,可以在初始化/创建定时器时使用参数RT_TIMER_FLAG_HARD_TIMER来指定定时器工作在该模式下。

RT-Thread定时器的默认工作模式是HARD_TIMER模式,即定时器超时后,超时函数是在系统时钟中断的上下文环境中运行的。在中断上下文中的执行方式决定了定时器的超时函数不会调用任何会让当前上下文挂起的系统函数,也不能执行非常长的时间,否则会导致其他中断的响应时间加长或抢占其他线程执行的时间。

2)SOFT_TIMER模式

SOFT_TIMER模式是可配置的,用户既可以通过宏定义RT_USING_TIMER_SOFT决定定时器是否工作于该模式,也可以在初始化/创建定时器时使用参数RT_TIMER_FLAG_SOFT_TIMER来指定定时器工作于该模式。SOFT_TIMER模式在启用后,系统会在初始化时创建一个timer线程,定时器的超时函数会在timer线程的上下文环境中执行。

2.2.1.2 定时器的工作原理

下面以一个例子来说明RT-Thread定时器的工作原理。RT-Thread的定时器模块维护着两个重要的全局变量:

(1)当前系统经过的滴答时间rt_tick:当硬件定时器中断触发时,该全局变量将加1。

(2)定时器链表rt_timer_list:系统创建并激活的定时器都会按照超时时间排序的方式插入rt_timer_list中。

定时器链表的结构如图2.7所示,系统当前时间为20个滴答时间,在当前系统中已经创建并启动了三个定时器,分别是定时时间为50个滴答时间的Timer1、100个滴答时间的Timer2和500个滴答时间的Timer3,这三个定时器分别加上系统当前时间rt_tick=20,从小到大排序链接在rt_timer_list中。

rt_tick随着硬件定时器的中断触发次数的增加而增长(每触发一次硬件定时器中断,rt_tick就会加1),经过50个滴答时间后,rt_tick从20增长到70,与Timer1的timeout值相等,这时会触发与Timer1定时器相关联的超时函数,同时将Timer1从rt_timer_list中删除。同理,经过100个滴答时间和500个滴答时间后,与Timer2和Timer3定时器相关联的超时函数会被触发,接着将Time2和Timer3从rt_timer_list中删除。

图2.7 定时器链表结构

如果当前定时器(Timer1)在10个滴答时间后(rt_tick=30)创建了一个定时时间为300个滴答时间的Timer4,由于Timer4的timeout=rt_tick+300=330,因此它将被插入在Timer2和Timer3中间,如图2.8所示。

图2.8 新创建的定时器在定时器链表中的位置

2.2.1.3 定时器的管理方式

前文介绍了RT-Thread定时器的工作原理,本节将深入介绍定时器的各个接口,帮助读者在代码层次上理解RT-Thread定时器的管理方式。

RT-Thread在启动时需要初始化定时器管理系统。通过下面的函数可完成定时器管理系统的初始化:

如果需要使用SOFT_TIMER模式,则在初始化定时器管理系统时应该调用下面的函数:

定时器控制块中包含了与定时器相关的重要参数,这些参数在定时器的各种状态间起到纽带作用。定时器的相关操作如图2.9所示。所有的定时器都会在定时超时后从定时器链表中删除,而周期性定时器则会在再次启动时加入定时器链表,这与定时器参数设置相关。当操作系统时钟中断触发时,都会对已经超时的定时器状态参数进行修改。

图2.9 定时器的相关操作

1)创建定时器

在需要动态创建一个定时器时,可使用下面的函数:

调用上面的函数后,RT-Thread会首先为定时器控制块分配动态内存,然后对该定时器控制块进行基本的初始化。rtdef.h中定义了一些与定时器相关的宏,例如:

当指定的flag为RT_TIMER_FLAG_HARD_TIMER时,如果定时器超时,则定时器的回调函数将在时钟中断服务程序上下文中被调用;当指定的flag为RT_TIMER_FLAG_SOFT_TIMER时,如果定时器超时,则定时器的回调函数将在系统时钟timer线程的上下文中被调用。

2)删除定时器

当系统不再使用定时器时,可使用下面的函数将其删除:

3)启动定时器

定时器在创建或者初始化后,并不会被立即启动,必须调用启动定时器的函数后定时器才开始工作。启动定时器的函数如下:

调用定时器启动函数后,定时器的状态将更改为激活状态(RT_TIMER_FLAG_ACTIVATED),并按照超时顺序插入rt_timer_list中。

4)停止定时器

在启动定时器后,若想停止它,可以使用下面的函数:

调用定时器停止函数后,定时器的状态将更改为停止状态,并从rt_timer_list中脱离出来不参与定时器超时检查。当某个定时器超时时,也可以调用这个函数停止该定时器本身。

5)控制定时器

除了上述提供的一些函数,RT-Thread还提供了定时器控制函数,以获取或设置更多定时器的信息。控制定时器的函数如下:

控制定时器函数可根据命令类型来查看或改变定时器的设置。

2.2.2 开发设计与实践

2.2.2.1 硬件设计

本节的硬件设计同1.5.2.1节。

2.2.2.2 软件设计

软件设计流程如图2.10所示。

(1)创建定时器线程,并且在main函数中完成线程的初始化工作。

(2)编写线程入口函数,在线程入口函数中完成LED引脚的初始化工作。

(3)在MobaXterm串口终端FinSH控制台中输入“timerManage start”命令,4个LED循环点亮,同时在FinSH控制台中输出“led timer starting success!”信息;当输入“timerManage control 100”命令时,4个LED循环点亮的速度加快,同时在FinSH控制台中输出“led timer control success!”信息;当输入“timerManage stop”命令时,4个LED停止循环点亮,只有1个LED点亮,同时在FinSH控制台中输出“led timer stop success!”信息;当输入“timerManage delete”命令时,4个LED循环点亮停止,同时在FinSH控制台中输出“led timer deletion success!”信息。

图2.10 软件设计流程

2.2.2.3 功能设计与核心代码设计

通过原理学习可知,要实现定时器的管理,就需要使用RT-Thread提供的定时器管理接口进行定时器的初始化。定时器的管理使用的是FinSH控制台命令,需要实现对应的FinSH控制台命令,并将已实现命令添加到FinSH控制台命令列表中。

1)主函数(zonesion/app/main.c)

主函数的主要工作是调用led_timer_init()函数,完成引导工作。代码如下:

2)定时器初始化函数(zonesion/app/apl_led.c)

定时器初始化函数的主要工作是实现定时器的创建,包括定义定时器名称和入口函数,设置入口函数参数、定时器超时时间、定时器类型。代码如下:

3)定时器入口函数(zonesion/app/apl_led.c)

定时器入口函数的主要工作是周期性地对LED进行操作,类似于定时器中断服务程序,需要在规定的时间执行此函数。这里在定时器入口函数中实现LED流水灯。代码如下:

4)自定义FinSH控制台命令函数(zonesion/app/finsh_cmd/finsh_ex.c)

自定义FinSH控制台命令函数的主要工作是实现定时器管理的命令,包括定时器的启动、控制、停止及删除,可以在FinSH控制台中使用相关的命令对定时器进行操作。代码如下:

2.2.3 开发步骤与验证

2.2.3.1 硬件部署

同1.2.3.1节。

2.2.3.2 工程调试

(1)将本项目的工程(06-Timer)文件夹复制到RT-ThreadStudio\workspace目录下。

(2)其余同2.1.3.2节。

2.2.3.3 验证效果

(1)关闭RT-Thread Studio,拔掉仿真器,按下ZI-ARMEmbed上的电源按键重新上电。

(2)在MobaXterm串口终端FinSH控制台中输入“timerManage start”命令,4个LED循环点亮,点亮的时间间隔是1 s(见图2.11),同时在FinSH控制台中输出“led timer starting success!”信息。

图2.11 4个LED循环点亮,点亮的时间间隔是1 s

(3)在MobaXterm串口终端FinSH控制台中输入“timerManage control 100”命令,将定时器设置为100 ms的定时器,4个LED循环点亮,循环的速度将变快,同时在FinSH控制台中输出“led timer control success!”信息。

(4)在MobaXterm串口终端FinSH控制台中输入“timerManage stop”命令,将停止定时器,4个LED停止循环点亮,同时在FinSH控制台中输出“led timer stop success!”信息。

(4)在MobaXterm串口终端FinSH控制台中输入“timerManage delete”命令,将删除定时器,在FinSH控制台中输出“led timer delete success!”信息,使用“list_thread”命令可以看到此时定时器已被删除。

2.2.4 小结

本节主要介绍定时器的基本概念、工作原理和管理方式。通过本节的学习,读者可以掌握RT-Thread定时器的应用。 2BfnH5bulvikp/3vyLZomBVK56EzpB7UsFPsCkk4gNo7mJ9yvOMmvoqEPvdoJs9Z

点击中间区域
呼出菜单
上一章
目录
下一章
×