OSAL中的每个任务的每个事件都可以拥有一个软件定时器,而这些定时器由一个链表统一组织起来。软件定时器的作用就是对 任务和相应的事件 周期执行提供支持。
一、定时器链表节点结构
typedef struct
{
void *next; //指向下一个节点
osalTime_t timeout; //定时器定时时间
uint16 event_flag; //事件标志
uint8 task_id; //任务ID
uint32 reloadTimeout; //定时器重载的定时时间
} osalTimerRec_t;
二、创建定时器链表节点
//创建一个属于task_id和event_flag的定时器,如果已经存在则更新计数值
osalTimerRec_t * osalAddTimer( uint8 task_id, uint16 event_flag, uint32 timeout )
{
osalTimerRec_t *newTimer;
osalTimerRec_t *srchTimer;
// Look for an existing timer first
//寻找是否已经存在属于task_id和event_flag的定时器
newTimer = osalFindTimer( task_id, event_flag );
if ( newTimer )
{
// Timer is found - update it.
//已经存在,则更新timeout
newTimer->timeout.time32 = timeout;
return ( newTimer );
}
else
{
// New Timer
//不存在,创建一个新的定时器节点,挂到定时器链表尾部
newTimer = osal_mem_alloc( sizeof( osalTimerRec_t ) );
if ( newTimer )
{
// Fill in new timer
newTimer->task_id = task_id;
newTimer->event_flag = event_flag;
newTimer->timeout.time32 = timeout;
newTimer->next = (void *)NULL;
newTimer->reloadTimeout = 0;
// Does the timer list already exist
if ( timerHead == NULL )
{
// Start task list
//如果链表为空,即一个节点都没有,则将现在创建的节点作为链表头节点
timerHead = newTimer;
}
else
{
// Add it to the end of the timer list
srchTimer = timerHead;
// Stop at the last record
while ( srchTimer->next )
srchTimer = srchTimer->next;
// Add to the list
srchTimer->next = newTimer;
}
return ( newTimer );
}
else
{
return ( (osalTimerRec_t *)NULL );
}
}
}
三、定时器的计数方式
//该函数在时钟管理的时间更新中(void osalTimeUpdate( void ))被调用,形参updateTime单位是ms
void osalTimerUpdate( uint32 updateTime )
{
halIntState_t intState;
osalTimerRec_t *srchTimer;
osalTimerRec_t *prevTimer;
osalTime_t timeUnion;
timeUnion.time32 = updateTime;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Update the system time
//记录系统时间,从上电开始算起
osal_systemClock += updateTime;
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
// Look for open timer slot
if ( timerHead != NULL )
{
// Add it to the end of the timer list
srchTimer = timerHead;
prevTimer = (void *)NULL;
// Look for open timer slot
while ( srchTimer )
{
osalTimerRec_t *freeTimer = NULL;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// To minimize time in this critical section, avoid 32-bit math
//timeUnion是逝去的时间,如果该数值高24位为0,即小于256,则仅仅只需要比较低八位大小然后进行计算,一定程度上避免32位的计算,加快运算速度
if ((timeUnion.time16[1] == 0) && (timeUnion.time8[1] == 0))
{
// If upper 24 bits are zero, check lower 8 bits for roll over
//链表节点中的定时数值的低八位比timeUnion的低八位小,则直接低八位数相减即可,减少了运算时间
if (srchTimer->timeout.time8[0] >= timeUnion.time8[0])
{
// 8-bit math
srchTimer->timeout.time8[0] -= timeUnion.time8[0];
}
else
{
// 32-bit math
if (srchTimer->timeout.time32 > timeUnion.time32)
{
srchTimer->timeout.time32 -= timeUnion.time32;
}
else
{
srchTimer->timeout.time32 = 0;
}
}
}
else
{
// 32-bit math
if (srchTimer->timeout.time32 > timeUnion.time32)
{
srchTimer->timeout.time32 -= timeUnion.time32;
}
else
{
srchTimer->timeout.time32 = 0;
}
}
// Check for reloading
//检查是否需要重载定时器,即定时时间到后是否需要继续定时。
if ( (srchTimer->timeout.time16[0] == 0) && (srchTimer->timeout.time16[1] == 0) &&
(srchTimer->reloadTimeout) && (srchTimer->event_flag) )
{
// Notify the task of a timeout
//定时时间到,对task_id设置事件标志event_flag,等待在任务轮询中被处理
osal_set_event( srchTimer->task_id, srchTimer->event_flag );
// Reload the timer timeout value
srchTimer->timeout.time32 = srchTimer->reloadTimeout;
}
// When timeout or delete (event_flag == 0)
//定时时间到,或者事件标志为空,即没有事件,则将该节点独立出来,并释放空间
if ( ((srchTimer->timeout.time16[0] == 0) && (srchTimer->timeout.time16[1] == 0)) ||
(srchTimer->event_flag == 0) )
{
// Take out of list
if ( prevTimer == NULL )
{
timerHead = srchTimer->next;
}
else
{
prevTimer->next = srchTimer->next;
}
// Setup to free memory
freeTimer = srchTimer;
// Next
srchTimer = srchTimer->next;
}
else
{
// Get next
prevTimer = srchTimer;
srchTimer = srchTimer->next;
}
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
if ( freeTimer )
{
//定时时间到
if ( (freeTimer->timeout.time16[0] == 0) && (freeTimer->timeout.time16[1] == 0) )
{
//设置任务的事件标志位
osal_set_event( freeTimer->task_id, freeTimer->event_flag );
}
osal_mem_free( freeTimer );
}
}
}
}