一、定时器的建立:
定时器是在我们的应用程序中建立的,
OS_TMR *OSTmrCreate (INT32U dly,
INT32U period,
INT8U opt,
OS_TMR_CALLBACK callback,
void *callback_arg,
INT8U *pname,
INT8U *perr)
想使用定时器那些函数要在os_cfg.h中定义OS_TMR_EN。
返回值是os_tmr结构体(定义在ucos_ii.h中)。
typedef struct os_tmr {
INT8U OSTmrType;
OS_TMR_CALLBACK OSTmrCallback;
void *OSTmrCallbackArg;
void *OSTmrNext;
void *OSTmrPrev;
INT32U OSTmrMatch; 当OSTmrTime == OSTmrMatch定时器到时间了。
INT32U OSTmrDly;
INT32U OSTmrPeriod;
#if OS_TMR_CFG_NAME_EN > 0u
INT8U *OSTmrName;
#endif
INT8U OSTmrOpt;
INT8U OSTmrState;
} OS_TMR;
OSTmrType类型定义在ucos_ii.h中:OS_TMR_TYPE
OS_ARG_CHK_EN要在os_cfg.h中定义一下,来确定要不要一些功能。
OS_TMR_CFG_NAME_EN要你自己在os_cfg.h中定义,来控制要不要用OSTmrName
OSTmrState在ucos_ii.h中有以下几种类型:
OS_TMR_STATE_UNUSED 不存在这个定时器
OS_TMR_STATE_RUNNING 这个定时器正在运行
OS_TMR_STATE_COMPLETED这个定时器已经跑完了
OS_TMR_STATE_STOPPED 这个定时器停止了
参数:
1、 Dly 定时时间,如果是这个定时器只用一次,那么就用这个,如果定时器要反复用那么它是第一次时用,以后用period。
2、 Period 定时器从复用时会用到这个作定时时间。
3、 Opt 这里有两种选项,告诉我们是只用一次还是反复使用。只用一次OS_TMR_OPT_ONE_SHOT,反复使用OS_TMR_OPT_PERIODIC。这些定义在ucos_ii.h中。
定时器选项有五种
#define OS_TMR_OPT_NONE 0u 没有选择
#define OS_TMR_OPT_ONE_SHOT 1u 定时器不会自动重复使用
#define OS_TMR_OPT_PERIODIC 2u 定时器会自动重装
#define OS_TMR_OPT_CALLBACK 3u OSTmrStop()中使用,调用回调函数,但不带参数
#define OS_TMR_OPT_CALLBACK_ARG 4u 也是OSTmrStop()中使用,调用回调函数,但有参数。
4、 Callback 指向回调函数的指针,这个函数这样声明,void mycallback(OS_TMR *ptmr, void p_arg );
5、 Callback_arg 参数给callback的。
6、 Pname 定时器的名字
7、 Perr 错误指针* OS_ERR_NONE 没有错误
OS_ERR_TMR_INVALID_DLY 无效的定时时间
OS_ERR_TMR_INVALID_PERIOD 无效的周期
OS_ERR_TMR_INVALID_OPT 无效的选项
OS_ERR_TMR_ISR 在中断中调用
OS_ERR_TMR_NON_AVAIL 空的定时器用光了,这个和task一样意思。
用到的函数OSTmr_Alloc()得到一个定时器结构体。
二、OSTmrStart
会调用OSTmr_Link,OSTmr_Link代码如下
#if OS_TMR_EN > 0u
static void OSTmr_Link (OS_TMR *ptmr,
INT8U type)
{
OS_TMR *ptmr1;
OS_TMR_WHEEL *pspoke;
INT16U spoke;
ptmr->OSTmrState = OS_TMR_STATE_RUNNING;
if (type == OS_TMR_LINK_PERIODIC) { /* Determine when timer will expire */
ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
} else {
if (ptmr->OSTmrDly == 0u) {
ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
} else {
ptmr->OSTmrMatch = ptmr->OSTmrDly + OSTmrTime;
}
}
spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
pspoke = &OSTmrWheelTbl[spoke];
if (pspoke->OSTmrFirst == (OS_TMR *)0) { /* Link into timer wheel */
pspoke->OSTmrFirst = ptmr;
ptmr->OSTmrNext = (OS_TMR *)0;
pspoke->OSTmrEntries = 1u;
} else {
ptmr1 = pspoke->OSTmrFirst; /* Point to first timer in the spoke */
pspoke->OSTmrFirst = ptmr;
ptmr->OSTmrNext = (void *)ptmr1;
ptmr1->OSTmrPrev = (void *)ptmr;
pspoke->OSTmrEntries++;
}
ptmr->OSTmrPrev = (void *)0; /* Timer always inserted as first node in list */
}
#endif
三、OSTmr_Task()
用于在定时器到时间后,执行定时器创建时候的回调函数,代码如下:
static void OSTmr_Task (void *p_arg)
{
INT8U err;
OS_TMR *ptmr;
OS_TMR *ptmr_next;
OS_TMR_CALLBACK pfnct;
OS_TMR_WHEEL *pspoke;
INT16U spoke;
p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
for (;;) {
OSSemPend(OSTmrSemSignal, 0u, &err); /* Wait for signal indicating time to update timers */
OSSchedLock();
OSTmrTime++; /* Increment the current time */
spoke = (INT16U)(OSTmrTime % OS_TMR_CFG_WHEEL_SIZE); /* Position on current timer wheel entry */
pspoke = &OSTmrWheelTbl[spoke];
ptmr = pspoke->OSTmrFirst;
while (ptmr != (OS_TMR *)0) {
ptmr_next = (OS_TMR *)ptmr->OSTmrNext; /* Point to next timer to update because current ... */
/* ... timer could get unlinked from the wheel. */
if (OSTmrTime == ptmr->OSTmrMatch) { /* Process each timer that expires */
OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
if (ptmr->OSTmrOpt == OS_TMR_OPT_PERIODIC) {
OSTmr_Link(ptmr, OS_TMR_LINK_PERIODIC); /* Recalculate new position of timer in wheel */
} else {
ptmr->OSTmrState = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */
}
pfnct = ptmr->OSTmrCallback; /* Execute callback function if available */
if (pfnct != (OS_TMR_CALLBACK)0) {
(*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg);
}
}
ptmr = ptmr_next;
}
OSSchedUnlock();
}
}
#endif