定时器
定时器的实现方式:
使用OS自带的定时器模块,建立一个定时器,定时间隔为自定义TICKS,定时器的回调函数中设置定时器到时的事件。
定时器模块定义了一个定时器的链表,用于定时器的管理。
操作定时器管理链表的过程需要关闭任务调度。
注意:OS本身定时器存在一定的误差,通过OS来实现的定时器也是有误差的。误差的大小跟WSF自定义的ticks大小有关。
定时器的管理结构
//定时器对象管理结构
typedef struct wsfTimer_tag
{
struct wsfTimer_tag *pNext; //指向队列中下一个定时器节点
wsfTimerTicks_t ticks; //定时器超时ticks
wsfHandlerId_t handlerId; //定时器超时,处理函数句柄
bool_t isStarted; //定时器是否启动
wsfMsgHdr_t msg; //应用定义的定时器参数
} wsfTimer_t;
定时器的初始化
- 初始化定时器管理链表
- 创建WSF驱动定时器,用于周期性发送事件处理定时器的超时。
/* 系统OS定时器回调函数,主Task发送定时器到时事件 */
static void WsfTimer_handler(TimerHandle_t xTimer)
{
WsfTaskSetReady(0, WSF_TIMER_EVENT);
}
/* WSF定时器基础初始化 */
void WsfTimerInit(void)
{
/* 定时器管理链表初始化 */
WSF_QUEUE_INIT(&wsfTimerTimerQueue);
if(xWsfTimer == NULL)
{
/* 使用OS相关接口创建一个定时器,此处使用的是freeRtos的接口 */
xWsfTimer = xTimerCreate("WSF Timer", pdMS_TO_TICKS(WSF_MS_PER_TICK),
pdFALSE, NULL, WsfTimer_handler);
configASSERT(xWsfTimer);
}
}
定时器的启动
计算出定时器到时的ticks count,并将定时器根据到时的时间插入到管理链表中。
/* 启动MS级别的定时器 */
void WsfTimerStartMs(wsfTimer_t *pTimer, wsfTimerTicks_t ms)
{
WSF_TRACE_INFO2("WsfTimerStartMs pTimer:0x%x ticks:%u", (uint32_t)pTimer, WSF_TIMER_MS_TO_TICKS(ms));
/* 计算时间为WSF的tick值,并根据大小插入到定时器链表中 */
wsfTimerInsert(pTimer, WSF_TIMER_MS_TO_TICKS(ms));
}
定时器的停止
找到定时器在链表中的位置,并将定时器从链表中移除,设置定时器的状态为,未启动状态。
//定时器停止函数
void WsfTimerStop(wsfTimer_t *pTimer)
{
WSF_TRACE_INFO1("WsfTimerStop pTimer:0x%x", pTimer);
/* task schedule lock */
WsfTaskLock();
//将定时器从管理链表移除,设置定时器运行状态为false
wsfTimerRemove(pTimer);
/* task schedule unlock */
WsfTaskUnlock();
}
定时器更新函数
轮询定时器管理链表中的每个定时器,减去已经过去的ticks时间,判断每个定时器是否到时,若定时器到时则发送时间给对应的处理函数。
void WsfTimerUpdate(wsfTimerTicks_t ticks)
{
wsfTimer_t *pElem;
/* 关任务调度 */
WsfTaskLock();
pElem = (wsfTimer_t *) wsfTimerTimerQueue.pHead;
/* 轮询链表上所有的定时器 */
while (pElem != NULL)
{
/* 减去已经获取的始终ticks */
if (pElem->ticks > ticks)
{
pElem->ticks -= ticks;
}
else
{
pElem->ticks = 0;
/* 定时器到期,通知对应的事件处理函数 */
WsfTaskSetReady(pElem->handlerId, WSF_TIMER_EVENT);
}
pElem = pElem->pNext;
}
/* 是能任务调度 */
WsfTaskUnlock();
}
获取当前系统ticks,并更新所有定时器,并根据下一个到期Timer的时间,重新设置系统定时器的超时时间。
//根据实际的OS仅从此函数的移植,这个函数在相关的TASK中应该一直被调用
void WsfTimerUpdateTicks(void)
{
uint32_t ui32CurrentTime, ui32ElapsedTime;
bool_t bTimerRunning;
wsfTimerTicks_t xNextExpiration;
/* 读取OS的时间值 */
ui32CurrentTime = xTaskGetTickCount();
/* 计算上次到这次计算之间的间隔 */
ui32ElapsedTime = ui32CurrentTime - g_ui32LastTime;
/* 计算是否达到了WSF的自定义tick值 */
if ( (ui32ElapsedTime / CLK_TICKS_PER_WSF_TICKS) > 0 )
{
/* 更新所有定时器 */
WsfTimerUpdate(ui32ElapsedTime / CLK_TICKS_PER_WSF_TICKS);
g_ui32LastTime = ui32CurrentTime;
}
/* 检查是否有定时器在运行,并获取剩余的ticks */
xNextExpiration = WsfTimerNextExpiration(&bTimerRunning);
/* 根据下一个到时时间,重新设置OS定时器的周期 */
if ( xNextExpiration )
{
configASSERT(pdPASS == xTimerChangePeriod( xWsfTimer,
pdMS_TO_TICKS(xNextExpiration*CLK_TICKS_PER_WSF_TICKS), 100)) ;
}
}