ESP32 FreeRTOS-queue(7)

Tip: A good memory is not as good as a bad pen. This blog is used as a study note, if there is a mistake, I hope to correct it

Foreword:

  References: FreeRTOS API Reference
  In the previous section, we described how to create a task, how to use it, and debug the task. Here we often execute multiple tasks during development. In the development without an operating system, we need to exchange data between different .c files. We generally use global variables, which are generally not recommended for development with an operating system. Such use may cause two tasks There is a problem when accessing a variable at the same time. Our queue is commonly used for communication with operating system tasks. The function of the queue is very powerful. *

1. xQueueCreate()

API prototype:

 QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,
                             UBaseType_t uxItemSize );

  Creates a new queue and returns a handle that can refer to this queue. configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h, or left undefined (in which case it defaults to 1) to use this RTOS API function.
  Each queue requires RAM for holding the state of the queue and the items contained in the queue (queue storage area). If the queue is created using xQueueCreate(), the required RAM will be automatically allocated from the FreeRTOS heap. If the queue is created using xQueueCreateStatic(), the RAM is provided by the application writer, which results in more parameters, but this enables static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for details.

Parameters:
  uxQueueLength The maximum number of items that the queue can hold simultaneously.
  uxItemSize The size in bytes required to store each data item in the queue.
  Data items are queued by copy, not by reference, so this value is the number of bytes that will be copied for each queued item. Each data item in the queue must be the same size.

Returns:
  If the queue is created successfully, it returns the handle of the created queue. Returns NULL if the memory required to create the queue cannot be allocated.
  When creating a queue, we can specify the length of the queue and the size of each long queue. We can use sizeof() to get the length of the queue. The space occupied by the queue = the length of the queue X sizeof(). The transmission parameters of the queue can be arbitrary, and we can transmit integers, floating-point types, arrays, strings, and pointers.
Example usage:

struct AMessage
{
    
    
    char ucMessageID;
    char ucData[ 20 ];
};

void vATask( void *pvParameters )
{
    
    
QueueHandle_t xQueue1, xQueue2;

    /* 创建一个能够包含10个无符号长值的队列。*/
    xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );

    if( xQueue1 == NULL )
    {
    
    
        /*队列未被创建,不得使用。*/
    }

    /* 创建一个能够包含10个AMessage结构指针的队列。
    结构的指针。 这些要用指针来排队,因为它们是
    相对较大的结构。*/
    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );

    if( xQueue2 == NULL )
    {
    
    
        /*队列未被创建,不得使用。*/
    }
 }

Two, xQueueCreateStatic ()

API prototype:

 QueueHandle_t xQueueCreateStatic(
                             UBaseType_t uxQueueLength,
                             UBaseType_t uxItemSize,
                             uint8_t *pucQueueStorageBuffer,
                             StaticQueue_t *pxQueueBuffer );

  Creates a new queue and returns a handle that can refer to the queue.
  configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for this RTOS API function to be available.
  Each queue requires RAM to hold the state of the queue and the data items contained in the queue (queue memory area). If a queue is created using xQueueCreate(), it is automatically allocated from the RAM heap FreeRTOS. If the queue is created using xQueueCreateStatic(), the RAM is provided by the application writer, which results in more parameters, but this enables static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for details.

Parameters:
  uxQueueLength The maximum number of items that the queue can hold simultaneously.
  uxItemSize The size in bytes required to store each data item in the queue.
Data items are queued by copy, not by reference, so this value is the number of bytes that will be copied for each queued item. Each data item in the queue must be the same size.
  pucQueueStorageBuffer If uxItemSize is non-zero, pucQueueStorageBuffer must point to an array of uint8_t at least large enough to hold the maximum number of items that can exist in the queue simultaneously, ie (uxQueueLength * uxItemSize) bytes. pucQueueStorageBuffer can be Null if uxItemSize is zero.
  pxQueueBuffer must point to a variable of type StaticQueue_t, which will be used to save the data structure of the queue.
Returns:
  If the queue is created successfully, it returns the handle of the created queue. Returns NULL if pxQueueBuffer is NULL.
  Compared with xQueueCreate(), xQueueCreateStatic() both create queues, but we generally use xQueueCreate() to create queues without special circumstances. When using xQueueCreateStatic() to create queues, we need to provide memory allocation.
Example usage:

/* 该队列将被创建为最多容纳10个uint64_t变量。*/
#define QUEUE_LENGTH    10
#define ITEM_SIZE       sizeof( uint64_t )

/* 用来保存队列数据结构的变量。*/
static StaticQueue_t xStaticQueue;

/* 用作队列存储区域的阵列。 这必须至少是uxQueueLength * uxItemSize字节。*/
uint8_t ucQueueStorageArea[ QUEUE_LENGTH * ITEM_SIZE ];

void vATask( void *pvParameters )
{
    
    
	QueueHandle_t xQueue;
    /* 创建一个能够包含10个uint64_t值的队列。*/
    xQueue = xQueueCreateStatic( QUEUE_LENGTH,
                                 ITEM_SIZE,
                                 ucQueueStorageArea,
                                 &xStaticQueue );

    /* pxQueueBuffer不是NULL,所以xQueue不应该是NULL。*/
    configASSERT( xQueue );
 }

3. vQueueDelete()

API prototype:

void vQueueDelete( QueueHandle_t xQueue );

  Delete Queue — Frees all memory allocated to store items placed on the queue.
Parameters:
  xQueue Handle to the queue to delete.

4. xQueueSend()

API prototype:

BaseType_t xQueueSend(
	                     QueueHandle_t xQueue,
	                     const void * pvItemToQueue,
	                     TickType_t xTicksToWait);

  This is a macro that calls xQueueGenericSend(). It is used for backward compatibility with versions of FreeRTOS that do not contain the xQueueSendToFront() and xQueueSendToBack() macros. It is equivalent to xQueueSendToBack().
  Post an item in the queue. The item is queued by copy, not by reference. This function must not be called from an Interrupt Service Routine. See xQueueSendFromISR() for an alternative that can be used with an ISR.
Parameters:
  xQueue Handle to the queue to which data items will be posted.
  pvItemToQueue Pointer to the data item to be enqueued. The size of items the queue will hold is defined when the queue is created, so a fixed number of bytes will be copied from pvItemToQueue to the queue storage area.
  xTicksToWait If the queue is full, the maximum time the task should enter the blocking state waiting for free space to appear on the queue. If the queue is full and xTicksToWait is set to 0, the call will return immediately. Times are defined in tick periods, so the constant portTICK_PERIOD_MS should be used to convert to real time if required.
If INCLUDE_vTaskSuspend is set to "1", specifying a blocking time of portMAX_DELAY causes the task to block indefinitely (with no timeout).
Returns:
  pdTRUE if the item is successfully published, otherwise errQUEUE_FULL.
Example usage:

struct AMessage
 {
    
    
    char ucMessageID;
    char ucData[ 20 ];
 } xMessage;

 unsigned long ulVar = 10UL;

 void vATask( void *pvParameters )
 {
    
    
	 QueueHandle_t xQueue1, xQueue2;
	 struct AMessage *pxMessage;
	
	/* 创建一个能够包含10个无符号长值的队列。*/
	xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
	
	/* 创建一个队列,能够包含10个指向AMessage结构的指针。
	这些应该通过指针传递,因为它们包含了大量的数据。*/
	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
    /* ... */
    if( xQueue1 != 0 )
    {
    
    
        /* 发送一个无符号长信息。 如果有必要的话,等待10秒钟,让空间变得
        如果需要的话。*/
        if( xQueueSend( xQueue1,
                       ( void * ) &ulVar,
                       ( TickType_t ) 10 ) != pdPASS )
        {
    
    
            /* 发布信息失败,即使在10个刻度之后。*/
        }
    }

    if( xQueue2 != 0 )
    {
    
    
        /* 发送一个指向AMessage结构对象的指针。 如果队列已经满了,就不要阻塞。
        队列已经满了。*/
        pxMessage = & xMessage;
        xQueueSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 )}
	/* ... 任务代码的其余部分。*/
 }

