キュー【FreeRTOSでの具体的な使い方】

キューとは

めかのとろ

キュー(Queue)とはコンピュータ用語の一つで、FreeRTOSではデータをタスク間で転送する場合によく利用されます。語源は順番を待つものの列のことです。

めかのとろ

キューは先入れ先出し(First In First Out)のデータ構造となっているバッファ(一時データ格納所)です。

めかのとろ

これと逆の動作をする後入れ先出し(Last In First Out)のデータ構造となっているバッファはスタックといいます。

キューとスタック

キューを使ったタスク間でのデータ転送

めかのとろ

キューを使ったタスク間でのデータ転送の応用例として、EEPROMへのパラメータ書き込みによる保存について解説していきます。

めかのとろ

処理Aを行うタスクTaskAと処理Bを行うTaskBが並列実行しているアプリケーションにおいて、それぞれのタスク内に存在するデータを外部メモリEEPROMに書き込んで保存します。

めかのとろ

EEPROM書き込み専用タスクTaskCにデータの転送を行ってからキューの順番で書き込んでいきます。EEPROMの書き込み処理はマイコンの処理の中でも比較的時間を要するものです。このため、通常の処理を行うTaskAやTaskBで書き込みを行ってしまうと、肝心な処理が中断してしまいます。

めかのとろ

そこで、EEPROMの書き込みだけを行うタスクとしてTaskCを作成し、キューの順番にしたがって処理を行うと効率がよくなります

 キューバッファ作成: 

めかのとろ

キューを利用するためにはまずキューのハンドル用変数xQueueを宣言しておきます。ハンドル用変数とは操作で扱う変数と理解しておいてください。この変数でタスク間のデータ受け渡しを行います。

めかのとろ

次にxQueueCreate関数でキューバッファを作成します。

キューバッファ作成 xQueueCreate関数実行例:xQueue=xQueueCreate(10,(sizeof(int8_t));

めかのとろ

関数の第1引数にはキューに格納するデータの個数を、第2引数にはキューに格納するデータ1つあたりのバイト数を指定します。この例では格納データの個数は10、受け渡すデータは最大255までの数値のため、データ長は1バイトを指定します。これでキューバッファのためのメモリが確保され、キューが使用できるようになります。

めかのとろ

この例では、キューバッファにはEEPROMに保存したいデータ値そのものを渡すのではなくデータ値のIDの受け渡しを行っています。そのため、キューのデータ長さは1(1byte)なのですが、文字列などの受け渡しもできます。その場合は使用する文字の個数(1文字1byte)を指定します。

めかのとろ

ただし、キューを作成することはメモリを確保することなのでメモリが不十分で確保に失敗するとxQueueCreate関数の返り値ハンドル用変数xQueueNULLとなります。キューを作成する場合は上例のようにキュー作成の確保を確認してから次に進めます。

 キューへの送信: 

めかのとろ

キューへデータを渡す(キューへの送信)には処理を行う各タスク内で行います。

めかのとろ

キューへのデータ送信はxQueueSendToBack関数を使用します。関数の第1引数はキューハンドル用変数xQueueを、第2引数には送信するデータのポインタ(アドレス)を指定します。関数の第3引数はキューの最大の待ち時間を指定します。指定時間の単位はTickです。マクロのportMAX_DELAYを指定すると待ち時間は制限なしになります。逆に0を指定すると待ち時間はなしになります。

 キューへの受信: 

めかのとろ

キューへ格納したデータを受け取るのは(キューからの受信)のはタスク内で行います。データを処理したいタスク内で行います。この例ではEEPROMの書き込み専用タスクTaskCで行います。

めかのとろ

キューからデータ受信はxQueueReceive関数を使用します。キューからのデータを格納する変数を準備しておきます。この例では1バイトのqueue_bufferとしています。関数の第1引数はキューハンドル用変数xQueueを、第2引数にはデータ格納変数queue_bufferのポインタ(アドレス)を指定します。関数の第3引数はキューの最大の待ち時間を指定します。

めかのとろ

送信のときとデータの流れは逆になり、キューからキューハンドル変数xQueueを介してデータを受け取り、データ格納変数queue_bufferで受け取ってそのデータ値にしたがって順次処理していく要領です。

キューによるデータの流れ
めかのとろ

このため、TaskCの実行周期がまわってきたときにキューバッファが空になるまでEEPROMの書き込みを実行することになります。これでTaskAとTaskBは自分の処理だけに集中できることになります。

めかのとろ

サンプル例では通常の処理TaskAやTaskBで発生したデータをとりあえずキューバッファにためておいて、比較的実行周期は長めで優先順位は高く設定したEEPROM書き込み専用タスクTaskCに渡しています(優先順位に関しては処理によります)。