全部文档
概述 硬件支持 快速开发指南 内核 驱动 通用组件 专业组件 常见问题

定时器管理


简介

定时器提供了延迟一段时间执行某个用户操作的接口,分为2种,第1种是单次性定时器,即触发一次后停止,第2种是周期性定时器,即周期性地循环触发,需要手动停止。目前内核只提供软件定时器,回调函数运行在任务上下文,不支持硬件定时器,如果要使用硬件定时器,需要调用BSP相关接口。

定时器实现原理

定时器实现主要是对激活状态定时器的管理,基于队列实现,如下图,gs_os_timer_active_list_info用于管理所有已经启动的定时器,gs_os_timer_active_list_info默认包含16个slot,每个启动的定时器都挂在一个slot上(一个slot对应一个队列)。启动定时器时,定时器超时时间对slot个数取余得到一个数值mod ticks,gs_os_timer_list_current向后移动mod ticks - 1所在的slot就是定时器应该插入的slot。如下图所示,当gs_os_timer_list_current指向slot1时,启动一个超时时间为18 ticks的timer 3,18对16取余得2,gs_os_timer_list_current向前移动1(2 - 1)个slot即slot2就是timer 3应该插入的slot。每次系统时钟到达时,处理挂在gs_os_timer_list_current指向的slot上的定时器,并向后移动一个slot,如果gs_os_timer_list_current已经到达active list最后一个slot,则移动到slot0。


重要定义及数据结构

定时器宏定义

#define OS_TIMER_FLAG_ONE_SHOT      0x0U   /* Oneshot timer. */
#define OS_TIMER_FLAG_PERIODIC      0x1U   /* Periodic timer. */
定时器宏 说明
OS_TIMER_FLAG_ONE_SHOT 一次性定时器
OS_TIMER_FLAG_PERIODIC 周期性定时器

定时器控制块结构体

struct os_timer
{
    void                 (*timeout_func)(void *timeout_param);    /* Timeout function. */
    void                  *parameter;                             /* Timeout function's parameter. */
    os_tick_t              init_ticks;                            /* Timer timeout tick. */
    os_tick_t              round_ticks;                           /* Timeout tick remaining. */
    os_uint32_t            index;
    os_list_node_t         list;
    os_timer_active_node_t active_node;
    char                   name[OS_NAME_MAX + 1];
};
定时器控制块成员变量 说明
timeout_func 定时器超时处理函数
parameter 定时器超时处理函数的参数
init_ticks 定时器初始超时ticks
round_ticks 定时器剩余ticks
index 定时器在激活定时器链表中的位置,即对应gs_os_timer_active_list_info中的数组下标
list 资源管理节点,通过该节点将创建的定时器挂载到gs_os_timer_list上
active_node 激活定时器管理节点,通过该节点将定时器挂在到gs_os_timer_active_list_info上
name 定时器名字,名字长度不能大于OS_NAME_MAX

API列表

接口 说明
os_timer_init 以静态方式初始化定时器,即定时器对象由使用者提供
os_timer_deinit 去初始化静态定时器,和os_timer_init()配套使用
os_timer_create 以动态方式创建定时器,会为定时器控制块分配内存并初始化
os_timer_destroy 销毁动态创建的定时器,并释放定时器控制块的内存,和os_timer_create()配套使用
os_timer_start 启动定时器
os_timer_stop 停止定时器
os_timer_set_timeout_ticks 重新设置定时器超时时间
os_timer_get_timeout_ticks 获取定时器超时时间
os_timer_is_active 获取定时器是否处于激活状态
os_timer_set_oneshot 设置定时器为oneshot类型
os_timer_set_periodic 设置定时器为periodic类型
os_timer_is_periodic 获取定时器是否是periodic类型

os_timer_init

该函数用于以静态方式初始化定时器,即定时器对象由使用者提供,其函数原型如下:

void os_timer_init(os_timer_t *timer,
                   const char *name,
                   void      (*function)(void *parameter),
                   void       *parameter,
                   os_tick_t  timeout,
                   os_uint8_t flag);
