freeRTOS 队列1 创建&初始化


freeRTOS最吸引我的地方,就是他的任务间通信、任务间同步所用的概念,全部都建立在“队列”的基础之上。

只要抓住队列的实现,对其他的就比较清晰了。

对任务状态的管理,建立在“列表”的基础之上。

 

Queue_t
queue.h

步骤:
xQueueCreate( uxQueueLength, uxItemSize ) -> xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) -> prvInitialiseNewQueue -> xQueueGenericReset
|
+-- vListInitialise( &( pxQueue->xTasksWaitingToSend ) );
+-- vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
 

 

 

本节只有创建队列、初始化队列两部分。参考地址:http://blog.csdn.net/zhzht19861011/article/details/51510384

Queue_t

typedef struct QueueDefinition  
{  
    int8_t *pcHead;             /* 指向队列存储区起始位置,即第一个队列项 */  
    int8_t *pcTail;             /* 指向队列存储区结束后的下一个字节 */  
    int8_t *pcWriteTo;          /* 指向下队列存储区的下一个空闲位置 */  
  
  
    union                       /* 使用联合体用来确保两个互斥的结构体成员不会同时出现 */  
    {  
        int8_t *pcReadFrom;     /* 当结构体用于队列时,这个字段指向出队项目中的最后一个. */  
        UBaseType_t uxRecursiveCallCount;/* 当结构体用于互斥量时,用作计数器,保存递归互斥量被"获取"的次数. */  
    } u;  
  
  
    List_t xTasksWaitingToSend;      /* 因为等待入队而阻塞的任务列表,按照优先级顺序存储 */  
    List_t xTasksWaitingToReceive;   /* 因为等待队列项而阻塞的任务列表,按照优先级顺序存储 */  
  
  
    volatile UBaseType_t uxMessagesWaiting;/*< 当前队列的队列项数目 */  
    UBaseType_t uxLength;            /* 队列项的数目 */  
    UBaseType_t uxItemSize;          /* 每个队列项的大小 */  
  
  
    volatile BaseType_t xRxLock;   /* 队列上锁后,存储从队列收到的列表项数目,如果队列没有上锁,设置为queueUNLOCKED */  
    volatile BaseType_t xTxLock;   /* 队列上锁后,存储发送到队列的列表项数目,如果队列没有上锁,设置为queueUNLOCKED */  
  
  
    #if ( configUSE_QUEUE_SETS == 1 )  
        struct QueueDefinition *pxQueueSetContainer;  
    #endif  
  
  
    #if ( configUSE_TRACE_FACILITY == 1 )  
        UBaseType_t uxQueueNumber;  
        uint8_t ucQueueType;  
    #endif  
  
  
    #if ( configSUPPORT_STATIC_ALLOCATION == 1 )  
        uint8_t ucStaticAllocationFlags;  
    #endif  
  
  
} xQUEUE;  
  
  
typedef xQUEUE Queue_t;  

 

 

queue.h

/**
 * Type by which queues are referenced. 【queue被引用的句柄】 For example, a call to xQueueCreate()
 * returns an QueueHandle_t variable that can then be used as a parameter to
 * xQueueSend(), xQueueReceive(), etc.
 */
typedef void * QueueHandle_t;
/* For internal use only. */
#define    queueSEND_TO_BACK         ( ( BaseType_t ) 0 )
#define    queueSEND_TO_FRONT        ( ( BaseType_t ) 1 )
#define    queueOVERWRITE            ( ( BaseType_t ) 2 )

/* For internal use only.  These definitions *must* match those in queue.c. */
#define queueQUEUE_TYPE_BASE                   ( ( uint8_t ) 0U )
#define queueQUEUE_TYPE_SET                    ( ( uint8_t ) 0U )
#define queueQUEUE_TYPE_MUTEX                  ( ( uint8_t ) 1U )
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE     ( ( uint8_t ) 2U )
#define queueQUEUE_TYPE_BINARY_SEMAPHORE       ( ( uint8_t ) 3U )
#define queueQUEUE_TYPE_RECURSIVE_MUTEX        ( ( uint8_t ) 4U )

