FreeRTOS-timers.c
FreeRTOS-timers.c文件分析
#define tmrSTATUS_IS_ACTIVE ( ( uint8_t ) 0x01 ) /*有效*/
#define tmrSTATUS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 0x02 ) /*静态申请内存*/
#define tmrSTATUS_IS_AUTORELOAD ( ( uint8_t ) 0x04 ) /*自动重载*/
typedef struct tmrTimerControl /* */
{
const char * pcTimerName; /*<< 定时器名称*/
ListItem_t xTimerListItem; /*定时器列表条目,用来记录定时器超时时间点。*/
TickType_t xTimerPeriodInTicks; /*<< 定时器周期*/
void * pvTimerID; /*<< 定时器id,/
TimerCallbackFunction_t pxCallbackFunction; /*<< 定时器超时回调函数 *
uint8_t ucStatus; /*<< 定时器状态,tmrSTATUS_IS_ACTIVE、tmrSTATUS_IS_STATICALLY_ALLOCATED、tmrSTATUS_IS_AUTORELOAD*/
} xTIMER;
定时器指令
#define tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR ( ( BaseType_t ) -2 )
#define tmrCOMMAND_EXECUTE_CALLBACK ( ( BaseType_t ) -1 )
#define tmrCOMMAND_START_DONT_TRACE ( ( BaseType_t ) 0 )
#define tmrCOMMAND_START ( ( BaseType_t ) 1 )
#define tmrCOMMAND_RESET ( ( BaseType_t ) 2 )
#define tmrCOMMAND_STOP ( ( BaseType_t ) 3 )
#define tmrCOMMAND_CHANGE_PERIOD ( ( BaseType_t ) 4 )
#define tmrCOMMAND_DELETE ( ( BaseType_t ) 5 )
#define tmrFIRST_FROM_ISR_COMMAND ( ( BaseType_t ) 6 )
#define tmrCOMMAND_START_FROM_ISR ( ( BaseType_t ) 6 )
#define tmrCOMMAND_RESET_FROM_ISR ( ( BaseType_t ) 7 )
#define tmrCOMMAND_STOP_FROM_ISR ( ( BaseType_t ) 8 )
#define tmrCOMMAND_CHANGE_PERIOD_FROM_ISR ( ( BaseType_t ) 9 )
typedef struct tmrTimerParameters
{
TickType_t xMessageValue; /*<< 消息值,一般用来记录执行定时器指令时的tick值,或者说起始tick值*/
Timer_t * pxTimer; /*<< 定时器指针*/
} TimerParameter_t;
typedef struct tmrTimerQueueMessage
{
BaseType_t xMessageID; /*<< 定时器指令T */
union
{
TimerParameter_t xTimerParameters;
/* 没用到,不关心*/
#if ( INCLUDE_xTimerPendFunctionCall == 1 )
CallbackParameters_t xCallbackParameters;
#endif /* INCLUDE_xTimerPendFunctionCall */
} u;
} DaemonTaskMessage_t;
PRIVILEGED_DATA static List_t xActiveTimerList1; /*有效定时器列表1*/
PRIVILEGED_DATA static List_t xActiveTimerList2; /*有效定时器列表2*/
PRIVILEGED_DATA static List_t * pxCurrentTimerList; /*当前定时器列表指针*/
PRIVILEGED_DATA static List_t * pxOverflowTimerList; /*溢出定时器列表指针*/
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; /*定时器消息队列*/
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; /*定时器任务句柄*/
BaseType_t xTimerCreateTimerTask( void )
功能:创建定时器任务
返回值:成功时返回1,否则返回0
TimerHandle_t xTimerCreate( const char * const pcTimerName, /*l*/
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )
功能:创建定时器
参数:
- pcTimerName 定时器名
- xTimerPeriodInTicks 定时器周期,单位:tick
- uxAutoReload 是否自动重载
- pvTimerID 定时器id
- pxCallbackFunction 定时器回调函数
返回值:成功时定时器句柄,否则返回NULL
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait )
功能:执行定时器指令
参数:
- xTimer 定时器句柄
- xCommandID 指令id
- xOptionalValue 选项值,一般是执行指令时的tick值
- pxHigherPriorityTaskWoken 输出型参数,用来指示 是否有更高优先级的任务就绪
- xTicksToWait 等待超时时间
返回值:成功时返回1,否则返回0
TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
功能:获取定时器任务句柄
返回值:定时器任务句柄
TickType_t xTimerGetPeriod( TimerHandle_t xTimer )
功能:获取定时器周期
参数:
- xTimer 定时器句柄
返回值:定时器周期
void vTimerSetReloadMode( TimerHandle_t xTimer,
const UBaseType_t uxAutoReload )
功能:设置是否自动重载
参数:
- xTimer定时器句柄
- uxAutoReload 1:自动重载,0:执行一次
UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer )
功能:获取任务重载模式
参数:
- xTimer 定时器句柄
返回值:自动重载返回1,执行一次返回0。
TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )
功能:获取定时器超时时间
参数:
- xTimer 定时器句柄
返回值:定时器超时时间,即下一次执行时间
const char * pcTimerGetName( TimerHandle_t xTimer )
功能:获取定时器名
参数:
- xTimer 定时器句柄
返回值:定时器名
BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
功能:获取定时器是否有效
参数:
- xTimer 定时器句柄
返回值:定时器有效返回,否则返回0
void * pvTimerGetTimerID( const TimerHandle_t xTimer )
功能:获取定时器id
参数:
- xTimer 定时器句柄
返回值:定时器id
void vTimerSetTimerID( TimerHandle_t xTimer,
void * pvNewID )
功能:设置定时器id
参数:
- xTimer 定时器句柄
- pvNewID 定时器id
重点分析
TimerHandle_t xTimerCreate( const char * const pcTimerName, /**/
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )
{
Timer_t * pxNewTimer;
pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
if( pxNewTimer != NULL )
{
pxNewTimer->ucStatus = 0x00;
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
}
return pxNewTimer;
}
static void prvInitialiseNewTimer( const char * const pcTimerName, /*l. */
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
Timer_t * pxNewTimer )
{
configASSERT( ( xTimerPeriodInTicks > 0 ) );
if( pxNewTimer != NULL )
{
prvCheckForValidListAndQueue();
pxNewTimer->pcTimerName = pcTimerName;
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
pxNewTimer->pvTimerID = pvTimerID;
pxNewTimer->pxCallbackFunction = pxCallbackFunction;
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
if( uxAutoReload != pdFALSE )
{
pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
}
traceTIMER_CREATE( pxNewTimer );
}
}
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait )
{
BaseType_t xReturn = pdFAIL;
DaemonTaskMessage_t xMessage;
configASSERT( xTimer );
if( xTimerQueue != NULL )
{
/* 创建一个定时器消息并发送到定时器消息队列*/
xMessage.xMessageID = xCommandID;
xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.u.xTimerParameters.pxTimer = xTimer;
if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
{
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
{
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
}
else
{
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
}
}
else
{
xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
}
traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
return xReturn;
}
static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
const TickType_t xTimeNow )
{
BaseType_t xResult;
Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /* */
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
traceTIMER_EXPIRED( pxTimer );
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
{
if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )
{
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
configASSERT( xResult );
( void ) xResult;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
mtCOVERAGE_TEST_MARKER();
}
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
}
定时器任务
static portTASK_FUNCTION( prvTimerTask, pvParameters )
{
TickType_t xNextExpireTime;
BaseType_t xListWasEmpty;
( void ) pvParameters;
for( ; ; )
{
/* 获取下一个超时时间*/
xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
/* 处理定时器或者阻塞任务*/
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
/* 处理接收到的指令*/
prvProcessReceivedCommands();
}
}
static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
BaseType_t xListWasEmpty )
{
TickType_t xTimeNow;
BaseType_t xTimerListsWereSwitched;
vTaskSuspendAll();
{
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
if( xTimerListsWereSwitched == pdFALSE )
{
if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
{
( void ) xTaskResumeAll();
prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
}
else
{
if( xListWasEmpty != pdFALSE )
{
xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
}
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
else
{
( void ) xTaskResumeAll();
}
}
}

从当前定时器列表获取第一个定时器的超时时间
static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
{
TickType_t xNextExpireTime;
*pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
if( *pxListWasEmpty == pdFALSE )
{
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
}
else
{
xNextExpireTime = ( TickType_t ) 0U;
}
return xNextExpireTime;
}
采样当前时间,记录上一次的采样时间处理定时器列表切换
static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
{
TickType_t xTimeNow;
PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*l*/
xTimeNow = xTaskGetTickCount();
if( xTimeNow < xLastTime )
{
prvSwitchTimerLists();
*pxTimerListsWereSwitched = pdTRUE;
}
else
{
*pxTimerListsWereSwitched = pdFALSE;
}
xLastTime = xTimeNow;
return xTimeNow;
}
static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
const TickType_t xNextExpiryTime,
const TickType_t xTimeNow,
const TickType_t xCommandTime )
{
BaseType_t xProcessTimerNow = pdFALSE;
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
if( xNextExpiryTime <= xTimeNow )
{
if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /* */
{
xProcessTimerNow = pdTRUE;
}
else
{
vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
}
}
else
{
if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
{
xProcessTimerNow = pdTRUE;
}
else
{
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
}
}
return xProcessTimerNow;
}

static void prvProcessReceivedCommands( void )
{
DaemonTaskMessage_t xMessage;
Timer_t * pxTimer;
BaseType_t xTimerListsWereSwitched, xResult;
TickType_t xTimeNow;
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /* */
{
if( xMessage.xMessageID >= ( BaseType_t ) 0 )
{
pxTimer = xMessage.u.xTimerParameters.pxTimer;
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /**/
{
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
switch( xMessage.xMessageID )
{
case tmrCOMMAND_START:
case tmrCOMMAND_START_FROM_ISR:
case tmrCOMMAND_RESET:
case tmrCOMMAND_RESET_FROM_ISR:
case tmrCOMMAND_START_DONT_TRACE:
/* Start or restart a timer. */
pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
{
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
traceTIMER_EXPIRED( pxTimer );
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
{
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
configASSERT( xResult );
( void ) xResult;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
break;
case tmrCOMMAND_STOP:
case tmrCOMMAND_STOP_FROM_ISR:
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
break;
case tmrCOMMAND_CHANGE_PERIOD:
case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR:
pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
break;
case tmrCOMMAND_DELETE:
{
if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 )
{
vPortFree( pxTimer );
}
else
{
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
}
}
break;
default:
/* Don't expect to get here. */
break;
}
}
}
}

static void prvSwitchTimerLists( void )
{
TickType_t xNextExpireTime, xReloadTime;
List_t * pxTemp;
Timer_t * pxTimer;
BaseType_t xResult;
while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
{
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*li*/
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
traceTIMER_EXPIRED( pxTimer );
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
{
xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
if( xReloadTime > xNextExpireTime )
{
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
}
else
{
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
configASSERT( xResult );
( void ) xResult;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}

pxTemp = pxCurrentTimerList;
pxCurrentTimerList = pxOverflowTimerList;
pxOverflowTimerList = pxTemp;
}
浙公网安备 33010602011771号