FreeRTOS有三个一般的队列发送函数,xQueueSend(),
xQueueSendToFront() 和 xQueueSendToBack()
,此三个函数不可以在中断中使用,它们都是通过宏的方式实现,其中xQueueSend()与xQueueSendToBack()的定义是一样的,只是
为与早期的版本兼容而保留下来。
此三个宏定义如下:
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait )
xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait,
queueSEND_TO_FRONT )
#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait )
xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait,
queueSEND_TO_BACK )
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait )
xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait,
queueSEND_TO_BACK )
三个宏在底层均是通过xQueueGenericSend函数来实现,通过传递给此函数的最后一个参数来区别三个宏的实现,下面分析xQueueGenericSend函数的实现方式
signed portBASE_TYPE
xQueueGenericSend( xQueueHandle pxQueue, const void * const
pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
{
signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut;
/* This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest
of execution time efficiency. */
for( ;; )
{
taskENTER_CRITICAL();
{
/* Is there room on the queue now? To be running we must be
the highest priority task wanting to access the queue. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) /*判断队列是否已满,如果还有空的空间则插入条目*/
{
traceQUEUE_SEND( pxQueue );
/*
prvCopyDataToQueue函数用于把条目数据复制到队列中
xCopyPosition为queueSEND_TO_FRONT时把条目数据复制到pcReadFrom指向的位置,即放到第一项
为queueSEND_TO_BACK时则复制到pcWriteTo指向的位置,即为最后一项
*/
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
/* If there was a task waiting for data to arrive on the
queue then unblock it now. */
/*如果有任务在等待则把任务从等待队列移出然后进行调度*/
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
{
/* The unblocked task has a priority higher than
our own so yield immediately. Yes it is ok to do
this from within the critical section - the kernel
takes care of that. */
taskYIELD();
}
}
taskEXIT_CRITICAL();
return pdPASS;
}
else /*队列已满,如果xTicksToWait>0则把任务插入到等待队列,否则直接返回队列满信息*/
{
if( xTicksToWait == ( portTickType ) 0 ) /*不等待返回*/
{
/* The queue was full and no block time is specified (or
the block time has expired) so leave now. */
taskEXIT_CRITICAL();
traceQUEUE_SEND_FAILED( pxQueue );
return errQUEUE_FULL;
}
else if( xEntryTimeSet == pdFALSE )
{
/* The queue was full and a block time was specified so
configure the timeout structure. */
vTaskSetTimeOutState( &xTimeOut ); /*把xTimeOut初始化为当前的系统时间计数*/
xEntryTimeSet = pdTRUE;
}
}
}
taskEXIT_CRITICAL();
/* Interrupts and other tasks can send to and receive from the queue
now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
/* Update the timeout state to see if it has expired yet. */
/*检查超时是否已经到达,并且通过当前系统时间来校正xTicksToWait的值*/
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
if( prvIsQueueFull( pxQueue ) ) /*如果队列已满,则把当前任务插入到队列的等待列表中*/
{
traceBLOCKING_ON_QUEUE_SEND( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
/* Unlocking the queue means queue events can effect the
event list. It is possible that interrupts occurring now
remove this task from the event list again - but as the
scheduler is suspended the task will go onto the pending
ready last instead of the actual ready list. */
prvUnlockQueue( pxQueue );
/* Resuming the scheduler will move tasks from the pending
ready list into the ready list - so it is feasible that this
task is already in a ready list before it yields - in which
case the yield will not cause a context switch unless there
is also a higher priority task in the pending ready list. */
if( !xTaskResumeAll() )
{
taskYIELD();
}
}
else /*队列未满,重试插入*/
{
/* Try again. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
}
}
else /*已经超时,不等待返回*/
{
/* The timeout has expired. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
traceQUEUE_SEND_FAILED( pxQueue );
return errQUEUE_FULL;
}
}
}
相关网址:http://www.openrtos.cn/article/10.php
文章评论(0条评论)
登录后参与讨论