/**
 QueueHandle_t xQueueCreate(
                              UBaseType_t uxQueueLength,
                              UBaseType_t uxItemSize
                          );
 * Creates a new queue instance, and returns a handle by which the new queue
 * can be referenced.
 *
 * Internally, within the FreeRTOS implementation, queues use two blocks of
 * memory.  The first block is used to hold the queue's data structures.  The
 * second block is used to hold items placed into the queue.  
+ If a queue is * created using xQueueCreate() then both blocks of memory are automatically * dynamically allocated inside the xQueueCreate() function.
+ If a queue is created using * xQueueCreateStatic() then the application writer must provide the memory that * will get used by the queue. xQueueCreateStatic() therefore allows a queue to * be created without using any dynamic memory allocation. * @param uxQueueLength The maximum number of items that the queue can contain. * * @param uxItemSize The number of bytes each item in the queue will require. * Items are queued by copy, not by reference, so this is the number of bytes * that will be copied for each posted item. Each item on the queue must be * the same size. * * @return If the queue is successfully create then a handle to the newly * created queue is returned. If the queue cannot be created then 0 is * returned. * * Example usage: struct AMessage { char ucMessageID; char ucData[ 20 ]; }; void vATask( void *pvParameters ) { QueueHandle_t xQueue1, xQueue2; // Create a queue capable of containing 10 uint32_t values. xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) ); if( xQueue1 == 0 ) { // Queue was not created and must not be used. } // Create a queue capable of containing 10 pointers to AMessage structures. // These should be passed by pointer as they contain a lot of data. xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) ); if( xQueue2 == 0 ) { // Queue was not created and must not be used. } } */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #define xQueueCreate( uxQueueLength, uxItemSize )
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) #endif /** QueueHandle_t xQueueCreateStatic( UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t *pucQueueStorageBuffer, StaticQueue_t *pxQueueBuffer ); * @param pucQueueStorageBuffer 【保存队列存储区】
If uxItemSize is not zero then * pucQueueStorageBuffer must point to a uint8_t array that is at least large * enough to hold the maximum number of items that can be in the queue at any * one time - which is ( uxQueueLength * uxItemsSize ) bytes.
If uxItemSize is * zero then pucQueueStorageBuffer can be NULL.

   * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which
   * will be used to hold the queue's data structure.【保存队列结构体】

 * Example usage:
 struct AMessage
 {
    char ucMessageID;
    char ucData[ 20 ];
 };

 #define QUEUE_LENGTH 10
 #define ITEM_SIZE sizeof( uint32_t )

 // xQueueBuffer will hold the queue structure.
 StaticQueue_t xQueueBuffer;

 // ucQueueStorage will hold the items posted to the queue.  Must be at least
 // [(queue length) * ( queue item size)] bytes long.
 uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];

 void vATask( void *pvParameters )
 {
 QueueHandle_t xQueue1;

    // Create a queue capable of containing 10 uint32_t values.
    xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold.
                            ITEM_SIZE      // The size of each item in the queue
                            &( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue.
                            &xQueueBuffer ); // The buffer that will hold the queue structure.

    // The queue is guaranteed to be created successfully as no dynamic memory
    // allocation is used.  Therefore xQueue1 is now a handle to a valid queue.

    // ... Rest of task code.
 }
 */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
    #define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) 
xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) ) #endif /* configSUPPORT_STATIC_ALLOCATION */

 

 分析动态创建函数  xQueueGenericCreate() 

    QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )
    {
    Queue_t *pxNewQueue;
    size_t xQueueSizeInBytes;
    uint8_t *pucQueueStorage;

        configASSERT( uxQueueLength > ( UBaseType_t ) 0 );

        if( uxItemSize == ( UBaseType_t ) 0 )
        {
            /* There is not going to be a queue storage area. */
            xQueueSizeInBytes = ( size_t ) 0;
        }
        else
        {
            /* Allocate enough space to hold the maximum number of items that
            can be in the queue at any time. */
            xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 */
        }

        pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );  【动态创建 队列存储区 和 队列结构体】

        if( pxNewQueue != NULL )
        {
            /* Jump past the queue structure to find the location of the queue
            storage area. */
            pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t );  【队列存储区地址】

            #if( configSUPPORT_STATIC_ALLOCATION == 1 )
            {
                /* Queues can be created either statically or dynamically, so
                note this task was created dynamically in case it is later
                deleted. 【pdFALSE 标记他是动态创建的】*/
                pxNewQueue->ucStaticallyAllocated = pdFALSE;
            }
            #endif /* configSUPPORT_STATIC_ALLOCATION */

            prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );  //<-- 
        }

        return pxNewQueue;
    }

 插一下

freeRTOSconfig.h
断言机制
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

 

 继续看prvInitaliseNewQueue