5. xQueueSendFromISR()

API prototype:

BaseType_t xQueueSendFromISR
          (
              QueueHandle_t xQueue,
              const void *pvItemToQueue,
              BaseType_t *pxHigherPriorityTaskWoken);

  This is the macro used to call xQueueGenericSendFromISR(). This macro was added for backward compatibility with versions of FreeRTOS that did not include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR() macros.
  Post an item to the tail of the queue. It is safe to use this function in an interrupt service routine.
  Data items are enqueued by copy, not by reference, so it is best to only enqueue smaller items, especially when called from an ISR. In most cases it is better to store a pointer to the data item being queued.
Parameters:
  xQueue Handle to the queue to which data items will be posted.
  pvItemToQueue Pointer to the data item to be enqueued. The size of items the queue will hold is defined when the queue is created, so a fixed number of bytes will be copied from pvItemToQueue to the queue storage area.
  pxHigherPriorityTaskWoken xQueueSendFromISR() sets *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue causes a task to unblock, and the unblocked task has a higher priority than the currently running task. If xQueueSendFromISR() sets this value to pdTRUE, a context switch should be requested before the interrupt exits.
  Starting with FreeRTOS V7.3.0, pxHigherPriorityTaskWoken is an optional parameter that can be set to NULL.
Returns:
  pdTRUE if the data is successfully sent to the queue, otherwise errQUEUE_FULL.
Usage example of buffered IO (multiple values ​​can be obtained per call to ISR):
usage example:

void vBufferISR( void )
{
    
    
	char cIn;
	BaseType_t xHigherPriorityTaskWoken;

    /* 我们在ISR开始时没有唤醒一个任务。*/
    xHigherPriorityTaskWoken = pdFALSE;

    /* 循环直到缓冲区为空。*/
    do
    {
    
    
        /* 从缓冲区获取一个字节。*/
        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS )

        /* 发布该字节。*/
        xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken )

    } while( portINPUT_BYTE( BUFFER_COUNT ))

    /* 现在缓冲区是空的,如果需要,我们可以切换上下文。*/
    if( xHigherPriorityTaskWoken )
    {
    
    
        /* 这里使用的实际宏是针对端口的。*/
        taskYIELD_FROM_ISR()。
    }
}

6. xQueueSendToBack()

API prototype:

BaseType_t xQueueSendToBack(
		                      QueueHandle_t xQueue,
		                      const void * pvItemToQueue,
		                      TickType_t xTicksToWait);

  This is a macro that calls xQueueGenericSend(). It is equivalent to xQueueSend().
  Enqueue a data item from the end of the queue. Data items are enqueued by copy rather than by reference. must not be interrupted from the Service Routine. See xQueueSendToBackFromISR () for an alternative that can be used in an ISR.

Parameters:
  xQueue Handle to the queue to which data items will be posted.
  pvItemToQueue Pointer to the data item to be enqueued. The size of items the queue will hold is defined when the queue is created, so a fixed number of bytes will be copied from pvItemToQueue to the queue storage area.
  xTicksToWait If the queue is full, the maximum time the task should enter the blocking state waiting for free space to appear on the queue. If set to 0, the call will return immediately. Time is defined in tick periods, so the constant portTICK_PERIOD_MS should be used to convert to real time if necessary.
If INCLUDE_vTaskSuspend is set to "1", specifying a blocking time of portMAX_DELAY causes the task to block indefinitely (with no timeout).
Returns:
  pdTRUE if the item is successfully published, otherwise errQUEUE_FULL.
Example usage:

struct AMessage
{
    
    
    char ucMessageID;
    char ucData[ 20 ];
} xMessage;

unsigned long ulVar = 10UL;

void vATask( void *pvParameters )
{
    
    
	QueueHandle_t xQueue1, xQueue2;
	struct AMessage *pxMessage;
	/* 创建一个能够包含10个无符号长值的队列。*/
    xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) )/* 创建一个队列,能够包含10个指向AMessage结构的指针。
    结构的指针。 这些应该通过指针传递,因为它们包含大量的
    数据。*/
    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) )/* ... */
    if( xQueue1 != 0 )
    {
    
    
        /* 发送一个无符号长信息。 如果有必要的话,等待10秒钟,让空间变得
        如果需要的话。*/
        if( xQueueSendToBack( xQueue1,
                             ( void * ) &ulVar,
                             ( TickType_t ) 10 ) != pdPASS )
        {
    
    
            /* 发布信息失败,即使在10个刻度之后。*/
        }
    }

    if( xQueue2 != 0 )
    {
    
    
        /* 发送一个指向AMessage结构对象的指针。 如果队列已经满了,就不要阻塞。
        队列已经满了。*/
        pxMessage = & xMessage;
        xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 )}
	/* ... 任务代码的其余部分。*/
}

7. xQueueSendToBackFromISR()

API prototype:

BaseType_t xQueueSendToBackFromISR(
			                       QueueHandle_t xQueue,
			                       const void *pvItemToQueue,
			                       BaseType_t *pxHigherPriorityTaskWoken);

  This macro is used to call xQueueGenericSendFromISR().
  Enqueue a data item from the end of the queue. This function can be used in an interrupt service routine.
  Data items are enqueued by copy rather than by reference, so it's best to only send smaller items, especially when called from an ISR.
Parameters:
  xQueue Handle to the queue to which data items will be posted.
  pvItemToQueue Pointer to the data item to be enqueued. The size of items the queue will hold is defined when the queue is created, so a fixed number of bytes will be copied from pvItemToQueue to the queue storage area.
  pxHigherPriorityTaskWoken xQueueSendTobackFromISR() sets *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue causes a task to unblock, and the unblocked task has a higher priority than the currently running task. If xQueueSendTobackFromISR() sets this value to pdTRUE, a context switch should be requested before exiting the interrupt.
  Starting from FreeRTOSV7.3.0, pxHigherPriorityTaskWoken is an optional parameter that can be set to NULL.
Return:
  If it is successfully sent to the queue, it will return pdPASS, otherwise it will return errQUEUE_FULL.
  Usage example of buffered IO (multiple values ​​can be obtained per call to ISR):
usage example:

void vBufferISR( void )
{
    
    
	char cIn;
	BaseType_t xHigherPriorityTaskWoken;

    /* 我们在ISR开始时没有唤醒一个任务。*/
    xHigherPriorityTaskWoken = pdFALSE;

    /* 循环直到缓冲区为空。*/
    do
    {
    
    
        /* 从缓冲区获取一个字节。*/
        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS )

        /* 发布该字节。*/
        xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken )

    } while( portINPUT_BYTE( BUFFER_COUNT ))

    /* 现在缓冲区是空的,如果需要,我们可以切换上下文。*/
    if( xHigherPriorityTaskWoken )
    {
    
    
        /* 这里使用的实际宏是针对端口的。*/
        taskYIELD_FROM_ISR()。
    }
}

8. xQueueSendToFront()

API prototype:

BaseType_t xQueueSendToFront( 
								QueueHandle_t xQueue,
								const void * pvItemToQueue,
								TickType_t xTicksToWait );

  This macro is used to call xQueueGenericSend().
  Enqueue a data item from the head of the queue. Data items are enqueued by copy rather than by reference. This function must not be called from an Interrupt Service Routine. See xQueueSendToFrontFromISR() for an alternative method that can be used in an ISR.
Parameters:
  xQueue Handle to the queue to which data items will be posted.
  pvItemToQueue Pointer to the data item to be enqueued. The size of items the queue will hold is defined when the queue is created, so a fixed number of bytes will be copied from pvItemToQueue to the queue storage area.
  xTicksToWait If the queue is full, the maximum time the task should enter the blocking state waiting for free space to appear on the queue. If set to 0, the call will return immediately. Time is defined in tick periods, so the constant portTICK_PERIOD_MS should be used to convert to real time if necessary.
