新闻  |   论坛  |   博客  |   在线研讨会
FreeRTOS队列发送
mayer | 2009-06-21 12:56:02    阅读:6139   发布文章

FreeRTOS队列发送

 

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;
        }
    }
}

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客