static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue )
{
    /* Remove compiler warnings about unused parameters should
    configUSE_TRACE_FACILITY not be set to 1. */
    ( void ) ucQueueType;

    if( uxItemSize == ( UBaseType_t ) 0 )
    {
        /* No RAM was allocated for the queue storage area, but PC head cannot
        be set to NULL because NULL is used as a key to say the queue is used as a mutex.  Therefore just set pcHead to point to the queue as a benign(good) value that is known to be within the memory map. */
        pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;  【做个标记而已,没有实际存储区】
    }
    else
    {
        /* Set the head to the start of the queue storage area. */
        pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
    }

    /* Initialise the queue members as described where the queue type is
    defined. */
    pxNewQueue->uxLength = uxQueueLength;
    pxNewQueue->uxItemSize = uxItemSize;
    ( void ) xQueueGenericReset( pxNewQueue, pdTRUE );  //<-- 复位队列 #if ( configUSE_TRACE_FACILITY == 1 )【略】
    {
        pxNewQueue->ucQueueType = ucQueueType;
    }
    #endif /* configUSE_TRACE_FACILITY */

    #if( configUSE_QUEUE_SETS == 1 )【略】
    {
        pxNewQueue->pxQueueSetContainer = NULL;
    }
    #endif /* configUSE_QUEUE_SETS */

    traceQUEUE_CREATE( pxNewQueue );
}

 

继续:

BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
{
Queue_t * const pxQueue = ( Queue_t * ) xQueue;

    configASSERT( pxQueue );

    taskENTER_CRITICAL();
    {
        pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );
        pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
        pxQueue->pcWriteTo = pxQueue->pcHead;
        pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
        pxQueue->cRxLock = queueUNLOCKED;
        pxQueue->cTxLock = queueUNLOCKED;

        if( xNewQueue == pdFALSE )  【不是新创建的队列】
        {
            /* If there are tasks blocked waiting to read from the queue, then
            the tasks will remain blocked as after this function exits the queue
            will still be empty.  
If there are tasks blocked waiting to write to the queue, then one should be unblocked as after this function exits it will be possible to write to it.
*/ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 如果有任务等待写入队列,这个任务可以被Unblock { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) ## 见后 { queueYIELD_IF_USING_PREEMPTION(); } else { mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); } } else 【是新创建的队列】 { /* Ensure the event queues start in the correct state. */ vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); } } taskEXIT_CRITICAL(); /* A value is returned for calling semantic consistency with previous versions. */ return pdPASS; }

 

##  xTaskRemoveFromEventList

BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
{
TCB_t *pxUnblockedTCB;
BaseType_t xReturn;

    /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION.  It can also be
    called from a critical section within an ISR. */

    /* The event list is sorted in priority order, so the first in the list can
    be removed as it is known to be the highest priority.  Remove the TCB from
    the delayed list, and add it to the ready list.

    If an event is for a queue that is locked then this function will never
    get called - the lock count on the queue will get modified instead.  This
    means exclusive access to the event list is guaranteed here.

    This function assumes that a check has already been made to ensure that
    pxEventList is not empty. */
    pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
    configASSERT( pxUnblockedTCB );
    ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );

    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )  如果调度器没有关闭,将任务放入就绪任务列表
    {
        ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) );
        prvAddTaskToReadyList( pxUnblockedTCB );
    }
    else  调度器关闭,将任务放入PendingReadyList,不排序的插入
    {
        /* The delayed and ready lists cannot be accessed, so hold this task
        pending until the scheduler is resumed. */
        vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
    }

    if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )  Unblock的任务优先级比当前的任务高
    {
        /* Return true if the task removed from the event list has a higher
        priority than the calling task.  This allows the calling task to know if it should force a context switch now. */
        xReturn = pdTRUE;

        /* Mark that a yield is pending in case the user is not using the
        "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
        xYieldPending = pdTRUE;
    }
    else
    {
        xReturn = pdFALSE;
    }

    #if( configUSE_TICKLESS_IDLE != 0 )
    {
        /* If a task is blocked on a kernel object then xNextTaskUnblockTime
        might be set to the blocked task's time out time.  If the task is
        unblocked for a reason other than a timeout xNextTaskUnblockTime is
        normally left unchanged, because it is automatically reset to a new
        value when the tick count equals xNextTaskUnblockTime.  However if
        tickless idling is used it might be more important to enter sleep mode
        at the earliest possible time - so reset xNextTaskUnblockTime here to
        ensure it is updated at the earliest possible time. */
        prvResetNextTaskUnblockTime();
    }
    #endif

    return xReturn;
}

 

 

 

 

 

 

留白


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM