定时器的管理方式
在系统启动时需要初始化定时器管理系统。
c
void rt_system_timer_init(void);
如果需要使用SOFT_TIMER,则系统初始化时,应该调用
c
void rt_system_timer_thread_init(void);
定时器控制块中含有定时器相关的重要参数,在定时器各种状态间起到纽带的作用。
定时器的相关操作如图所示,对定时器的操作包含:创建/初始化定时器、启动定时器、运行定时器、删除/脱离定时器。
所有定时器在定时超时后都会从定时器链表中被移除,而周期性定时器会在它再次启动时被加入定时器链表,这与定时器参数设置相关。
c
rt_timer_t rt_timer_create(const char* name,
void (*timeout)(void* parameter),
void* parameter,
rt_tick_t time,
rt_uint8_t flag);
调用该函数接口后,内核首先从动态内存堆中分配一个定时器控制块,然后对该控制块进行基本的初始化。
- time:定时器的超时时间,单位是时钟节拍。
- flag:定时器创建的参数,支持的值包括单次定时、周期定时、硬件定时器、软件定时器等,可以用或关系取多个值。
c
#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 /* 软件定时器 */
上面 2 组值可以以 "或" 逻辑的方式赋给 flag。当指定的 flag 为 RT_TIMER_FLAG_HARD_TIMER 时,如果定时器超时,定时器的回调函数将在时钟中断的服务例程上下文中被调用;当指定的 flag 为 RT_TIMER_FLAG_SOFT_TIMER 时,如果定时器超时,定时器的回调函数将在系统时钟 timer 线程的上下文中被调用。
启动和停止定时器
当定时器被创建或初始化以后,并不会被立即启动,必须在调用启动定时器函数接口后,才开始工作,启动定时器函数接口如下:
c
rt_err_t rt_timer_start(rt_timer_t timer);
调用定时器启动函数接口后,定时器的状态将更改为激活状态(RT_TIMER_FLAG_ACTIVATED),并按照超时顺序插入到 rt_timer_list 队列链表中。
启动定时器以后,若想使它停止:
c
rt_err_t rt_timer_stop(rt_timer_t timer);
调用定时器停止函数接口后,定时器状态将更改为停止状态,并从rt_timer_list链表中脱离出来不参与定时器超时检查。
当一个周期性定时器超时时,也可以调用这个函数接口停止这个定时器。
控制定时器
c
rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void *arg);
c
#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 /* 设置定时器为周期型定时器 */
定时器应用示例
这是一个创建定时器的例子,这个例程会创建两个动态定时器,一个是单次定时,一个是周期性定时并让周期定时器运行一段时间后停止运行。
c
#include <rtthread.h>
static rt_timer_t timer1;
static rt_timer_t 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");
}
}
/* 定时器 2 超时函数 */
static void timeout2(void *parameter)
{
rt_kprintf("one shot timer is timeout\n");
}
int timer_sample(void){
timer1 = rt_timer_create("timer1", timeout1, RT_NULL, 10, RT_TIMER_FLAG_PERIODIC);
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;
}
高精度延时
RTT定时器的最小精度是由系统时钟节拍所决定的(1OS Tick=1/RT_TICK_PER_SECOND秒),定时器设定的时间必须是OS Tick的整数倍。
当需要实现更短时间长度的系统定时时,例如OS Tick是10ms,而程序需要实现1ms的定时或延时,这种时候操作系统定时器将不能够满足要求,只能通过读取系统某个硬件定时器的计数器或直接使用硬件定时器的方式。
在Cortex-M系列中,SysTick已经被RT-Thread用于作为OS Tick使用,它被配置成1/RT_TICK_PER_SECOND秒后触发一次中断的方式。
c
void rt_hw_us_delay(rt_uint32_t us)