uCOS-III笔记之定时器
说到定时器,就先来说说它有什么用,定时器和时间是不一样的也就是timer和time,我们是为了等一段时间后去完成某一个操作。
一、初始化
要用定时器首先要做的就是初始化定时器,ucos中初始化定时器使用的函数是 void OS_TmrInit (OS_ERR *p_err),初始化中主要做了什么呢。
1、初始化一个全局的一个定时器的存放处也就是这个TmrWheel,下面我就来看一下这个定时器的轮盘。可以看到这就是一个OS_TMR的一个指针。(另外还初始化了其他的一些计数器)
typedef struct os_tmr_spoke OS_TMR_SPOKE;
struct os_tmr_spoke {
OS_TMR *FirstPtr;
/* Pointer to first timer in linked list */
OS_OBJ_QTY NbrEntries;
OS_OBJ_QTY NbrEntriesMax;
};
OS_TMR_SPOKE OSCfg_TmrWheel [OS_CFG_TMR_WHEEL_SIZE];
2、创建一个定时器任务:OS_TmrTask,也就是这个任务管理着我们所有的定时器有序的运行完成我们的预期目标。
注意<这个任务其实优先级很低通过源码可以看到 :#define OS_CFG_TMR_TASK_PRIO (OS_CFG_PRIO_MAX - 2u),如果要求高优先级高实时的的事件还是要考虑好再使用>。
让我们看一下这个任务到底做了什么,从代码中可以看到这个任务就是在轮询上面提到的定时器管理的轮子,判断match是否到达,然后对到达的定时器做了相关的操作,然后运行我们的回到函数CallbackPtr程序。
...
while (DEF_ON) {
(void)OSTaskSemPend((OS_TICK )0, /* Wait for signal indicating time to update tmrs */
(OS_OPT )OS_OPT_PEND_BLOCKING,
(CPU_TS *)&ts,
(OS_ERR *)&err);
OSSchedLock(&err);
ts_start = OS_TS_GET();
OSTmrTickCtr++;
/* Increment the current time */
spoke = (OS_TMR_SPOKE_IX)(OSTmrTickCtr % OSCfg_TmrWheelSize);
p_spoke = &OSCfg_TmrWheel[spoke];
p_tmr = p_spoke->FirstPtr;
done = DEF_FALSE;
while (done == DEF_FALSE) {
if (p_tmr != (OS_TMR *)0) {
p_tmr_next = (OS_TMR *)p_tmr->NextPtr;
/* Point to next tmr to update because current ... */
/* ... timer could get unlinked from the wheel. */
if (OSTmrTickCtr == p_tmr->Match) {
/* Process each timer that expires */
OS_TmrUnlink(p_tmr);
/* Remove from current wheel spoke */
if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
OS_TmrLink(p_tmr,
OS_OPT_LINK_PERIODIC);
/* Recalculate new position of timer in wheel */
} else {
p_tmr->State = OS_TMR_STATE_COMPLETED;
/* Indicate that the timer has completed */
}
p_fnct = p_tmr->CallbackPtr;
/* Execute callback function if available */
if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
(*p_fnct)((void *)p_tmr,
p_tmr->CallbackPtrArg);
}
p_tmr = p_tmr_next;
/* See if next timer matches */
} else {
done = DEF_TRUE;
}
} else {
done = DEF_TRUE;
}
}
}
...
二、使用定时器
定时器已经完成了初始化,也已经把定时器管理的大轮子转起来了,接下来就是我们如何把我们的定时器事件插到这个飞速旋转的轮子上。
1、创建定时器
使用OSTmrCreate,创建定时器指针,然后初始化这个定时器:名称,时间,回调函数。
函数里面有一个‘’OSTmrQty++‘’用来记录定时器个数正好与OSTmrDel函数内的“OSTmrQty--”相互对应。
void OSTmrCreate (OS_TMR *p_tmr,
CPU_CHAR *p_name,
OS_TICK dly,
OS_TICK period,
OS_OPT opt,
OS_TMR_CALLBACK_PTR p_callback,
void *p_callback_arg,
OS_ERR *p_err)
2、启动定时器
启动定时器,其实就是将定时器指针放入到我们的定时管理的轮子上。
CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr,
OS_ERR *p_err)
这start这个函数里用到了几个重要的函数,一个是link将定时器加入链表中,一个是unlink将定时器从链表中删除。这样我们的定时器就可以进入任务调度的大军中了。
void OS_TmrLink (OS_TMR *p_tmr,
OS_OPT opt)
void OS_TmrUnlink (OS_TMR *p_tmr)
三、定时器的停止删除