参数 说明
timer 定时器控制块,由用户提供,并指向对应的定时器控制块内存地址
name 定时器名字,其最大长度由OS_NAME_MAX宏指定,多余部分会被自动截掉
function 超时函数,时间达到时此函数被调用
parameter 超时函数的参数
timeout 超时时间
flag 参数,可配置定时器属性:单次定时器OS_TIMER_FLAG_ONE_SHOT或周期定时器OS_TIMER_FLAG_PERIODIC
返回 说明

os_timer_deinit

该函数用于去初始化静态定时器,其函数原型如下:

void os_timer_deinit(os_timer_t *timer);
参数 说明
timer 要去初始化的定时器控制块
返回 说明

os_timer_create

该函数用于以动态方式创建定时器,会为定时器控制块分配内存并初始化,与os_timer_init()达到的效果一样,函数原型如下:

os_timer_t *os_timer_create(const char *name,
                            void      (*function)(void *parameter),
                            void       *parameter,
                            os_tick_t   timeout,
                            os_uint8_t  flag);
参数 说明
name 定时器名字,其最大长度由OS_NAME_MAX 宏指定,多余部分会被自动截掉
function 超时函数,时间达到时此函数被调用
parameter 超时函数的参数
timeout 超时时间
flag 参数,可配置定时器属性:单次定时器OS_TIMER_FLAG_ONE_SHOT或周期定时器OS_TIMER_FLAG_PERIODIC
返回 说明
非OS_NULL 定时器创建成功
OS_NULL 定时器创建失败

os_timer_destroy

该函数用于销毁动态创建的定时器,并释放定时器控制块的内存,其函数原型如下:

os_err_t os_timer_destroy(os_timer_t *timer);
参数 说明
timer 要销毁的定时器控制块
返回 说明
OS_EOK 销毁定时器成功

os_timer_start

该函数用于启动定时器,函数原型如下:

