[FreeRTOS] Message Queue - Introduction, Common API Functions, Precautions, Project Implementation

In embedded system development, communication between tasks is a very common requirement. FreeRTOS provides a variety of communication mechanisms between tasks, one of which is message queue. Message queues are a very flexible and efficient way to pass data between different tasks. Through message queues, tasks can send and receive messages asynchronously, thereby realizing data exchange and collaboration between tasks.

In this blog post, we will delve into the use of message queues in FreeRTOS, including how to create and initialize message queues, and how to send and receive messages in tasks. We will also discuss the characteristics and limitations of message queues and provide some practical example code to help readers better understand how message queues work and how to use them. Through this blog post, readers will be able to master the techniques and methods of effectively using message queues for inter-task communication in FreeRTOS.



1. Introduction to message queue

Queue, also known asMessage queue, is a type of communication commonly used forinter-task communication 'sdata structure, the queue can be betweentask and task, Transfer information between interrupts and tasks , enabling tasks to receive messages of variable length from other tasks or interrupts.


1.1 Features

FreeRTOS uses the queue data structure to implement task asynchronous communication, which has the followingcharacteristics:

  • Messages support first-in-first-out queuing and asynchronous reading and writing.
  • Both read and write queues support timeout mechanisms.
  • Messages support last-in-first-out queuing, and messages are sent to the head of the queue (LIFO).
  • Any type of message of varying lengths (up to the queue node maximum) can be allowed.
  • A task can receive and send messages from any message queue.
  • Multiple tasks can receive and send messages from the same message queue.
  • When the queue is finished using, it can be deleted through the delete queue function.

1.2 Message queue data storage

Usually the queue adopts the storage buffering mechanism offirst in, first out (FIFO). LIFO storage buffering can also be used, that is. LIFO

Sending data to the queue will result in data copying, that is, copying the data to be sent to the queue, which means that the original value of the data is stored in the queue, rather than a reference to the original data (that is, only the pointer of the data is passed) , this is also called value transfer.


1.3 Dequeue blocking

When a task attempts to read a message from a queue, a blocking time can be specified. This blocking time is the time the task blocks when the task fails to read a message from the queue.


1.4 Queue blocking

Joining the queue means sending a message to the queue and adding the message to the queue. Like dequeue blocking, the blocking time can also be set when a task sends a message to the queue.


1.5 Message queue operation diagram

(1) Create a queue

Insert image description here

(2) Send the first message to the queue

Insert image description here

(3) Send the second message to the queue
Insert image description here

(4) Read messages from the queue

Insert image description here


1.6 Message queue control block

Insert image description here
Insert image description here
Insert image description here


2. Commonly used message queue API functions

2.1 Message queue creation functionxQueueCreate()

Insert image description here


2.2 Message queue static creation functionxQueueCreateStatic()

Insert image description here


2.3 Message queue deletion functionvQueueDelete()

  • Prototype:void vQueueDelete(QueueHandle_t xQueue)
  • Function: Delete a queue and release related resources
  • Parameter: xQueue is the queue handle to be deleted
  • Reply:No

2.4 Send message function to message queue

2.4.1 xQueueSend()givenxQueueSendToBack()

Insert image description here
Insert image description here


2.4.2 xQueueSendFromISR()given xQueueSendToBackFromISR()

Insert image description here
Insert image description here


2.4.3 xQueueSendToFront()

Insert image description here
Insert image description here


2.4.4 xQueueSendToFrontFromISR()

Insert image description here
Insert image description here


2.4.5 xQueueGenericSend()
  • Prototype:
BaseType_t xQueueGenericSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition)
  • Function: Send data to queue

  • number of references :

    • xQueue:Queue handle to send data
    • pvItemToQueue: Pointer to the data to be sent
    • xTicksToWait: Timeout when sending data
    • xCopyPosition:Specify the location of data copy
  • Return value:
    If the data is successfully sent to the queue, return pdPASS; if the queue is full and If timeout occurs, errQUEUE_FULL will be returned; in other error conditions, errQUEUE_FULL will be returned.


2.4.6 xQueueGenericSendFromISR()
  • Prototype:
BaseType_t xQueueGenericSendFromISR(QueueHandle_t xQueue, const void * pvItemToQueue, BaseType_t * pxHigherPriorityTaskWoken, BaseType_t xCopyPosition)
  • Function: Send data to queue from ISR

  • number of references :

    • xQueue:Queue handle to send data
    • pvItemToQueue: Pointer to the data to be sent
    • pxHigherPriorityTaskWoken: Pointer to a variable used to indicate whether there is a higher priority task that needs to be executed immediately
    • xCopyPosition:Specify the location of data copy
  • Return value: If the data is successfully sent to the queue, return pdPASS; if the queue is full, return errQUEUE_FULL;Other error conditions returnerrQUEUE_FULL.


2.5 Read message function from message queue

2.5.1 xQueueReceive()givenxQueuePeek()

Insert image description here
Insert image description here
Insert image description here


2.5.2 xQueueReceiveFromISR()given xQueuePeekFromISR()

Insert image description here

Insert image description here


3. Things to note when using message queues

  1. Before using these functions such asxQueueSend(), xQueueSendFromISR(), xQueueReceive(), you should first create the required message queue and use the queue handle Perform operations.
  2. Queue reading uses a first-in, first-out (FIFO) mode, and the data stored in the queue is read first. Of course, FreeRTOS also supports the last-in-first-out (LIFO) mode, so the data in the last-in queue will be read when reading.
  3. When getting the message in the queue, we must define a place to store the read data, and the size of the data area is not less than the message size. Otherwise, an illegal address error is likely to occur.
  4. Whether messages are sent or received, they are all copied. If the message is too large, the address of the message can be sent and received as a message.
  5. A queue is a kernel object with its own independent permissions and does not belong to any task. All tasks can write to and read from the same queue. It is common for a queue to be written by multiple tasks or interrupts, but it is less common to be read by multiple tasks.

4. Sample project

stm32 sample code:

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "stm32f4xx.h"

#define QUEUE_LENGTH 5
#define ITEM_SIZE sizeof(int)

QueueHandle_t xQueue;

void vSenderTask(void *pvParameters) {
    
    
    int xData = 100;
    while (1) {
    
    
        xQueueSend(xQueue, &xData, portMAX_DELAY);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void vReceiverTask(void *pvParameters) {
    
    
    int xReceivedData;
    while (1) {
    
    
        xQueueReceive(xQueue, &xReceivedData, portMAX_DELAY);
        // 处理接收到的数据
    }
}

int main() {
    
    
    xQueue = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE);

    xTaskCreate(vSenderTask, "Sender", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(vReceiverTask, "Receiver", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

    vTaskStartScheduler();

    while (1) {
    
    
        // 该处不会被执行
    }
}

Project explanation:

In this example, we first create a queuexQueue with a length of 5 and each item of size oneint. Then we created two tasks: vSenderTask and vReceiverTask. vSenderTaskThe task sends data to the queue, and vReceiverTaskThe task receives data from the queue.

In thevSenderTask task, we use thexQueueSend() function to send data to the queue. In the vReceiverTasktask, we use the xQueueReceive() function to receive data from the queue and can process the received data in the task. Both tasks have an infinite loop so they will run forever.

Inmain function, we create two tasks and start the FreeRTOS scheduler. Once the scheduler is started, the tasks will start executing their functions.

Guess you like

Origin blog.csdn.net/Goforyouqp/article/details/134810202