FreeRTOS Queue

Queues are used for data communication between tasks. The queue is similar to a sized FIFO buffer. Basically it is FIFO, but it is also possible to overwrite data in the first buffer.

Also, the queue can be written and read by multiple tasks.

Here is a simple example using a queue.


#include <Arduino.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
 
QueueHandle_t queue1;
void sender_task(void *pvParameters);
 
 
void setup(){
  Serial.begin(9600);
  delay(3000); // wait for display serial monitor
   
  queue1 = xQueueCreate(1, sizeof(uint32_t));
  xTaskCreate(sender_task, "SENDER", 512, NULL, 4, NULL );
}
 
void loop(){
  uint32_t buf;
  xQueueReceive(queue1, &buf, 0);
  Serial.println(buf);
  delay(1000);
}
 
void sender_task(void *pvParameters){
  uint32_t count = 0;
  while(1){
    xQueueSend(queue1, &count, 0);
    count++;
    delay(100);
  }
}

Output result:
0
11
21
31
41

In the sample, at first the function "setup" creates a queue "queue1" with a length of 1. The length is 1, but it's actually a 4-byte queue that is uint32_t in size. After that, the task "sender_task" is created and sends count value to the queue incrementing at intervals of 100ms. Data is read from the queue and displayed every second in the loop.

As the output result, 0 is output for the initial count value. This means that the queue will not be overwritten and will hold until xQueueReceive is done in the loop.

Note that xQueueSend and xQueueReceive can be set to wait for a certain period of time until the queue is empty or data arrives, depending on the value of the third argument.

Replacing xQueueSend with xQueueOverwrite will overwrite the data in the queue. For example, when constantly updating sensor values, it is not necessary to think about the receive side of the queue.


xQueueOverwrite(queue1, &count);

Output result:
10
20
30
40

When using xQueueOverwrite, you can see that the latest count value is written to the queue, as shown in the output.

Finally, an example of displaying acceleration, angular velocity and temperature from the acceleration sensor MPU 6050 is shown. The point is that the data handled by the queue is of type struct Data_t. In addition, the task of reading the sensor and the task of displaying the value are separated, so it is easy to replace, for example, the task of displaying the value with the task of performing motor control.


#include <Arduino.h>
#include <Wire.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
 
void taskSensing(void *pvParameters);
void taskShowData(void *pvParameters);
QueueHandle_t xQueue;
 
#define MPU6050_ADDR     0x68
#define MPU6050_AX_ADDR  0x3B
#define MPU6050_READ_NUM 14
typedef struct
{
  float ax; float ay; float az;
  float gx; float gy; float gz;
  float tp;
} Data_t;
 
TaskHandle_t periodicHandle = NULL;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
 
  xQueue = xQueueCreate(5, sizeof(Data_t));
  xTaskCreate(taskSensing, "taskSensing", 512, NULL, 1, NULL);
  xTaskCreate(taskShowData, "taskShowData", 512, NULL, 1, NULL);
}
 
void loop() {
  // put your main code here, to run repeatedly:
  delay(1);
}
 
void taskSensing(void *pvParameters){
  Wire.begin();
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);
 
  while(1){
    Data_t data;
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(MPU6050_AX_ADDR);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU6050_ADDR, MPU6050_READ_NUM, true);
    int16_t ax=Wire.read()<<8 | Wire.read();
    int16_t ay=Wire.read()<<8 | Wire.read();
    int16_t az=Wire.read()<<8 | Wire.read();
    int16_t tp=Wire.read()<<8 | Wire.read();
    int16_t gx=Wire.read()<<8 | Wire.read();
    int16_t gy=Wire.read()<<8 | Wire.read();
    int16_t gz=Wire.read()<<8 | Wire.read();
 
    data.tp = ((float)tp + 12412.0) / 340.0;
    data.ax = ax / 16384.0;
    data.ay = ay / 16384.0;
    data.az = az / 16384.0;
    data.gx = gx / 131.0;
    data.gy = gy / 131.0;
    data.gz = gz / 131.0;
 
    if(xQueueSend(xQueue, &data, 0) != pdPASS){
      Serial.println("no queue space.");
    }
    delay(100);
  }
}
 
void taskShowData(void *pvParameters){
  while(1){
    Data_t data;
    if(xQueueReceive(xQueue, &data, 0) == pdPASS){
      Serial.print(" ax= "); Serial.print(data.ax); 
      Serial.print(" ay= "); Serial.print(data.ay);
      Serial.print(" az= "); Serial.print(data.az);
      Serial.print(" gx= "); Serial.print(data.gx);
      Serial.print(" gy= "); Serial.print(data.gy);
      Serial.print(" gz= "); Serial.print(data.gz);
      Serial.print(" temp= "); Serial.print(data.tp);
      Serial.println();
    } 
    else {
      // no queue
    }
    delay(10);
  }
}

Output result:
 ax= 0.04 ay= 0.01 az= 1.00 gx= -0.69 gy= 1.23 gz= 0.01 temp= 27.38
 ax= 0.04 ay= 0.01 az= 1.01 gx= -0.69 gy= 1.31 gz= -0.06 temp= 27.52
 ax= 0.04 ay= 0.01 az= 1.01 gx= -0.73 gy= 1.21 gz= 0.02 temp= 27.42
 ax= 0.04 ay= 0.01 az= 1.01 gx= -0.76 gy= 1.31 gz= -0.02 temp= 27.42
 ax= 0.04 ay= 0.01 az= 1.00 gx= -0.79 gy= 1.29 gz= -0.09 temp= 27.52