If INCLUDE_vTaskSuspend is set to "1", specifying a blocking time of portMAX_DELAY causes the task to block indefinitely (with no timeout).
Returns:
  pdTRUE if the item is successfully published, otherwise errQUEUE_FULL.
Example usage:

struct AMessage
{
    
    
    char ucMessageID;
    char ucData[ 20 ];
} xMessage;

unsigned long ulVar = 10UL;

void vATask( void *pvParameters )
{
    
    
	QueueHandle_t xQueue1, xQueue2;
	struct AMessage *pxMessage;

    /* 创建一个能够包含10个无符号长值的队列。*/
    xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) )

    /* 创建一个队列,能够包含10个指向AMessage结构的指针。
    结构的指针。 这些应该通过指针传递,因为它们包含大量的
    数据。*/
    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) )

    /* ... */

    if( xQueue1 != 0 )
    {
    
    
        /* 发送一个无符号长信息。 如果有必要的话,等待10秒钟,让空间变得
        如果需要的话。*/
        if( xQueueSendToFront( xQueue1,
                              ( void * ) &ulVar,
                              ( TickType_t ) 10 ) != pdPASS )
        {
    
    
            /* 发布信息失败,即使是在10个tick之后。*/
        }
    }

    if( xQueue2 != 0 )
    {
    
    
        /* 发送一个指向AMessage结构对象的指针。 如果队列已经满了,就不要阻塞。
        队列已经满了。*/
        pxMessage = &xMessage;
        xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 )}

	/* ... 任务代码的其余部分。*/
}

Nine, xQueueSendToFrontFromISR()

API prototype:

BaseType_t xQueueSendToFrontFromISR(
                    QueueHandle_t xQueue,
                    const void *pvItemToQueue,
                    BaseType_t *pxHigherPriorityTaskWoken);

  This is the macro used to call xQueueGenericSendFromISR().
  Enqueue a data item from the head of the queue. This function can be used in an interrupt service routine.
  Data items are enqueued by copy, not by reference, so it's best to just send the smaller item, or a pointer to the item.
Parameters:
  xQueue Handle to the queue to which data items will be posted.
  pvItemToQueue Pointer to the data item to be enqueued. The size of items the queue will hold is defined when the queue is created, so a fixed number of bytes will be copied from pvItemToQueue to the queue storage area.
  pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() sets *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue causes a task to unblock, and the unblocked task has a higher priority than the currently running task. If xQueueSendToFrontFromISR() sets this value to pdTRUE, a context switch should be requested before the interrupt exits.
Starting with FreeRTOS V7.3.0, pxHigherPriorityTaskWoken is an optional parameter that can be set to NULL.
Return:
  If the data is successfully sent to the queue, pdPass is returned, otherwise errQUEUE_FULL is returned.

10. xQueueReceive()

API prototype:

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

  Receive an item from the queue. This item is received by copy, so the buffer must provide enough space. The number of bytes copied into the buffer is defined when the queue is created.
  This function must not be used in an interrupt service routine. See xQueueReceiveFromISR for possible options.
Parameters:
  pxQueue The handle of the queue that will receive items
  pvBuffer Pointer to the buffer where the received items will be copied.
  xTicksToWait Maximum time a task interrupts and waits for free space in the queue, should it be full. If set to 0, the call will return immediately. The time is defined in the slice interval, and the portTICK_RATE_MS constant is used to convert to actual time if necessary.
If INCLUDE_vTaskSuspend is defined as 1, the specified interruption time (portMAX_DELAY) will cause the task to be suspended indefinitely (no timeout).
Returns:
  pdTRUE if the item was successfully received from the queue, otherwise pdFALSE.

11. xQueueReceiveFromISR()

API prototype:

BaseType_t xQueueReceiveFromISR(
                   QueueHandle_t xQueue,
                   void *pvBuffer,
                   BaseType_t *pxHigherPriorityTaskWoken);

  Receive items from the queue. It is safe to use this function from within an interrupt service routine.
Parameters:
  xQueue The handle to the queue to receive items from.
  pvBuffer Pointer to the buffer into which received items will be copied.
  The pxHigherPriorityTaskWoken task can be blocked waiting for space to become available on the queue. If xQueueReceiveFromISR unblocks such tasks, *pxHigherPriorityTaskWoken will be set to pdTRUE, otherwise *pxHigherPriorityTaskWoken will remain unchanged.
Starting from FreeRTOSV7.3.0, pxHigherPriorityTaskWoken is an optional parameter that can be set to NULL.
Returns:
  pdTRUE if the item was successfully received from the queue, otherwise pdFALSE.
Example usage:

QueueHandle_t xQueue。
/* 创建一个队列并发布一些值的函数。*/
void vAFunction( void *pvParameters )
{
    
    
	char cValueToPost;
	const TickType_t xTicksToWait = ( TickType_t )0xff;

    /* 创建一个能够包含10个字符的队列。*/
    xQueue = xQueueCreate( 10, sizeof( char ) )if( xQueue == 0 )
    {
    
    
        /* 创建队列失败。*/
    }

    /* ... */

    /* 发布一些将在ISR中使用的字符。 如果队列
    则该任务将阻塞xTicksToWait ticks。*/
    cValueToPost = 'a';
    xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait )
    cValueToPost = 'b';
    xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait )

    /* ...继续发布字符...当队列变成满的时候,这个任务可能会阻塞。
    成为满的时候,这个任务可能会阻塞。*/

    cValueToPost = 'c'xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait )}

/* 输出队列中收到的所有字符的ISR。*/
void vISR_Routine( void )
{
    
    
	BaseType_t xTaskWokenByReceive = pdFALSE。
	char cRxedChar;
    while( xQueueReceiveFromISR( xQueue,
                                ( void * ) &cRxedChar,
                                &xTaskWokenByReceive) )
    {
    
    
        /* 收到了一个字符。 现在输出该字符。*/
        vOutputCharacter( cRxedChar )

        /* 如果从队列中移除字符,那么在队列中发帖的任务xTaskWokenByReceive将被设置为
        xTaskWokenByReceive将被设置为
        pdTRUE。 无论这个循环迭代多少次,只有一个任务被唤醒。
        任务都会被唤醒。*/
    }

    if( xTaskWokenByReceive != pdFALSE )
    {
    
    
        /* 我们应该切换上下文,以便ISR返回到一个不同的任务。
        注意:如何做到这一点取决于你所使用的端口。 检查
        你的端口的文档和例子。*/
        taskYIELD ()}
}

12. uxQueueMessagesWaiting()

API prototype:

UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue );

  Returns the number of messages stored in the queue.
Parameters:
  xQueue The handle to the queue being queried.
Returns:
  The number of messages available in the queue.

Thirteen, uxQueueMessagesWaitingFromISR()

API prototype:

UBaseType_t uxQueueMessagesWaitingFromISR( QueueHandle_t xQueue );

  A version of uxQueueMessagesWaiting() that can be called from an ISR. Returns the number of messages stored in the queue.
Parameters:
  xQueue The handle to the queue being queried.
Returns:
  The number of messages available in the queue.

14. uxQueueSpacesAvailable()

API prototype:

UBaseType_t uxQueueSpacesAvailable( QueueHandle_t xQueue );

  Returns the number of free spaces in the queue.
Parameters:
  xQueue The handle to the queue being queried.
Returns:
  The number of free spaces available in the queue.

15. xQueueReset()

API prototype:

BaseType_t xQueueReset( QueueHandle_t xQueue );

  Reset the queue to its original empty state.
Parameters:
  xQueue The handle of the queue being reset
Returns:
  Since FreeRTOSV7.2.0 xQueueReset() always returns pdPASS.

Sixteen, xQueueOverwrite()

API prototype:

BaseType_t xQueueOverwrite(
                              QueueHandle_t xQueue,
                              const void * pvItemToQueue
                           );

  This is the macro used to call the xQueueGenericSend() function.
  The xQueueSendToBack() version of the queue will write even if the queue is full, overwriting data already in the queue.
  xQueueOverwrite() is intended for use with queues of length 1, which means that the queue is either empty or full.
  This function should not be called from an Interrupt Service Routine (ISR). See xQueueOverwriteFromISR() for an alternative function that can be used in an ISR.