os_err_t os_timer_start(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
OS_EOK 定时器启动成功

os_timer_stop

该函数用于停止定时器,函数原型如下:

os_err_t os_timer_stop(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
OS_EOK 定时器停止成功
OS_ERROR 定时器停止成功

os_timer_set_timeout_ticks

重新设置定时器超时时间,其函数原型如下:

os_err_t os_timer_set_timeout_ticks(os_timer_t *timer, os_tick_t timeout);
参数 说明
timer 定时器控制块
timeout 设置定时器超时时间成功
返回 说明
OS_EOK 设置定时器超时时间成功

os_timer_get_timeout_ticks

获取定时器超时时间,其函数原型如下:

os_err_t os_timer_get_timeout_ticks(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
os_tick_t 定时器超时时间,以tick为单位

os_timer_is_active

获取定时器是否处于激活状态,其函数原型如下:

os_bool_t os_timer_is_active(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
OS_TRUE 定时器处于激活状态
OS_FALSE 定时器处于非激活状态

os_timer_set_oneshot

设置定时器为oneshot类型,其函数原型如下:

os_err_t os_timer_set_oneshot(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
OS_TRUE 设置定时器为oneshot类型成功

os_timer_set_periodic

设置定时器为periodic类型,其函数原型如下:

os_err_t os_timer_set_periodic(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
OS_TRUE 设置定时器为periodic类型成功

os_timer_is_periodic

获取定时器是否是periodic类型,其函数原型如下:

os_bool_t os_timer_is_periodic(os_timer_t *timer);
参数 说明
timer 定时器控制块
返回 说明
OS_TRUE 定时器是periodic类型
OS_FALSE 定时器不是periodic类型

配置选项

OneOS在使用定时器时提供了功能选项和裁剪的配置,具体配置如下图所示:

配置项 说明
Enable software timer with a timer task 使能定时器功能,如果不使能该功能,定时器相关的源代码就不会编译,默认使能
The stack size of timer task 定时器任务栈大小,以字节为单位,默认512
Software timers in each hash bucket are sorted 使能定时器队列按到期时间排序功能,使能该功能时,定时器队列就会按照到期时间从小到大排序,默认不使能

使用示例

静态定时器使用示例

本例利用静态方式分别初始化了一个周期性定时器和一次性定时器,过一段时间后去初始化 由于timer回调函数运行在timer任务中,timer任务栈空间比较小,LOG_W消耗的栈空间较大,无法使用LOG_W打印log,所以使用os_kprintf代替,用户可以自己实现打印log接口

#include <oneos_config.h>
#include <dlog.h>
#include <os_assert.h>
#include <shell.h>
#include <os_timer.h>

#define TEST_TAG  "TEST"

static os_timer_t timer_s1;
static os_timer_t timer_s2;

void timer_s1_timeout(void *parameter)
{
    os_kprintf("timer_s1 PERIODIC\r\n");
}

void timer_s2_timeout(void *parameter)
{
    os_kprintf("timer_s2 ONE_SHOT\r\n");
}

void static_timer_sample(void)
{
    os_timer_init(&timer_s1, "timer_s1", timer_s1_timeout, OS_NULL, 100, OS_TIMER_FLAG_PERIODIC);

    LOG_W(TEST_TAG, "===timer_s1 start===");
    os_timer_start(&timer_s1);
    os_task_tsleep(550);

    LOG_W(TEST_TAG, "===timer_s1 deinit===");
    os_timer_deinit(&timer_s1);

    os_timer_init(&timer_s2, "timer_s2", timer_s2_timeout, OS_NULL, 100, OS_TIMER_FLAG_ONE_SHOT);

    LOG_W(TEST_TAG, "===timer_s2 start===");
    os_timer_start(&timer_s2);
    os_task_tsleep(550);

    LOG_W(TEST_TAG, "===timer_s2 deinit===");
    os_timer_deinit(&timer_s2);
}

SH_CMD_EXPORT(static_timer, static_timer_sample, "test static timer");

运行结果如下:

sh>static_timer
W/TEST: ===timer_s1 start===
timer_s1 PERIODIC
timer_s1 PERIODIC
timer_s1 PERIODIC
timer_s1 PERIODIC
timer_s1 PERIODIC
W/TEST: ===timer_s1 deinit===
W/TEST: ===timer_s2 start===
timer_s2 ONE_SHOT
W/TEST: ===timer_s2 deinit===

动态定时器使用示例

本例用动态方式分别创建了一个周期性定时器和一次性定时器,过一段时间后再销毁定时器

#include <oneos_config.h>
#include <dlog.h>
#include <os_assert.h>
#include <shell.h>
#include <os_timer.h>

#define TEST_TAG  "TEST"

void timer_d1_timeout(void *parameter)
{
    os_kprintf("timer_d1 PERIODIC\r\n");
}

void timer_d2_timeout(void *parameter)
{
    os_kprintf("timer_d2 ONE_SHOT\r\n");
}

void dynamic_timer_sample(void)
{
    static os_timer_t *timer_d1;
    static os_timer_t *timer_d2;

    timer_d1 = os_timer_create("timer_d1", timer_d1_timeout, OS_NULL, 100, OS_TIMER_FLAG_PERIODIC);
    if (!timer_d1)
    {
        LOG_W(TEST_TAG, "===timer_d1 create err===");
        return;
    }

    LOG_W(TEST_TAG, "===timer_d1 start===");
    os_timer_start(timer_d1);
    os_task_tsleep(550);

    LOG_W(TEST_TAG, "===timer_d1 destroy===");
    os_timer_destroy(timer_d1);

    timer_d2 = os_timer_create("timer_d2", timer_d2_timeout, OS_NULL, 100, OS_TIMER_FLAG_ONE_SHOT);
    if (!timer_d2)
    {
        LOG_W(TEST_TAG, "===timer_d2 create err===");
        return;
    }

    LOG_W(TEST_TAG, "===timer_d2 start===");
    os_timer_start(timer_d2);
    os_task_tsleep(550);

    LOG_W(TEST_TAG, "===timer_d2 destroy===");
    os_timer_destroy(timer_d2);
}

SH_CMD_EXPORT(dynamic_timer, dynamic_timer_sample, "test dynamic timer");

运行结果如下:

sh>dynamic_timer
W/TEST: ===timer_d1 start===
timer_d1 PERIODIC
timer_d1 PERIODIC
timer_d1 PERIODIC
timer_d1 PERIODIC
timer_d1 PERIODIC
W/TEST: ===timer_d1 destroy===
W/TEST: ===timer_d2 start===
timer_d2 ONE_SHOT
W/TEST: ===timer_d2 destroy===

results matching ""

    No results matching ""