原创 FreeRTOS队列接收

2009-6-20 10:56 2399 5 7 分类: MCU/ 嵌入式

与队列的发送对应,一般的队列接收函数也是由宏来实现,底层用一个函数来实现,队列接收函数有下面两个:


#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE )


#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE )


xQueuePeek与xQueueReceive的区别在于前者只接收而不删除条目,后者在成功接收后会删除原来的条目,两者均通过xQueueGenericReceive函数来实现,不能在中断中调用。


下面分析xQueueGenericReceive的实现方式:


signed portBASE_TYPE
xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer,
portTickType xTicksToWait, portBASE_TYPE xJustPeeking )

{

signed portBASE_TYPE xEntryTimeSet = pdFALSE;

xTimeOutType xTimeOut;

signed portCHAR *pcOriginalReadPosition;



    /* 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 space on the queue now?  To be running we must be

              the highest priority task wanting to access the queue. */       

            if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )   /*队列非空*/

            {

                /* Remember our read position in case we are just peeking. */

                pcOriginalReadPosition = pxQueue->pcReadFrom;



                prvCopyDataFromQueue( pxQueue, pvBuffer );



                if( xJustPeeking == pdFALSE )    /*复制完成后删除条目*/

                {

                    traceQUEUE_RECEIVE( pxQueue );



                    /* We are actually removing data. */

                    --( pxQueue->uxMessagesWaiting );



                    #if ( configUSE_MUTEXES == 1 )

                    {

                        if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )    /*与互斥锁相关的操作,改变互斥锁的拥有者为当前任务*/

                        {

                            /* Record the information required to implement

                            priority inheritance should it become necessary. */

                            pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();

                        }

                    }

                    #endif



                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )   /*如果过有条目在等待发送,则移出等待队列并进行切换*/

                    {

                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )

                        {

                            taskYIELD();

                        }

                    }

                }

                else    /*不删除条目*/

                {

                    traceQUEUE_PEEK( pxQueue );



                    /* We are not removing the data, so reset our read

                    pointer. */

                    pxQueue->pcReadFrom = pcOriginalReadPosition;



                    /* The data is being left in the queue, so see if there are

                    any other tasks waiting for the data. */

                    if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )

                    {

                        /* Tasks that are removed from the event list will get added to

                        the pending ready list as the scheduler is still suspended. */

                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )

                        {

                            /* The task waiting has a higher priority than this task. */

                            taskYIELD();

                        }

                    }



                }



                taskEXIT_CRITICAL();

                return pdPASS;

            }

            else 
/*条目为空,如果xTicksToWait>0则插入到等待队列,否则直接返回,下面的操作跟队列发送时类似*/

            {

                if( xTicksToWait == ( portTickType ) 0 )

                {

                    /* The queue was empty and no block time is specified (or

                    the block time has expired) so leave now. */               

                    taskEXIT_CRITICAL();

                    traceQUEUE_RECEIVE_FAILED( pxQueue );

                    return errQUEUE_EMPTY;

                }

                else if( xEntryTimeSet == pdFALSE )

                {

                    /* The queue was empty and a block time was specified so

                    configure the timeout structure. */               

                    vTaskSetTimeOutState( &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. */

        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )

        {

            if( prvIsQueueEmpty( pxQueue ) )

            {

                traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );



                #if ( configUSE_MUTEXES == 1 )

                {

                    if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )

                    {

                        portENTER_CRITICAL();

                        {

                            vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );

                        }

                        portEXIT_CRITICAL();

                    }

                }

                #endif



                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );

                prvUnlockQueue( pxQueue );

                if( !xTaskResumeAll() )

                {

                    taskYIELD();

                }

            }

            else

            {

                /* Try again. */

                prvUnlockQueue( pxQueue );

                ( void ) xTaskResumeAll();

            }

        }

        else

        {

            prvUnlockQueue( pxQueue );

            ( void ) xTaskResumeAll();

            traceQUEUE_RECEIVE_FAILED( pxQueue );

            return errQUEUE_EMPTY;

        }

    }

}

相关网址:http://www.openrtos.cn/article/11.php

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户394669 2009-6-20 22:39

呵呵,两个月前拜读了前辈的几篇文章,现在有空就学学样子,分享自己学习过程中的一点收获。

用户1361860 2009-6-20 18:27

不错,freertos队列这块去年就想写个帖子,不过一直没时间写,bz写的不错
相关推荐阅读
用户394669 2010-01-17 08:55
(笔记)无光驱使用U盘安装XP与Vista双系统
原系统为Vista,由于受不了其蜗牛般的速度,决定换为XP,又因为XP下面驱动不完善,因此还需要保留vista备用。又由于笔记本光驱用不了几次就坏了,因此需要使用U盘安装。准备工作:将xp oem安装...
用户394669 2009-12-31 11:29
跨平台同步的文档管理
不知道什么时候开始养成了上网记笔记的坏习惯,见到实用的内容总想摘录下来。由于有时需要同时在linux与windows下工作,所以需要一个跨平台的解决方法。开始的时候使用google doc,但是由于众...
用户394669 2009-12-11 10:36
VPN配置笔记
因为众所周知的原因,没办法只好给自己配置了一个私有的VPN来访问国外技术网站,忙了大半天终于完成,特总结为笔记方便以后使用。我使用的为DiaHosting的VPS主机,CentOs5 i386系统,2...
用户394669 2009-10-23 10:57
linux 中文乱码转换方法
使用 enconv 命令, enconv 文件名 。自动检测编码,并转换为utf-8...
用户394669 2009-09-16 13:52
ARM正式加盟Linux基金会
新闻来源:网易科技9月16日消息,英国微处理器和微控制器制造商ARM公司宣布正式加盟Linux基金会。Linux负责销售和开发者计划的副总裁AmandaMcPherson在Liunx基金会上表示,“通...
用户394669 2009-08-20 17:59
ubuntu 不重启更新PATH的方法
编辑 /etc/bash.bashrc添加 PATH=$PATH:(添加的位置)键入 source /etc/profile 命令更新完成因记性不好, 写下来,免得以后又去搜 :)如有更好方法欢迎交流...
我要评论
2
5
关闭 站长推荐上一条 /3 下一条