Parameters:
  xQueue The handle of the queue that receives and sends data.
  pvItemToQueue Pointer to the data item to be enqueued. Queue The number of items a queue can hold is defined when the queue is created, and the items are copied from pvItemToQueue to the queue storage area.
Returns:
  xQueueOverwrite() is a macro for calling xQueueGenericSend(), so it has the same return value as xQueueSendToFront(). However, since xQueueOverwrite() will write to the queue (even if the queue is full), pdPASS is the only value that can be returned.

Example usage:

 void vFunction( void *pvParameters )
 {
    
    
	 QueueHandle_t xQueue;
	 unsigned long ulVarToSend, ulValReceived;

    /* 创建一个队列来容纳一个无符号长值。 强烈建议
    强烈建议*不要*在可以包含多个值的队列上使用xQueueOverwrite()。
    强烈建议不要在可以包含一个以上的值的队列上使用xQueueOverwrite(),这样做会触发一个断言。
    如果定义了configASSERT()。*/
    xQueue = xQueueCreate( 1, sizeof( unsigned long ) )

    /* 使用xQueueOverwrite()将数值10写到队列中。*/
    ulVarToSend = 10;
    xQueueOverwrite( xQueue, &ulVarToSend )

    /* 窥视队列现在应该返回10,但在队列中留下数值10。
    的值留在队列中。 块时间为0,因为我们知道队列里有一个值。
    队列中有一个值。*/
    ulValReceived = 0;
    xQueuePeek( xQueue, &ulValReceived, 0 )

    if( ulValReceived != 10 )
    {
    
    
        /* 错误,除非另一个任务删除了该值。*/
    }

    /* 队列仍然是满的。 使用xQueueOverwrite()来覆盖
    用100来覆盖队列中的值。*/
    ulVarToSend = 100;
    xQueueOverwrite( xQueue, &ulVarToSend )

    /* 这一次从队列中读出,让队列再次变空。
    再次使用一个0的阻塞时间。*/
    xQueueReceive( xQueue, &ulValReceived, 0 )

    /* 读取的值应该是最后写入的值,即使队列中的值已经满了。
    读取的值应该是最后写入的值,即使在写入该值时队列已经满了。*/
    if( ulValReceived != 100 )
    {
    
    
        /* 错误,除非另一个任务正在使用同一个队列。*/
    }
    /* ... */
}

Seventeen, xQueueOverwriteFromISR()

API prototype:

 BaseType_t xQueueOverwriteFromISR(
                      QueueHandle_t xQueue,
                      const void * pvItemToQueue
                      BaseType_t *pxHigherPriorityTaskWoken);

  This is the macro used to call the xQueueGenericSend() function.
  The xQueueSendToBack() version of the queue will write even if the queue is full, overwriting data already in the queue.
  xQueueOverwrite() is intended for use with queues of length 1, which means that the queue is either empty or full.
  This function should not be called from an Interrupt Service Routine (ISR). See xQueueOverwriteFromISR() for an alternative function that can be used in an ISR.
Parameters:
  xQueue The handle of the queue that receives and sends data.
  pvItemToQueue Pointer to the data item to be enqueued. Queue The number of items a queue can hold is defined when the queue is created, and the items are copied from pvItemToQueue to the queue storage area.
Returns:
  xQueueOverwrite() is a macro for calling xQueueGenericSend(), so it has the same return value as xQueueSendToFront(). However, since xQueueOverwrite() will write to the queue (even if the queue is full), pdPASS is the only value that can be returned.

Example usage:

QueueHandle_t xQueue。

void vFunction( void *pvParameters )
{
    
    
    /* 创建一个队列来容纳一个无符号长值。 强烈建议不要使用
    强烈建议不要在可以包含多个值的队列上使用xQueueOverwriteFromISR()。
    强烈建议不要在可以包含一个以上的值的队列上使用xQueOverwriteFromISR(),这样做会触发一个断言。
    如果定义了configASSERT()。*/
    xQueue = xQueueCreate( 1, sizeof( unsigned long ) )}

void vAnInterruptHandler( void )
{
    
    
	/* xHigherPriorityTaskWoken在使用前必须被设置为pdFALSE。*/
	BaseType_t xHigherPriorityTaskWoken = pdFALSE。
	unsigned long ulVarToSend, ulValReceived;

    /* 使用xQueueOverwriteFromISR()将值10写到队列中。*/
    ulVarToSend = 10;
    xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken )

    /* 队列已满,但再次调用xQueueOverwriteFromISR()仍会通过,因为队列中持有的值。
    通过,因为队列中的值将被新的值覆盖。
    新值覆盖。*/
    ulVarToSend = 100;
    xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken )

    /* 从队列中读取数据现在将返回100。*/

    /* ... */

    if( xHigherPrioritytaskWoken == pdTRUE )
    {
    
    
        /* 写入队列导致一个任务解除封锁,并且解除封锁的任务
        的优先级高于或等于当前执行任务的优先级。
        执行的任务(该中断所中断的任务)的优先级。 执行一个
        执行上下文切换,使该中断直接返回到未阻塞的
        任务。*/
        portYIELD_FROM_ISR(); /*或portEND_SWITCHING_ISR(),具体取决于
        */取决于端口。
    }
}

18. xQueuePeek()

API prototype:

BaseType_t xQueuePeek(
	                    QueueHandle_t xQueue,
	                    void *pvBuffer,
	                    TickType_t xTicksToWait);

  This is a macro that calls the xQueueGenericReceive() function.
  Receives an item from the queue without removing the item from the queue. Items are received by a copy, so an appropriately sized buffer must be provided. When the queue is created, the number of bytes copied into the buffer is defined.
  Successfully received items are still in the queue, so will be returned again by the next call or xQueueReceive() call.
  This macro must not be used in interrupt service routines.
Parameters:
  xQueue The handle to the queue to receive items from.
  pvBuffer Pointer to the buffer where received items will be copied. It must be at least large enough to accommodate the size of the queue entry defined when the queue was created.
  xTicksToWait If the queue is empty when called, the maximum time the task should block waiting for an item to be received. The time is already defined in tick period, so the constant portTICK_PERIOD_MS should be used to convert it to real time if needed.
If INCLUDE_vTaskSuspend is set to "1", specifying a blocking time of portMAX_DELAY causes the task to block indefinitely (with no timeout).
Returns:
  pdTRUE if the item was successfully received (peeked) from the queue, pdFALSE otherwise.
Example usage:

