RT_Thread_软件定时器

  • Post author:
  • Post category:其他

1、定时器分类

1.1、硬件定时器(MCU提供)

精度很高,可以达到纳秒级别,并且是中断触发方式。

由外部晶振提供给芯片输入时钟,到达设定时间值后芯片中断控制器产生时钟中断。

1.2、软件定时器(OS提供)

定时数值必须是 时钟节拍(OS Tick)的整数倍

  • HARD_TIMER模式

RT-Thread 定时器默认的方式是 HARD_TIMER 模式,即定时器超时后,超时函数是在系统时钟中断的上下文环境中运行的。

  • SOFT_TIMER模式

通过宏定义 RT_USING_TIMER_SOFT 来决定是否启用该模式;在初始化 / 创建定时器时使用参数 RT_TIMER_FLAG_SOFT_TIMER 来指定设置 SOFT_TIMER 模式。

SOFT_TIMER 模式的定时器超时函数在 timer 线程的上下文环境中执行。

2、定时器工作机制

2.1、rt_tick加1

2.2、定时器链表 rt_timer_list

超时时间排序的方式插入到 rt_timer_list 链表中。

如下图,定时器链表中超时时间timeout由小到大排序的,如果又有定时器timer4被激活,超时时间在330的话,会插到timer2和timer3之间。

当系统节拍rt_tick增加到70时timer1执行,rt_tick=120时timer2执行…….

 

3、定时器控制块

struct rt_timer
{
    struct rt_object parent;
    rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL];  /* 定时器链表节点 */

    void (*timeout_func)(void *parameter);    /* 定时器超时调用的函数 */
    void      *parameter;                     /* 超时函数的参数 */
    rt_tick_t init_tick;                      /* 定时器初始超时节拍数 */
    rt_tick_t timeout_tick;                   /* 定时器实际超时时的节拍数 */
};
typedef struct rt_timer *rt_timer_t;

4、定时器API

4.1、系统初始化

在系统初始化时,默认调用1是HARD_TIMER模式,如果想用SOFT_TIMER要调用2

1、void rt_system_timer_init(void);
2、void rt_system_timer_thread_init(void);

4.2、创建和删除定时器

  • 动态定时器
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_TIMER_FLAG_ONE_SHOT、周期定时RT_TIMER_FLAG_PERIODIC、

硬件模式RT_TIMER_FLAG_HARD_TIMER、软件模式RT_TIMER_FLAG_SOFT_TIMER;

(可以用 “或” 关系取多个值)

返回 ——
RT_NULL 创建失败(通常会由于系统内存不够用而返回 RT_NULL)
定时器的句柄 定时器创建成功
rt_err_t rt_timer_delete(rt_timer_t timer);
参数 描述
timer 定时器句柄,指向要删除的定时器
返回 ——
RT_EOK 删除成功(如果参数 timer 句柄是一个 RT_NULL,将会导致一个 ASSERT 断言)
  • 静态定时器
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);
rt_err_t rt_timer_detach(rt_timer_t timer);

4.3、启动和停止定时器

  • 启动定时器

启动定时器后,定时器的状态将更改为激活状态(RT_TIMER_FLAG_ACTIVATED),并按照超时顺序插入到 rt_timer_list 队列链表中;

rt_err_t rt_timer_start(rt_timer_t timer);
参数 描述
timer 定时器句柄,指向要启动的定时器控制块
返回 ——
RT_EOK 启动成功
  • 停止定时器 
rt_err_t rt_timer_stop(rt_timer_t timer);
参数 描述
timer 定时器句柄,指向要停止的定时器控制块
返回 ——
RT_EOK 成功停止定时器
– RT_ERROR timer 已经处于停止状态

5、例程

HARD_TIMER模式;

定时器1是周期性定时器,超时时间是10倍(OS Tick),执行10次后调用rt_timer_stop停止;

定时器2是单次定时器,超时时间是30倍(OS Tick),执行1次后自动停止;

#include <rtthread.h>

/* 定时器的控制块 */
static rt_timer_t timer1;
static rt_timer_t 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");
}

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

    /* 启动定时器1 */
    if (timer1 != RT_NULL) rt_timer_start(timer1);

    /* 创建定时器2 单次定时器 */
    timer2 = rt_timer_create("timer2", timeout2,
                             RT_NULL,  30,
                             RT_TIMER_FLAG_ONE_SHOT);

    /* 启动定时器2 */
    if (timer2 != RT_NULL) rt_timer_start(timer2);
    return 0;
}

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

版权声明:本文为E2242原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。