(二)时钟管理

一、基本概念及工作机制

  操作系统中最小的时间单位是时钟节拍(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不满足定时精度需求时,只能通过读取系统某个硬件定时器的计数器或是直接使用硬件定时器的方式来实现定时。

二、定时器相关操作及操作函数使用说明
在这里插入图片描述
  和线程管理类似,分为创建/初始化、启动、停止/控制、删除/脱离4个部分。

  1. 获取当前的时钟节拍值 rt_tick_get(),可用于记录系统的运行时间长短或是测量某任务运行的时长
 rt_tick_t rt_tick_get(void);
返回描述
rt_tick返回当前时钟节拍数
  1. 创建定时器 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     /* 软件定时器   */
  1. 删除定时器 rt_timer_delete()
 rt_err_t rt_timer_delete(rt_timer_t timer);
参数描述
timer定时器句柄,指向要删除的定时器
返回描述
RT_EOK删除成功(若参数timer句柄为RT_NULL,将导致一个ASSERT断言)
  1. 初始化定时器 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定时器创建时的参数,支持的值包括单次/周期定时、硬件/软件定时等(可使用“或”取多个值)

疑问保留:线程的初始化函数有返回值。但是定时器的初始化函数却无返回值。

  1. 脱离定时器 rt_timer_detach()
 rt_err_t rt_timer_detach(rt_timer_t timer);
参数描述
timer定时器句柄,指向要脱离的定时器控制块
返回描述
RT_EOK脱离成功
  1. 启动定时器 rt_timer_start()
rt_err_t rt_timer_start(rt_timer_t timer);
参数描述
timer定时器句柄,指向要启动的定时器控制块
返回描述
RT_EOK启动成功
  1. 停止定时器 rt_timer_stop()
rt_err_t rt_timer_stop(rt_timer_t timer);
参数描述
timer定时器句柄,指向要停止的定时器控制块
返回描述
RT_EOK成功停止定时器
-RT_ERRORtimer已经处于停止状态
  1. 定时器控制 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 进行设定
返回描述
RT_EOK设置成功

函数参数 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;

/* 定时器1超时函数 */
static void timeout1(void *parameter)
{
    rt_kprintf("periodic timer is timeout %d.\n", cnt);

    /* 运行第10次,停止周期定时器 */
    if (cnt++ >= 9)
    {
        rt_timer_stop(timer1);
        rt_kprintf("periodic timer was stopped!\n");
    }
}

/* 定时器2超时函数 */
static void timeout2(void *parameter)
{
    rt_kprintf("one shot timer is timeout.\n");
	
	  /* 启动定时器1 */
    if (timer1 != RT_NULL) rt_timer_start(timer1);
		rt_kprintf("periodic timer starts working.\n");
	
}

int timer_sample(void)
{
    /* 创建定时器1  周期定时器 */
    timer1 = rt_timer_create("timer1", timeout1,
                             RT_NULL, 10,
                             RT_TIMER_FLAG_PERIODIC);


    /* 初始化定时器2 单次定时器 */
    rt_timer_init(&timer2,"timer2", timeout2,
                   RT_NULL,  10,
                   RT_TIMER_FLAG_ONE_SHOT);
	
		/* 启动定时器2 */
    rt_timer_start(&timer2);
		rt_kprintf("one shot timer starts working.\n");
	
    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(timer_sample, timer sample);

运行结果如下图:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值