struct AMessage
{
    
    
   char ucMessageID;
   char ucData[ 20 ];
} xMessage;

 QueueHandle_t xQueue。

 // 创建一个队列并发布一个值的任务。
 void vATask( void *pvParameters )
 {
    
    
 	struct AMessage *pxMessage;
    // 创建一个队列,能够包含10个指向AMessage结构的指针。
    // 这些应该用指针传递,因为它们包含大量的数据。
    xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
    if( xQueue == 0 )
    {
    
    
        // 创建队列失败。
    }

    // ...

    // 发送一个指向AMessage结构对象的指针。 如果队列已经满了,请不要阻塞。
    // queue is already full.
    pxMessage = &xMessage;
    xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );

    // ... 任务代码的其余部分。
 }

 // 从队列中偷看数据的任务。
 void vADifferentTask( void *pvParameters )
 {
    
    
 	struct AMessage *pxRxedMessage;
    if( xQueue != 0 )
    {
    
    
        // 在创建的队列中偷看一条消息。 如果一个
        // 消息不是立即可用的。
        if( xQueuePeek( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
        {
    
    
            // pcRxedMessage现在指向vATask发布的AMessage结构变量。
            // 由vATask发布,但该项目仍在队列中。
        }
    }

    // ... 任务代码的其余部分。
 }

19. xQueuePeekFromISR()

API prototype:

BaseType_t xQueuePeekFromISR(
                                QueueHandle_t xQueue, 
                                void * const pvBuffer);

  Version of xQueuePeek() that can be allocated from within an Interrupt Service Routine (ISR).
  Receives an item from the queue without removing the item from the queue. Items are received by a copy, so an appropriately sized buffer must be provided. When the queue is created, the number of bytes copied into the buffer is defined.
  Successfully received items are still in the queue, so will be returned again by the next call or by the return of any queue receive function call.
Parameters:
  xQueue The handle to the queue to receive items from.
  pvBuffer Pointer to copy receive item buffer. This must be at least large enough to accommodate the size of the queue entry as defined when the queue was created.
Returns:
  pdTRUE if the item was successfully received (peeped) from the queue, pdFALSE otherwise.

20. vQueueAddToRegistry()

API prototype:

void vQueueAddToRegistry(
                            QueueHandle_t xQueue,
                            char *pcQueueName);

  Give the queue a name and add the queue to the registry.
Parameters:
  xQueue The queue handle to add to the registry.
  The queue name specified by pcQueueName. This is a text string and is provided for debugging purposes only. The queue registry just stores a pointer to the string, so the string must be persistent (global variable, or preferably in ROM/Flash), not defined on the stack.
  The queue registry serves two purposes, both related to RTOS kernel-aware debugging:

  1. A textual name can be associated with a queue to facilitate identification of the queue in the debug GUI.
  2. Contains information needed by the debugger to locate each registered queue and semaphore.

  The queue registry serves no purpose unless an RTOS kernel-aware debugger is used.
  configQUEUE_REGISTRY_SIZE defines the maximum number of queues and semaphores that can be registered. Only those queues and semaphores need to be registered that are to be viewed with an RTOS kernel-aware debugger.
Example usage:

void vAFunction( void )
{
    
    
	QueueHandle_t xQueue;
	/* 创建一个足够大的队列,以容纳10个字符。*/
	xQueue = xQueueCreate( 10, sizeof( char ) );
	/* 我们希望这个队列可以在RTOS内核感知的调试器中查看。
	所以要注册它。*/
	vQueueAddToRegistry( xQueue, "AMeaningfulName");
}

21. vQueueUnregisterQueue()

API prototype:

void vQueueUnregisterQueue(QueueHandle_t xQueue);

  Delete a queue from the queue registry.
Parameters:
  xQueue The queue handle to delete from the registry.
  The queue registry serves two purposes, both related to RTOS kernel-aware debugging:

  • A textual name can be associated with a queue to facilitate identification of the queue in the debug GUI.
  • Contains information needed by the debugger to locate each registered queue and semaphore.

  The queue registry serves no purpose unless an RTOS kernel-aware debugger is used.
  configQUEUE_REGISTRY_SIZE defines the maximum number of queues and semaphores that can be registered. Only those queues and semaphores need to be registered that are to be viewed with an RTOS kernel-aware debugger.
Example usage:

void vAFunction( void )
{
    
    
	QueueHandle_t xQueue;
	
	/* 创建一个足够大的队列,以容纳10个字符。*/
	xQueue = xQueueCreate( 10, sizeof( char ) );
	
	/* 我们希望这个队列可以在RTOS内核感知的调试器中查看。
	所以要注册它。*/
	vQueueAddToRegistry( xQueue, "AMeaningfulName");
	
	/* 该队列在这里被使用。*/
	
	/* 在以后的某个时候,如果要删除这个队列,首先要把它从注册表中删除。
	从注册表中删除它。*/
	vQueueUnregisterQueue( xQueue );
	vQueueDelete( xQueue );
}

22, pcQueueGetName()

API prototype:

const char *pcQueueGetName( QueueHandle_t xQueue )

  Look up the queue name from the queue's handle.
  Queues only have names when they are added to the queue registry.
Parameters:
  xQueue The handle to the queue being queried.
Returns:
  If the queue referenced by xQueue is in the queue registry, it returns the textual name of the queue, otherwise it returns NULL.

23. xQueueIsQueueFullFromISR()

API prototype:

BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue );

  Queries the queue to determine if the queue is full. This function can only be used in ISR.
Parameters:
  xQueue The handle to the queue being queried.
Returns:
  pdFALSE if the queue is not full; pdTRUE if the queue is full.

24. xQueueIsQueueEmptyFromISR()

API prototype:

BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue );

  Queries the queue to determine if the queue is empty. This function can only be used in ISR.
Parameters:
  xQueue The handle of the queue being queried
Returns:
  If the queue is not empty, pdFALSE is returned; if the queue is empty, pdTRUE is returned.

25. Queue synthesis sample code

Queue Basic API

/**
 * @file 5_TaskControl.c
 * @author WSP
 * @brief 任务队列
 * @version 0.1
 * @date 2022-10-09
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_Task_Queue";

// 根据宏定义来修改测试代码中不同部分
#define USER_DATA_TYPE_POINT 1

#if USER_DATA_TYPE_INT
typedef int INT_Data;
#elif USER_DATA_TYPE_ARRAY
typedef char Array_Data[6];
#elif USER_DATA_TYPE_POINT
typedef char * Pstr_Data;
#elif USER_DATA_TYPE_STRCUT
typedef struct  Struct_Data_t
{
    
    
    int Name_Number;
    char * Name;
}Struct_Data;
#endif

/**
 * @brief APP_Task_Queue_Send
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
     BaseType_t SendState;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
#ifdef USER_DATA_TYPE_INT
        INT_Data data = 168;                                                    // 发送的数据
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);    // 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
#elif USER_DATA_TYPE_ARRAY
        Array_Data data = {
    
    1, 2, 3, 4, 99, 168};
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
#elif USER_DATA_TYPE_POINT
        Pstr_Data data = (char *) malloc(25);
        snprintf(data,25,"USER_DATA_TYPE_STRING");
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
#elif USER_DATA_TYPE_STRCUT
        Struct_Data data = {
    
    1,"WSP"};
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
#endif
    }
}
/**
 * @brief   APP_Task_Queue_Get
 * @param   NULL
 * @return  NULL
 */
