一、基本概念及工作机制
操作系统中最小的时间单位是时钟节拍(OS Tick)。时钟节拍由配置为中断触发模式的硬件定时器产生,有设立专门的计数器对系统的时钟节拍进行计数,即每经过一个时钟节拍,计数器的值就会加1。
- RT-Thread 中,时钟节拍的长度可以根据 RT_TICK_PER_SECOND 的定义来调整,等于 1/RT_TICK_PER_SECOND 秒。
- RT-Thread 提供两种软件实现的定时器,即单次触发定时器和周期触发定时器。
- RT-Thread 定时器默认采用HARD_TIMER模式(中断环境模式),此模式下超时回调函数是在系统时钟中断的上下文环境中运行的,因此不应调用任何会使当前上下文挂起的系统函数或是执行过长的时间。在另外一种SOFT_TIMER模式(线程环境模式)下,超时回调函数会在timer线程的上下文环境中执行。
- RT-Thread 定时器通过定时器链表来对定时器进行管理。定时器被启动时,系统将根据系统当前的时钟节拍数及设定的定时时间计算出超时时刻的时钟节拍数,再根据此时钟节拍数依序(从小到大)插入到定时器链表中。当系统的时钟节拍数增长到与之前的计算结果相等时,触发定时器超时回调函数,同时将该定时器从链表中删除。
- 基于R-Thread 的定时器链表机制,可以运用跳表算法(类似二叉搜索树),增加上层索引,提升查找效率(空间换时间)。在 RT-Thread 中通过宏定义 RT_TIMER_SKIP_LIST_LEVEL 来配置跳表的层数,默认为 1,表示采用一级有序链表图的有序链表算法,每增加一,表示在原链表基础上增加一级索引。
- 当OS Tick不满足定时精度需求时,只能通过读取系统某个硬件定时器的计数器或是直接使用硬件定时器的方式来实现定时。
二、定时器相关操作及操作函数使用说明
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200816104008848.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTQwMzE2,size_16,color_FFFFFF,t_70#pic_center)
和线程管理类似,分为创建/初始化、启动、停止/控制、删除/脱离4个部分。
- 获取当前的时钟节拍值 rt_tick_get(),可用于记录系统的运行时间长短或是测量某任务运行的时长
rt_tick_t rt_tick_get(void);
- 创建定时器 rt_timer_create()
rt_timer_t rt_timer_create(const char* name,
void (*timeout)(void* parameter),
void* parameter,
rt_tick_t time,
rt_uint8_t flag);
参数 | 描述 |
---|
name | 定时器名称 |
void (timeout) (void parameter) | 定时器超时回调函数指针 |
parameter | 定时器超时函数的参数 |
time | 定时时间,单位是时钟节拍 |
flag | 定时器创建时的参数,支持的值包括单次/周期定时、硬件/软件定时等(可使用“或”取多个值) |
返回 | 描述 |
---|
RT_NULL | 创建失败(可能是由于系统内存不足而返回RT_NULL) |
定时器句柄 | 定时器创建成功 |
include/rtdef.h 中定义了一些定时器相关的宏,如下:
#define RT_TIMER_FLAG_ONE_SHOT 0x0
#define RT_TIMER_FLAG_PERIODIC 0x2
#define RT_TIMER_FLAG_HARD_TIMER 0x0
#define RT_TIMER_FLAG_SOFT_TIMER 0x4
- 删除定时器 rt_timer_delete()
rt_err_t rt_timer_delete(rt_timer_t timer);
返回 | 描述 |
---|
RT_EOK | 删除成功(若参数timer句柄为RT_NULL,将导致一个ASSERT断言) |
- 初始化定时器 rt_timer_init()
void rt_timer_init(rt_timer_t timer,
const char* name,
void (*timeout)(void* parameter),
void* parameter,
rt_tick_t time, rt_uint8_t flag);
参数 | 描述 |
---|
timer | 定时器句柄,指向要初始化的定时器控制块 |
name | 定时器名称 |
void (timeout) (void parameter) | 定时器超时回调函数指针 |
parameter | 定时器超时函数的参数 |
time | 定时时间,单位是时钟节拍 |
flag | 定时器创建时的参数,支持的值包括单次/周期定时、硬件/软件定时等(可使用“或”取多个值) |
疑问保留:线程的初始化函数有返回值。但是定时器的初始化函数却无返回值。
- 脱离定时器 rt_timer_detach()
rt_err_t rt_timer_detach(rt_timer_t timer);
参数 | 描述 |
---|
timer | 定时器句柄,指向要脱离的定时器控制块 |
- 启动定时器 rt_timer_start()
rt_err_t rt_timer_start(rt_timer_t timer);
参数 | 描述 |
---|
timer | 定时器句柄,指向要启动的定时器控制块 |
- 停止定时器 rt_timer_stop()
rt_err_t rt_timer_stop(rt_timer_t timer);
参数 | 描述 |
---|
timer | 定时器句柄,指向要停止的定时器控制块 |
返回 | 描述 |
---|
RT_EOK | 成功停止定时器 |
-RT_ERROR | timer已经处于停止状态 |
- 定时器控制 rt_timer_control()
rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);
参数 | 描述 |
---|
timer | 定时器句柄,指向要控制的定时器控制块 |
cmd | 用于控制定时器的指令,当前支持4个指令,分别是设置定时时间、查看定时时间、设置单次/周期触发 |
arg | 与cmd相对应的控制命令参数。比如,cmd为设定超时时间,就可以将超时时间参数通过 arg 进行设定 |
函数参数 cmd 支持的命令:
#define RT_TIMER_CTRL_SET_TIME 0x0
#define RT_TIMER_CTRL_GET_TIME 0x1
#define RT_TIMER_CTRL_SET_ONESHOT 0x2
#define RT_TIMER_CTRL_SET_PERIODIC 0x3
三、定时器应用示例(Keil 环境仿真)
创建一个单次定时的动态定时器和一个周期定时的静态定时器,通过静态定时器超时触发的方式来启动动态定时器进行计数,并在运行一段时间后停止:
#include <rtthread.h>
static rt_timer_t timer1;
static struct rt_timer timer2;
static int cnt = 0;
static void timeout1(void *parameter)
{
rt_kprintf("periodic timer is timeout %d.\n", cnt);
if (cnt++ >= 9)
{
rt_timer_stop(timer1);
rt_kprintf("periodic timer was stopped!\n");
}
}
static void timeout2(void *parameter)
{
rt_kprintf("one shot timer is timeout.\n");
if (timer1 != RT_NULL) rt_timer_start(timer1);
rt_kprintf("periodic timer starts working.\n");
}
int timer_sample(void)
{
timer1 = rt_timer_create("timer1", timeout1,
RT_NULL, 10,
RT_TIMER_FLAG_PERIODIC);
rt_timer_init(&timer2,"timer2", timeout2,
RT_NULL, 10,
RT_TIMER_FLAG_ONE_SHOT);
rt_timer_start(&timer2);
rt_kprintf("one shot timer starts working.\n");
return 0;
}
MSH_CMD_EXPORT(timer_sample, timer sample);
运行结果如下图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200816135113992.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTQwMzE2,size_16,color_FFFFFF,t_70#pic_center)