FreeRTOS Queue Usage Example
This article aims to demonstrate the usage of queues in FreeRTOS.
According to the description in this article, a simple usage of queues can be implemented.
Experimental conditions: Basic knowledge of C language, with an integrated development environment such as Keil uVision5.
Design Experiment
In this experiment, we will continue to use the project files from the previous article, modifying the input data obtained from the remote control to be implemented using queues.
Creating a Queue
Function prototype
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );
Function Description:
The function xQueueCreate is used to create a queue.
The first parameter uxQueueLength is the number of messages the queue can support, indicating the maximum number of items that can be stored.
The second parameter uxItemSize is the size of each message in bytes.
Return value: Non-zero indicates success, returning a handle to operate the queue later; NULL indicates failure due to insufficient memory.
Writing to the Queue
Function prototype
BaseType_t xQueueSend( QueueHandle_t xQueue, /* Queue handle */ const void * pvItemToQueue, /* Address of the data to be sent */ TickType_t xTicksToWait /* Maximum wait time for the queue to have space */ );
Function Description:
The first parameter xQueue is the queue handle.
The second parameter pvItemToQueue is the address of the data to be sent. Each time data is sent, a single message specified by the xQueueCreate function will be copied into the queue space.
The third parameter xTicksToWait is the maximum wait time for the queue to have space when it is full, measured in system clock ticks. If set to 0, the function will return immediately when unable to write data; if set to portMAX_DELAY, it will block until space is available.
Return value: if the message is successfully sent, returns pdPASS; if it fails, returns errQUEUE_FULL.
Points to note when using this function:
-
Message passing in FreeRTOS involves copying data, not passing the address of the data.
-
This function should be called in task code, and should not be called in interrupt service routines; use xQueueSendFromISR in interrupt service routines.
-
If the queue is full and the third parameter is 0, the function will return immediately.
-
If the user sets the macro definition INCLUDE_vTaskSuspend in the FreeRTOSConfig.h file to 1 and the third parameter to portMAX_DELAY, this sending function will wait indefinitely until space becomes available in the queue.
-
There are also two functions xQueueSendToBack and xQueueSendToFront; the function xQueueSendToBack implements FIFO access, while xQueueSendToFront implements LIFO read/write. The function xQueueSend we are discussing is equivalent to xQueueSendToBack, implementing FIFO access.
Reading from the Queue
Function prototype
BaseType_t xQueueReceive( QueueHandle_t xQueue, /* Queue handle */ void *pvBuffer, /* Buffer address for receiving queue data */ TickType_t xTicksToWait /* Maximum wait time for the queue to have data */ );
Function Description:
The first parameter xQueue is the queue handle.
The second parameter pvBuffer is the address where the data will be copied. The buffer pointer will receive the data copied from the queue; the size of the buffer must be at least equal to the size of a single message specified when creating the queue, or there may be a memory overflow.
The third parameter xTicksToWait is the maximum wait time for the queue to have data when it is empty, measured in system clock ticks.
Example Code Snippet for This Experiment
In this project, the data is obtained via an interrupt, and the queue is written with the following code:
// Called in the interrupt code /* Write to queue */ idata.dev = datas[0]; idata.val = datas[2]; xQueueSendFromISR(g_xQueuePlatform, &idata, NULL);
In the task, the following code is used to read from the queue:
xQueueReceive(g_xQueuePlatform, &idata, portMAX_DELAY);
In the game1_task code snippet:
void game1_task(void *params){ uint8_t dev, data, last_data; struct input_data idata; g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp); draw_init(); draw_end(); /* Create queue */ g_xQueuePlatform = xQueueCreate(10, sizeof(struct input_data));// g_xQueueKey = xQueueCreate(10, sizeof(struct key_data));//// /* Create a key task to get data */// xTaskCreate(KeyTask, "KeyTask", 128, NULL, osPriorityNormal, NULL); uptMove = UPT_MOVE_NONE;
ball.x = g_xres / 2; ball.y = g_yres - 10; ball.velX = -0.5; ball.velY = -0.6;// ball.velX = -1;// ball.velY = -1.1;
blocks = pvPortMalloc(BLOCK_COUNT); memset(blocks, 0, BLOCK_COUNT); lives = lives_origin = 3; score = 0; platformX = (g_xres / 2) - (PLATFORM_WIDTH / 2); // Create a paddle task// xTaskCreate(platform_task, "platform_task", 128, NULL, osPriorityNormal, NULL);
game1_draw(); LCD_Flush(); while (1) { /* Read from infrared remote control */// if (0 == IRReceiver_Read(&dev, &data)) xQueueReceive(g_xQueuePlatform, &idata, portMAX_DELAY); data = idata.val; { if (data == 0x00) { data = last_data; } if (data == 0xe0) /* Left */ { btnLeft(); }
if (data == 0x90) /* Right */ { btnRight(); } last_data = data; } game1_draw(); draw_end(); vTaskDelay(50); }}
Experimental Results
Using the above code for testing on my hardware, when I press the left button on the remote control, the paddle moves left, and when I press the right button, the paddle moves right, successfully demonstrating the use of queues for reading and writing in this demo.