void APP_Task_Queue_Get(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    int QueueDataLen = 0;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
#ifdef USER_DATA_TYPE_INT
        INT_Data data;
        QueueDataLen = uxQueueMessagesWaiting(QueueHandle);                         // 获取队列接受情况 返回队列长度    
        if(QueueDataLen != 0){
    
                                                          // 接收长度大于零的时候        
            SendState = xQueueReceive(QueueHandle, &data, 10 / portTICK_PERIOD_MS); // 获取接受状态        
            if(SendState != pdPASS)                                                 // 接受状态
                ESP_LOGI(TAG,"data send fail");
            else
                ESP_LOGI(TAG, "Int type Queue Receive DATA:%d data len :%d", data,QueueDataLen);
        }
#elif USER_DATA_TYPE_ARRAY
        Array_Data data;
        QueueDataLen = uxQueueMessagesWaiting(QueueHandle); // 返回存储在队列中的消息数。
        if(QueueDataLen != 0){
    
    
            SendState = xQueueReceive(QueueHandle, &data, 10 / portTICK_PERIOD_MS);
            if(SendState != pdPASS){
    
    
                ESP_LOGI(TAG,"data send fail");
            }else{
    
    
                for (uint8_t i = 0; i < 6; i++){
    
    
                    ESP_LOGI(TAG, "Array Type Queue Receive DATA:%d data len :%d", data[i],QueueDataLen);
                }
            }
        }
#elif USER_DATA_TYPE_POINT
        Pstr_Data data;
        QueueDataLen = uxQueueMessagesWaiting(QueueHandle);
        if(QueueDataLen != 0){
    
    
            SendState = xQueueReceive(QueueHandle, &data, 10 / portTICK_PERIOD_MS);
            if(SendState != pdPASS)
                ESP_LOGI(TAG,"data send fail");
            else
                ESP_LOGI(TAG, "Array Type Queue Receive DATA:%s data len :%d", data, QueueDataLen);
        }
#elif USER_DATA_TYPE_STRCUT
        Struct_Data data;
        QueueDataLen = uxQueueMessagesWaiting(QueueHandle);
        if(QueueDataLen != 0){
    
    
            SendState = xQueueReceive(QueueHandle, &data, 10 / portTICK_PERIOD_MS);
            if(SendState != pdPASS)
                ESP_LOGI(TAG,"data send fail");
            else
                ESP_LOGI(TAG, "Struct Type Queue Receive DATA name number:%d name:%s data len :%d", data.Name_Number,data.Name, QueueDataLen);
        }
#endif
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void Task_Queue_Init(void)
{
    
    
    TaskHandle_t APP_Task_Queue_Handle = NULL;

#ifdef USER_DATA_TYPE_INT                                           // 队列传输整型数据
    APP_Task_Queue_Handle = xQueueCreate(6, sizeof(INT_Data));      // 创建队列
#elif USER_DATA_TYPE_ARRAY                                          // 队列传输数组
    APP_Task_Queue_Handle = xQueueCreate(6, sizeof(Array_Data));    // 创建队列
#elif USER_DATA_TYPE_POINT                                          // 队列传输指针   
    APP_Task_Queue_Handle = xQueueCreate(6, sizeof(Pstr_Data));     // 创建队列
#elif USER_DATA_TYPE_STRCUT                                         // 队列传输结构体
    APP_Task_Queue_Handle = xQueueCreate(6, sizeof(Struct_Data));   // 创建队列
#endif

    if (APP_Task_Queue_Handle != NULL)
    {
    
    
        // 创建任务一
        xTaskCreate(APP_Task_Queue_Send,    // 创建任务
                    "Task_Queue_Send",      // 创建任务名
                    2048,                   // 任务堆栈
                    (void *)APP_Task_Queue_Handle,
                    3,                      // 默认3
                    NULL);                  // 任务句柄
        // 创建任务二
        xTaskCreate(APP_Task_Queue_Get,     // 创建任务
                    "Task_Queue_Get",       // 创建任务名
                    2048,                   // 任务堆栈
                    (void *)APP_Task_Queue_Handle,
                    2,                      // 默认3
                    NULL);                  // 任务句柄
        ESP_LOGI(TAG, "Task create ok");
    }
    else
    {
    
    
        ESP_LOGI(TAG, "Task create fail");
    }
    vTaskDelay(3000 / portTICK_PERIOD_MS); // 延时等待
}

Queue's multi-input and one-out multiple channels enter one channel output

/**
 * @file 8_TaskQueue_More_Input_One_Output.c
 * @author WSP
 * @brief 队列的多进一出 多个通道进入一个通道输出
 * @version 0.1
 * @date 2022-10-18
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_TaskQueue_More_Input_One_Output";



/**
 * @brief APP_Task_Queue_Send_One
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send_One(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
     BaseType_t SendState;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        int data = 99;                                                    // 发送的数据
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);    // 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
    }
}
/**
 * @brief APP_Task_Queue_Send_Two
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send_Two(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
     BaseType_t SendState;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        int data = 168;                                                    // 发送的数据
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);    // 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
    }
}
/**
 * @brief APP_Task_Queue_Send_Three
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send_Three(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
     BaseType_t SendState;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        int data = 1688;                                                    // 发送的数据
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);    // 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
    }
}
/**
 * @brief   APP_Task_Queue_Get
 * @param   NULL
 * @return  NULL
 */
void APP_Task_Queue_Get(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    int data = 0;
    while (1)
    {
    
      
        SendState = xQueueReceive(QueueHandle, &data, portMAX_DELAY); // 获取接受状态        
        if(SendState != pdPASS)                                                 // 接受状态
            ESP_LOGI(TAG,"data send fail");
        else
            ESP_LOGI(TAG, "Int type Queue Receive DATA:%d", data);
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void TaskQueue_More_Input_One_Output_Init(void)
{
    
    
    TaskHandle_t APP_Task_Queue_Handle = NULL;
    APP_Task_Queue_Handle = xQueueCreate(6, sizeof(int));
    if (APP_Task_Queue_Handle != NULL)
    {
    
    
        // 创建任务一
        xTaskCreate(APP_Task_Queue_Send_One,    // 创建任务
                    "Task_Queue_Send1",         // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)APP_Task_Queue_Handle,
                    1,     // 默认1
                    NULL); // 任务句柄
        // 创建任务二
        xTaskCreate(APP_Task_Queue_Send_Two,    // 创建任务
                    "Task_Queue_Send2",         // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)APP_Task_Queue_Handle,
                    2,     // 默认2
                    NULL); // 任务句柄
        // 创建任务三
        xTaskCreate(APP_Task_Queue_Send_Three,  // 创建任务
                    "Task_Queue_Send3",         // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)APP_Task_Queue_Handle,
                    3,     // 默认3
                    NULL); // 任务句柄
        // 创建任务四
        xTaskCreate(APP_Task_Queue_Get, // 创建任务
                    "Task_Queue_Get",   // 创建任务名
                    2048,               // 任务堆栈
                    (void *)APP_Task_Queue_Handle,
                    4,     // 默认4
                    NULL); // 任务句柄
        ESP_LOGI(TAG, "Task create ok");
    }
    else
    {
    
    
        ESP_LOGI(TAG, "Task create fail");
    }
    vTaskDelay(3000 / portTICK_PERIOD_MS); // 延时等待
}

queue mailbox

/**
 * @file 10_TaskQueue_Mail.c
 * @author WSP
 * @brief 队列的邮箱 一个队列发送多个队列接受但是不会清空发送队列中的数值,只有发送队列才可以清空或者覆写队列邮箱的数值
 * @version 0.1
 * @date 2022-10-18
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_TaskQueue_Mail";

/**
 * @brief APP_Task_Queue_Send
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send(void *arg)
{
    
    
    QueueHandle_t QueueMailbox = (QueueHandle_t)arg;
    BaseType_t SendState;
    int data = 99;                                      // 发送的数据
    while (1)
    {
    
    
        vTaskDelay(3000 / portTICK_PERIOD_MS);
        SendState = xQueueOverwrite(QueueMailbox, &data);   // 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
        data ++;
        if(data >= 168)
            data = 0;
    }
}
/**
 * @brief   APP_Task_Queue_Get_One
 * @param   NULL
 * @return  NULL
 */
void APP_Task_Queue_Get_One(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    int data = 0;
    while (1)
    {
    
                                                            
        SendState = xQueuePeek(QueueHandle, &data, portMAX_DELAY);  // 获取接受状态  
        if(SendState == pdPASS)      
            ESP_LOGI(TAG, "APP_Task_Queue_Get_One:%d", data);  
        vTaskDelay(3000 / portTICK_PERIOD_MS);                      // 延时等待
    }
}
/**
 * @brief   APP_Task_Queue_Get_Two
 * @param   NULL
 * @return  NULL
 */
void APP_Task_Queue_Get_Two(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    int data = 0;
    while (1)
    {
    
                                                            
        SendState = xQueuePeek(QueueHandle, &data, portMAX_DELAY);  // 获取接受状态
        if(SendState == pdPASS)      
            ESP_LOGI(TAG, "APP_Task_Queue_Get_Two:%d", data);  
        vTaskDelay(3000 / portTICK_PERIOD_MS);                      // 延时等待
    }
}
/**
 * @brief   APP_Task_Queue_Get_Three
 * @param   NULL
 * @return  NULL
 */
void APP_Task_Queue_Get_Three(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    int data = 0;
    while (1)
    {
    
                                                            
        SendState = xQueuePeek(QueueHandle, &data, portMAX_DELAY);  // 获取接受状态
        if(SendState == pdPASS)      
            ESP_LOGI(TAG, "APP_Task_Queue_Get_Three:%d", data);  
        vTaskDelay(3000 / portTICK_PERIOD_MS);                      // 延时等待
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void TaskQueue_Mail_Init(void)
{
    
    
    QueueHandle_t Mailbox_Handle = NULL;
    Mailbox_Handle = xQueueCreate(1, sizeof(int));      // 创建队列一
    if (Mailbox_Handle != NULL)
    {
    
    
        // 创建任务接收任务一
        xTaskCreate(APP_Task_Queue_Send,        // 创建任务
                    "Task_Queue_Send",          // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)Mailbox_Handle,
                    1,                          // 默认1
                    NULL);                      // 任务句柄
        // 创建任务接收任务二
        xTaskCreate(APP_Task_Queue_Get_One,     // 创建任务
                    "Task_Queue_Get1",          // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)Mailbox_Handle,
                    2,                          // 默认2
                    NULL);                      // 任务句柄
        // 创建任务接收任务三
        xTaskCreate(APP_Task_Queue_Get_Three,   // 创建任务
                    "Task_Queue_Get3",          // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)Mailbox_Handle,
                    2,                          // 默认2
                    NULL);                      // 任务句柄
        // 创建任务接收任务一       
        xTaskCreate(APP_Task_Queue_Get_Two,     // 创建任务
                    "Task_Queue_Get2",          // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)Mailbox_Handle,
                    3,                          // 默认4
                    NULL);                      // 任务句柄
        ESP_LOGI(TAG, "Task create ok");
    }
    else
    {
    
    
        ESP_LOGI(TAG, "Task create fail");
    }
    vTaskDelay(3000 / portTICK_PERIOD_MS); // 延时等待
}

26. Queue set

1、xQueueCreateSet()

API prototype:

QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength);

  configUSE_QUEUE_SETS must be set to 1 in FreeRTOSConfig.h for the xQueueCreateSet() API function to be available.
  Queue sets provide a mechanism that allows an RTOS task to block (suspend) after reading from multiple RTOS queues or semaphores simultaneously. Note that there are simpler alternatives to using queue sets. See the Blocking Multiple Objects page for details.
  A queue set must be explicitly created with a call to xQueueCreateSet() before it can be used. Once created, standard FreeRTOS queues and semaphores can be added to the set (by calling xQueueAddToSet()). Then, use xQueueSelectFromSet() to determine which, if any, of the queues or semaphores contained in the set are in a state in which a queue read or semaphore acquire operation will succeed.
Notice:

  • Queues and semaphores must be empty when added to a queue set. Be especially careful when adding objects, such as binary semaphores created using already available semaphores [this is the case if the semaphore was created using the vSemaphoreCreateBinary() macro, but not if the semaphore was created using the preferred xSemaphoreCreateBinary() function , this is not the case].
  • Blocking a queue set containing a mutex does not cause the mutex holder to inherit the priority of the blocked task.
  • Each slot in each queue added to the queue set requires an additional 4 bytes of RAM. Therefore, counting semaphores with higher maximum count values ​​should not be added to the queue set.
  • A receive (if a queue) or get (if a semaphore) operation must not be performed on a member of a queue set unless a call to xQueueSelectFromSet() first returns a handle to the queue set member.

Parameters:
  uxEventQueueLength The queue set stores events occurring on the queues and semaphores contained in the set. uxEventQueueLength specifies the maximum number of events that can be queued at one time.
To be absolutely sure that events will not be lost, uxEventQueueLength must be set to the sum of the lengths of the queues added to the set, where binary semaphores and mutexes have length 1, and counting semaphores have a length set by their maximum count value. For example:

  • If the queue set is to hold a queue of length 5, another queue of length 12, and a binary semaphore, then uxEventQueueLength should be set to (5 + 12 + 1) or 18.
  • uxEventQueueLength should be set to (1 + 1 + 1) or 3 if the queue set is to hold three binary semaphores.
  • If the queue set is to hold a count semaphore with a maximum count of 5 and a count semaphore with a maximum count of 3, then uxEventQueueLength should be set to (5 + 3) or 8.

Returns:
  If the queue set is created successfully, the handle of the created queue set is returned. Otherwise return NULL.

/* 定义将添加到队列集中的队列的长度。*/
#define QUEUE_LENGTH_1 10
#define QUEUE_LENGTH_2 10

/* 二进制信号量的有效长度为 1。 */
#define BINARY_SEMAPHORE_LENGTH 1

/* 分别定义队列1和队列2要持有的item的大小。
此处使用的值仅用于演示目的。*/
#define ITEM_SIZE_QUEUE_1 sizeof(uint32_t)
#define ITEM_SIZE_QUEUE_2 sizeof(something_else_t)

/* 两个队列和二进制信号量的组合长度
添加到队列集。*/
#define COMBINED_LENGTH ( QUEUE_LENGTH_1 +
                          QUEUE_LENGTH_2 +
                          BINARY_SEMAPHORE_LENGTH )

void vAFunction(无效)
{
    
    
静态 QueueSetHandle_t xQueueSet;
QueueHandle_t xQueue1,xQueue2,xSemaphore;
QueueSetMemberHandle_t xActivatedMember;
uint32_t xReceivedFromQueue1;
something_else_t xReceivedFromQueue2;

    /* 创建足够大的队列集来为每个空间保存一个事件
    要添加到集合中的每个队列和信号量。*/
    xQueueSet = xQueueCreateSet( COMBINED_LENGTH );

    /* 创建将包含在集合中的队列和信号量。*/
    xQueue1 = xQueueCreate( QUEUE_LENGTH_1, ITEM_SIZE_QUEUE_1 );
    xQueue2 = xQueueCreate( QUEUE_LENGTH_2, ITEM_SIZE_QUEUE_2 );

    /* 创建要添加到集合中的信号量。*/
    xSemaphore = xSemaphoreCreateBinary();

    /* 检查所有内容都已创建。*/
    configASSERT( xQueueSet );
    配置断言(xQueue1);
    配置断言(xQueue2);
    configASSERT( xSemaphore );

    /* 将队列和信号量添加到集合中。从这些队列中读取和
    只能在调用 xQueueSelectFromSet() 后执行信号量
    从此时起返回队列或信号量句柄。*/
    xQueueAddToSet( xQueue1, xQueueSet );
    xQueueAddToSet( xQueue2, xQueueSet );
    xQueueAddToSet( xSemaphore, xQueueSet );

    为了( ;;{
    
    
        /* 阻塞以等待队列中可用的东西或
        已添加到集合中的信号量。不要阻塞超过
        200 毫秒。*/
        xActivatedMember = xQueueSelectFromSet( xQueueSet,
                                                200 / 端口TICK_PERIOD_MS );

        /* 选择了哪个集合成员?接收/获取可以使用块时间
        为零,因为它们保证通过,因为 xQueueSelectFromSet()
        除非有可用的东西,否则不会返回句柄。*/
        如果(xActivatedMember == xQueue1)
        {
    
    
            xQueueReceive( xActivatedMember, &xReceivedFromQueue1, 0 );
            vProcessValueFromQueue1( xReceivedFromQueue1 );
        }
        否则如果(xActivatedMember == xQueue2)
        {
    
    
            xQueueReceive( xActivatedMember, &xReceivedFromQueue2, 0 );
            vProcessValueFromQueue2( &xReceivedFromQueue2 );
        }
        否则如果(xActivatedMember == xSemaphore)
        {
    
    
            /* 获取信号量以确保它可以再次“给定”。*/
            xSemaphoreTake( xActivatedMember, 0 );
            vProcessEventNotifiedBySemaphore();
            休息;
        }
        别的
        {
    
    
            /* 200 毫秒的块时间在没有 RTOS 队列或信号量的情况下到期
            准备好处理。*/
        }
    }
}

2、xQueueAddToSet()

API prototype:

BaseType_t xQueueAddToSet
                     (
                         QueueSetMemberHandle_t xQueueOrSemaphore,
                         QueueSetHandle_t xQueueSet
                     );

  configUSE_QUEUE_SETS must be set to 1 in FreeRTOSConfig.h for the xQueueAddToSet () API function to be available.
  Adds an RTOS queue or semaphore to the queue set previously created by the xQueueCreateSet() call.
  A receive (if a queue) or get (if a semaphore) operation, unless a call to xQueueSelectFromSet() first returns a handle to a queue set member.
Parameters:
  xQueueOrSemaphore The handle (converted to type QueueSetMemberHandle_t) of the queue or semaphore being added to the queue set.
  xQueueSet The queue set handle to which the queue or semaphore is being added.
Returns:
  pdPASS if the queue or semaphore was successfully added to the queue set. Returns pdFAIL if the queue could not be successfully added to the queue set because it is already a member of another queue set.
Usage example:
  see the example on the xQueueCreateSet() documentation page.

3、xQueueRemoveFromSet()

API prototype:

BaseType_t xQueueRemoveFromSet
                     (
                         QueueSetMemberHandle_t xQueueOrSemaphore,
                         QueueSetHandle_t xQueueSet
                     );

  configUSE_QUEUE_SETS must be set to 1 in FreeRTOSConfig.h for the xQueueRemoveFromSet() API function to be available.
  Removes an RTOS queue or semaphore from the queue set.
  An RTOS queue or semaphore can be removed from the queue set only if the queue or semaphore is empty.
Parameters:
  xQueueOrSemaphore The handle (converted to QueueSetMemberHandle_t type) of the queue or semaphore to remove from the queue set.
  xQueueSet A handle to a queue set containing queues or semaphores.
Returns:
  pdPASS if the queue or semaphore was successfully removed from the queue set. Returns pdFAIL if the queue is not in the queue set, or if the queue (or semaphore) is not empty.
Example usage:
  This example assumes that xQueueSet is the created queue set and xQueue is the queue that was created and added to xQueueSet.

4、xQueueSelectFromSet()

API prototype:

QueueSetMemberHandle_t xQueueSelectFromSet
                      (
                            QueueSetHandle_t xQueueSet,
                            const TickType_t xTicksToWait
                       );

  configUSE_QUEUE_SETS must be set to 1 in FreeRTOSConfig.h to use the xQueueSelectFromSet() API function.
  xQueueSelectFromSet() Selects a queue or semaphore from among the members of the queue set that either contains data (if a queue is selected) or is available for acquisition (if a semaphore is selected). xQueueSelectFromSet() effectively allows tasks to block (suspend) after reading all queues and semaphores in a queue set at the same time.
Note:
  You can also use a simpler alternative instead of using queue sets. See the Blocking Multiple Objects page for details.
  Blocking a queue containing a mutex does not cause the mutex holder to inherit the priority of the blocked task.
Unless xQueueSelectFromSet() (semaphore) operation, unless calling xQueueSelectFromSet() first returns the handle of the queue set member.
Parameters:
  xQueueSet The set of queues on which the task (possibly) blocks.
  xTicksToWait The maximum time, in ticks, required for the calling task to remain blocked (other tasks are executing) waiting for a queue set member to become ready in order to successfully read the queue or acquire a semaphore.
Returns:
  xQueueSelectFromSet() will return the handle (converted to type QueueSetMemberHandle_t) of the queue containing the data in the queue set or the handle to the semaphore (converted to type QueueSetMemberHandle_t) available in the queue set, if no such queue exists before the specified blocking time expires or semaphore, returns NULL.

5. Example of use

/**
 * @file 8_TaskQueue_Set.c
 * @author WSP
 * @brief 队列集合队列
 * @version 0.1
 * @date 2022-10-18
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_TaskQueue_Set";

TaskHandle_t APP_Task_Queue_Send_One_Handle = NULL,APP_Task_Queue_Send_Two_Handle = NULL;

/**
 * @brief APP_Task_Queue_Send_One
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send_One(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        int data = 99;                                                          // 发送的数据
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);    // 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
    }
}
/**
 * @brief APP_Task_Queue_Send_Two
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_Task_Queue_Send_Two(void *arg)
{
    
    
    QueueHandle_t QueueHandle = (QueueHandle_t)arg;
    BaseType_t SendState;
    while (1)
    {
    
    
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        char * data = (char *) malloc(25);
        snprintf(data,25,"My name is WSP");                                 // 发送的数据
        SendState = xQueueSend(QueueHandle, &data, 10 / portTICK_PERIOD_MS);// 发送队列
        if(SendState != pdPASS)
            ESP_LOGI(TAG,"data send fail");
    }
}
/**
 * @brief   APP_Task_Queue_Get
 * @param   NULL
 * @return  NULL
 */
void APP_Task_Queue_Get(void *arg)
{
    
    
    QueueSetHandle_t QueueSetHandle = (QueueSetHandle_t)arg;
    QueueSetMemberHandle_t QueueSetMemberHandle;
    BaseType_t SendState;
    while (1)
    {
    
      
        QueueSetMemberHandle = xQueueSelectFromSet(QueueSetHandle,portMAX_DELAY);   // 获取队列集合
        if(QueueSetMemberHandle == APP_Task_Queue_Send_One_Handle){
    
                     // 对队列集合的句柄判断
            int data = 0;                                                           // 设置接受变量
            SendState = xQueueReceive(QueueSetMemberHandle, &data, portMAX_DELAY);  // 获取接受状态  
            if(SendState == pdPASS)      
                ESP_LOGI(TAG, "APP_Task_Queue_Send_One_Handle Send DATA:%d", data);  
        }else if(QueueSetMemberHandle == APP_Task_Queue_Send_Two_Handle){
    
               // 对队列集合的句柄判断
            char * Pstr = NULL;                                                     // 设置接受变量
            SendState = xQueueReceive(QueueSetMemberHandle, &Pstr, portMAX_DELAY);  // 获取接受状态   
            if(SendState == pdPASS)      
                ESP_LOGI(TAG, "APP_Task_Queue_Send_Two_Handle Send DATA:%s", Pstr);  
        }    
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void TaskQueue_Set_Init(void)
{
    
    
    APP_Task_Queue_Send_One_Handle = xQueueCreate(6, sizeof(int));      // 创建队列一
    APP_Task_Queue_Send_Two_Handle = xQueueCreate(6, sizeof(char *));   // 创建队列二
    QueueSetHandle_t QueueSetHandle = NULL;                             // 创建队列集合句柄
    QueueSetHandle = xQueueCreateSet(6 + 6);                            // 创建队列集合 长度为 队列一 + 队列二
    xQueueAddToSet(APP_Task_Queue_Send_One_Handle,QueueSetHandle);      // 将队列加入队列集合
    xQueueAddToSet(APP_Task_Queue_Send_Two_Handle,QueueSetHandle);      // 将队列加入队列集合
    if (APP_Task_Queue_Send_One_Handle != NULL && APP_Task_Queue_Send_Two_Handle != NULL && QueueSetHandle != NULL)
    {
    
    
        // 创建任务发送任务一
        xTaskCreate(APP_Task_Queue_Send_One,    // 创建任务
                    "Task_Queue_Send1",         // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)APP_Task_Queue_Send_One_Handle,
                    1,                          // 默认1
                    NULL);                      // 任务句柄
        // 创建任务发送任务二
        xTaskCreate(APP_Task_Queue_Send_Two,    // 创建任务
                    "Task_Queue_Send2",         // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)APP_Task_Queue_Send_Two_Handle,
                    2,                          // 默认2
                    NULL);                      // 任务句柄
        // 创建任务接收任务一       
        xTaskCreate(APP_Task_Queue_Get,         // 创建任务
                    "Task_Queue_Get",           // 创建任务名
                    2048,                       // 任务堆栈
                    (void *)QueueSetHandle,
                    4,                          // 默认4
                    NULL);                      // 任务句柄
        ESP_LOGI(TAG, "Task create ok");
    }
    else
    {
    
    
        ESP_LOGI(TAG, "Task create fail");
    }
    vTaskDelay(3000 / portTICK_PERIOD_MS); // 延时等待
}

Guess you like

Origin blog.csdn.net/believe666/article/details/127205558