原创 FreeRTOS队列发送

2009-6-20 10:53 3089 5 5 分类: MCU/ 嵌入式

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


PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条