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);