5.FreeRTOS_队列基础知识

队列实质:队列是一个环形缓冲区,遵循先入先出(FIFO),通常将数据写入尾部,也可强制写到头部。当强制写到头部时,并不会覆盖原来的头部数据。

队列等待唤醒原则:唤醒最高优先级的任务。当优先级一致时,唤醒已经等待时间最长的任务

队列中包含的内容:数据buf,等待数据的任务,等待写数据的任务 

队列结构体

队列结构体的声明如下:

typedef xQUEUE Queue_t;

typedef struct QueueDefinition 
{
    /* 指针,用于指向存储数据的空间 */
    int8_t * pcHead;    /* 空间头部 */      
    int8_t * pcWriteTo; /* 写入的空间位置 */      
    
    union
    {
        QueuePointers_t xQueue; /* 读队列相关结构体 */    
        SemaphoreData_t xSemaphore; 
    } u;
    
    /* 链表,用于存放等待写入数据任务、等待读取数据任务 */
    List_t xTasksWaitingToSend;    /* 写入数据任务 */             
    List_t xTasksWaitingToReceive; /* 读取数据任务 */        

    volatile UBaseType_t uxMessagesWaiting; 
    UBaseType_t uxLength;                   
    UBaseType_t uxItemSize;                 

    volatile int8_t cRxLock;                
    volatile int8_t cTxLock;               

    #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
        uint8_t ucStaticallyAllocated; 
    #endif

    #if ( configUSE_QUEUE_SETS == 1 )
        struct QueueDefinition * pxQueueSetContainer;
    #endif

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxQueueNumber;
        uint8_t ucQueueType;
    #endif
} xQUEUE;

pcHead:指向数据空间的首地址,不会改变

pcWriteTo:向哪里进行写入,指向写入的位置 

xQueue:读队列相关结构体,里面存放了上一次读取的位置:pcReadFrom

xTasksWaitingToSend:等待写入数据任务的队列

xTasksWaitingToReceive:等待读取数据任务的队列

补充:

xQueue结构体声明如下:

/* 队列结构体中的形式 */
QueuePointers_t xQueue; /* 读队列相关结构体 */ 

/* QueuePointers_t结构体声明 */
typedef struct QueuePointers
{
    int8_t * pcTail;    
    int8_t * pcReadFrom; /* 读指针 */
} QueuePointers_t;

创建队列

函数声明

创建队列有两个接口,一个是宏xQueueCreate,另一个是这个宏的宏定义xQueueGenericCreate

这两个函数实质上都是一样的,具体的函数声明如下:

/* 这是一个宏 */
xQueueCreate( uxQueueLength, uxItemSize );

/* 宏定义 */
#define xQueueCreate( uxQueueLength, uxItemSize ) \ 
        xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) );

/* 这是xQueueCreate的宏定义 */
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,
                                   const UBaseType_t uxItemSize,
                                   const uint8_t ucQueueType        );

返回值:创建成功返回队列的句柄,失败返回0

uxItemSize:每一个项Item的大小,假设为int,那么 传入值为sizeof(int)

uxQueueLength:队列的长度

补充:

  • 队列长度:队列中包含的数据的个数
  • 队列数据:每个数据的类型不同,但每个数据的大小固定

创建队列过程

创建队列函数会分配一个Queue_t类型的结构体,并且开辟一个空间,让结构体中的pchead、pcWriteTo指向空间的头部,让pcReadFrom指向空间的尾部。

创建后的模型如下:

5.FreeRTOS_队列基础知识_第1张图片

写队列(尾插)

函数声明

写队列有三个接口,一个是宏xQueueSend,另一个是这个宏的宏定义xQueueGenericSend,还有一个函数xQueueSendToBack,这个函数与xQueueSend作用一致。

具体的函数声明如下:

/* 这两个是宏,作用一致,都是向尾部写入数据 */
xQueueSend( xQueue, pvItemToQueue, xTicksToWait );
xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait );

/* 宏定义 */
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \
    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) \
    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

/* 宏定义函数 */
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition )

xQueue:队列的句柄,即:创建队列函数的返回值

pvItemToQueue:原始数据的指针

xTicksToWait :当队列为满时等待写入的时间。写0表示不等待,portMAX_DELAY表示死等

写队列过程

写队列的过程为:从pvItemToQueue指向的空间中拷贝到pcWriteTo指向的空间,拷贝的数据大小为uxItemSize。之后pcWriteTo+uxItemSize进行写指针偏移。

具体模型如下:

5.FreeRTOS_队列基础知识_第2张图片

队列为满时的过程

当写队列时,队列已经满了,并且xTicksToWait不为0,那么该写数据的任务将会放到xTasksWaitingToSend这个等待写入数据任务队列中,这时该任务进入阻塞态,不再争夺CPU资源。当队列数据被读出,不再为满时,再从xTasksWaitingToSend这个队列中去唤醒刚刚的任务。

写队列(头插)

一般写队列的方法都是尾插法,这里也可以进行头插法进行写队列。

函数声明

/* 这是一个宏,头插法写入 */
xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait )

/* 宏定义 */
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) \
  xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )

/* 最终调用的底层函数与尾插法一致,只是传参不一致 */
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition )

xQueue:队列的句柄,即:创建队列函数的返回值

pvItemToQueue:原始数据的指针

xTicksToWait :当队列为满时等待写入的时间。写0表示不等待

写队列过程

头插法写队列,会将队列写到空间的最尾端(N-1处),并且将pcReadFrom向前移动

具体模型如下:

5.FreeRTOS_队列基础知识_第3张图片

读队列

函数声明

BaseType_t xQueueReceive( QueueHandle_t xQueue,
                          void * const pvBuffer,
                          TickType_t xTicksToWait )

xQueue:队列的句柄,即:创建队列函数的返回值

pvBuffer:读取数据存放空间的指针

xTicksToWait :当队列为空时等待读取的时间。写0表示不等待

读队列过程

pcReadFrom为上一次读的位置。读队列时,先将pcReadFrom+uxItemSize,之后再拷贝pcReadFrom指向位置的内容到pvBuffer中,拷贝的数据大小为uxItemSize

具体模型如下:

5.FreeRTOS_队列基础知识_第4张图片

队列为空时的过程

当读队列时,队列为空,并且xTicksToWait不为0,那么该读数据的任务将会放到xTasksWaitingToReceive这个等待读取数据任务队列中,这时该任务进入阻塞态,不再争夺CPU资源。。当队列数据被写入,不再为空时,再从xTasksWaitingToReceive这个队列中去唤醒刚刚的任务。

你可能感兴趣的:(FreeRTOS,数据库)