FreeRTOS キュー

キューはタスク同士のデータ通信に使用します。キューはサイズが決められたFIFOバッファと同様です。基本的にFIFOですが、先頭のバッファにデータを上書きすることもできます。

また、キューは複数のタスクによる書き込み、そして読み込みが可能です。

それではキューを用いたシンプルな例を示します。


#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);
  }
}

出力結果:
0
11
21
31
41

サンプルでは、まずsetupで長さが1のキュー"queue1"を生成しています。長さは1ですが、実際にはuint32_tのサイズである4バイトのキューです。その後、タスク"sender_task"が生成され、100ms間隔でインクリメントするcount値をキューに送ります。loopの中で1秒ごとにキューからデータを読み込んで表示します。

出力結果として、count初期値の0が出力されています。これはキューが上書きされず、loopでxQueueReceiveが行われるまで保持していることを意味します。

なお、xQueueSendやxQueueReceiveは第3引数の値によって、キューが空く、あるいはキューにデータが来るまで一定時間待つという設定を行うことができます。

xQueueSendをxQueueOverwriteに置き換えると、キューにデータを上書きするようになります。例えばセンサーの値を絶えず更新していくような場合に、キューのレシーブ側を考えずに済みます。


xQueueOverwrite(queue1, &count);

出力結果:
10
20
30
40

xQueueOverwriteを使用したときは、出力結果に示す通り、count値の最新値がキューに書かれていることが分かります。

最後に加速度センサMPU6050から加速度、角速度、温度を表示する例を示します。要点としては、キューで扱うデータをstruct Data_t型にしていることです。また、センサーを読むタスク、値を表示するタスクをそれぞれ分けているため、例えば値を表示するタスクをモーター制御を行うタスクに置き換えることも容易に行うことができます


#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);
  }
}

出力結果:
  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