前のチュートリアルでは、Arduino UnoにFreeRTOSを導入し、LEDが点滅するタスクを作成しました。ここで、このチュートリアルでは、RTOS APIの高度な概念について詳しく説明し、さまざまなタスク間の通信について学習します。ここでは、あるタスクから別のタスクにデータを転送するためのキューについても学び、16x2LCDとLDRをArduinoUnoとインターフェースすることによってキューAPIの動作を示します。
キューについて説明する前に、割り当てられた作業が終了したときにタスクを削除するのに役立つFreeRTOSAPIをもう1つ見てみましょう。割り当てられたメモリを解放するために、タスクを削除する必要がある場合があります。前のチュートリアルの続きで、同じコードで vTaskDelete() API関数を使用して、タスクの1つを削除します。タスクは、 vTaskDelete() API関数を使用して、自分自身またはその他のタスクを削除できます。
このAPIを使用するには、 FreeRTOSConfig.h ファイルを構成する必要があります。このファイルは、アプリケーションに応じてFreeRTOSを調整するために使用されます。スケジューリングアルゴリズムや他の多くのパラメータを変更するために使用されます。このファイルは、PCのDocumentsフォルダーに通常あるArduinoディレクトリにあります。私の場合、以下に示すように、 \ Documents \ Arduino \ libraries \ FreeRTOS \ srcで 利用できます。
ここで、任意のテキストエディタを使用してこのファイルを開き 、#define INCLUDE_vTaskDelete を検索して 、 その値が「1」であることを確認します(1は有効、0は無効を意味します)。デフォルトでは1ですが、チェックします。
次のチュートリアルでは、この構成ファイルを頻繁に使用してパラメーターを設定します。
それでは、タスクを削除する方法を見てみましょう。
FreeRTOSArduinoでタスクを削除する
タスクを削除するには、vTaskDelete()API関数を使用する必要があります。引数は1つだけです。
vTaskDelete(TaskHandle_t pxTaskToDelete);
pxTaskToDelete:削除されるタスクのハンドルです。これは、 xTaskCreate() APIの6番目の引数と同じです。前のチュートリアルでは、この引数はNULLに設定されていますが、任意の名前を使用してタスクの内容のアドレスを渡すことができます。として宣言されているTask2のタスクハンドルを設定する場合を考えてみましょう。
TaskHandle_t any_name; 例:TaskHandle_t xTask2Handle;
ここで、vTaskCreate()APIで、6番目の引数を次のように設定します。
xTaskCreate(TaskBlink2、 "task2"、128、NULL、1、&xTask2Handle);
これで、指定したハンドルを使用して、このタスクのコンテンツにアクセスできます。
また、タスクは、有効なタスクハンドルの代わりにNULLを渡すことにより、自分自身を削除できます。
タスク3自体からタスク3を削除する場合は、 vTaskDelete(NULL); を記述する必要があり ます。 Task3関数内ですが、タスク2からタスク3を削除する場合は、 vTaskDelete(xTask3Handle);と 記述し ます。 task2関数内。
前のチュートリアルコードでは、task2自体からTask2を削除するには、 vTaskDelete(NULL);を 追加するだけ です。 中 のボイドTaskBlink2(void *型のpvParameters) 機能。すると、上記の関数は次のようになります
void TaskBlink2(void * pvParameters) { Serial.println( "Task2が実行中であり、削除しようとしています"); vTaskDelete(NULL); pinMode(7、OUTPUT); while(1) { digitalWrite(7、HIGH); vTaskDelay(300 / portTICK_PERIOD_MS); digitalWrite(7、LOW); vTaskDelay(300 / portTICK_PERIOD_MS)。 } }
次に、コードをアップロードして、LEDとシリアルモニターを観察します。2番目のLEDが点滅しておらず、deleteAPIが発生した後にtask2が削除されていることがわかります。
したがって、このAPIを使用して、特定のタスクの実行を停止できます。
それでは、キューから始めましょう。
FreeRTOSのキューとは何ですか?
キューは、有限数の固定サイズ要素を保持できるデータ構造であり、FIFOスキーム(先入れ先出し)で動作します。キューは、タスクからタスク、タスクから割り込み、および割り込みからタスクの通信メカニズムを提供します。
キューが保持できる要素の最大数は、その「長さ」と呼ばれます。各要素の長さとサイズの両方は、キューの作成時に設定されます。
キューがデータ転送にどのように使用されるかの例は、ここにあるFreeRTOSドキュメントによく示されています。与えられた例は簡単に理解できます。
キューを理解した後、キューを作成するプロセスを理解し、FreeRTOSコードに実装してみましょう。
FreeRTOSでのキューの作成
まず、FreeRTOSキューとArduinoUnoを使用して実装される問題ステートメントについて説明します。
LDRセンサーの値を16 * 2LCDに出力したいと思います。したがって、現在2つのタスクがあります
- Task1はLDRのアナログ値を取得しています。
- Task2はアナログ値をLCDに印刷しています。
したがって、ここでは、task1によって生成されたデータをtask2に送信するため、キューがその役割を果たします。task1では、アナログ値をキューに送信し、task2では、キューから受信します。
キューを操作するための3つの関数があります
- キューの作成
- キューへのデータの送信
- キューからデータを受信する
キューを作成するには、xQueueCreate()関数APIを使用します。2つの引数が必要です。
xQueueCreate(UBaseType_t uxQueueLength、UBaseType_t uxItemSize);
uxQueueLength:作成中のキューが一度に保持できるアイテムの最大数。
uxItemSize:キューに格納できる各データ項目のバイト単位のサイズ。
この関数がNULLを返す場合、メモリが不足しているためにキューは作成されません。NULL以外の値を返す場合、キューは正常に作成されます。以下に示すように、この戻り値を変数に格納して、キューにアクセスするためのハンドルとして使用します。
QueueHandle_t queue1; queue1 = xQueueCreate(4、sizeof(int));
これにより、intサイズ(各ブロックの2バイト)のヒープメモリに4要素のキューが作成され、戻り値が queue1 ハンドル変数に格納されます。
2.FreeRTOSのキューにデータを送信する
値をキューに送信するために、FreeRTOSにはこの目的のためのAPIの2つのバリアントがあります。
- xQueueSendToBack():キューの後ろ(テール)にデータを送信するために使用されます。
- xQueueSendToFront():キューの先頭(先頭)にデータを送信するために使用されます。
現在、 xQueueSend() は xQueueSendToBack() と同等であり、まったく同じ です。
これらのAPIはすべて3つの引数を取ります。
xQueueSendToBack(QueueHandle_t xQueue、const void * pvItemToQueue、TickType_t xTicksToWait);
xQueue:データが送信(書き込み)されるキューのハンドル。この変数は、xQueueCreateAPIの戻り値を格納するために使用されるものと同じです。
pvItemToQueue:キューにコピーされるデータへのポインター。
xTicksToWait:キューでスペースが使用可能になるのを待つために、タスクがブロック状態のままである必要がある最大時間。
xTicksToWait を portMAX_DELAYに 設定すると、 FreeRTOSConfig.hで INCLUDE_vTaskSuspend が1に設定されている場合、タスクは無期限に(タイムアウトせずに)待機します。それ以外の場合は、マクロ pdMS_TO_TICKS() を使用して、ミリ秒単位で指定された時間をティック単位で指定された時間に変換できます。
3.FreeRTOSのキューからデータを受信する
キューからアイテムを受信(読み取り)するには、xQueueReceive()を使用します。受信したアイテムはキューから削除されます。
このAPIも3つの引数を取ります。
xQueueReceive(QueueHandle_t xQueue、void * const pvBuffer、TickType_t xTicksToWait);
1番目と3番目の引数は、APIの送信と同じです。2番目の引数のみが異なります。
const pvBuffer:受信したデータがコピーされるメモリへのポインタ。
3つのAPIを理解したことを願っています。ここで、これらのAPIをArduino IDEに実装し、上記で説明した問題ステートメントの解決を試みます。
回路図
ブレッドボードでは次のように表示されます。
ArduinoIDEでのFreeRTOSキューの実装
アプリケーションのコードを書き始めましょう。
1.まず、Arduino IDEを開き、 Arduino_FreeRTOS.h ヘッダーファイルをインクルードします。ここで、キューなどのカーネルオブジェクトを使用する場合は、そのヘッダーファイルをインクルードします。16 * 2 LCDを使用しているので、そのためのライブラリも含めます。
#include #include
2.キューハンドルを初期化して、キューの内容を格納します。また、LCDのピン番号を初期化します。
QueueHandle_t queue_1; LiquidCrystal lcd(7、8、9、10、11、12);
3. void setup()で、 LCDとシリアルモニターを9600ボーレート で 初期化します。それぞれのAPIを使用して、キューと2つのタスクを作成します。ここでは、整数型のサイズ4のキューを作成します。同じ優先順位でタスクを作成し、後でこの番号で遊んでみてください。最後に、以下に示すようにスケジューラを起動します。
void setup(){ Serial.begin(9600); lcd.begin(16、2); queue_1 = xQueueCreate(4、sizeof(int)); if(queue_1 == NULL){ Serial.println( "キューを作成できません"); } xTaskCreate(TaskDisplay、 "Display_task"、128、NULL、1、NULL); xTaskCreate(TaskLDR、 "LDR_task"、128、NULL、1、NULL); vTaskStartScheduler(); }
4.次に、2つの関数 TaskDisplay と TaskLDRを作成し ます。で TaskLDRの 我々はArduinoのUNOのA0ピンにLDRが接続されているように関数、変数、アナログピンA0を読み出します。次に、変数に格納されている値を xQueueSend APIに渡して送信し、 次に 示すように vTaskDelay() APIを使用して1秒後にタスクをブロック状態に送信します。
void TaskLDR(void * pvParameters){ int current_intensity; while(1){ Serial.println( "Task1"); current_intensity = analogRead(A0); Serial.println(current_intensity); xQueueSend(queue_1、¤t_intensity、portMAX_DELAY); vTaskDelay(1000 / portTICK_PERIOD_MS); } }
5.同様に、 TaskDisplayの 関数を 作成 し、 xQueueReceive 関数に渡される変数の値を 受け取り ます。また、 xQueueReceiveは() 戻り pdPASSを データキュー戻るから正常に受信することができれば errQUEUE_EMPTY キューが空である場合。
ここで、 lcd.print() 関数を使用して値をLCDに表示します。
void TaskDisplay(void * pvParameters){ int強度= 0; while(1){ Serial.println( "Task2"); if(xQueueReceive(queue_1、&intensity、portMAX_DELAY)== pdPASS){ lcd.clear(); lcd.setCursor(0、0); lcd.print( "強度:"); lcd.setCursor(11、0); lcd.print(intensity); } } }
それでおしまい。キュー実装のコーディング部分が終了しました。動作するビデオを含む完全なコードは、最後にあります。
次に、回路図に従ってLCDとLDRをArduino UNOに接続し、コードをアップロードします。シリアルモニターを開き、タスクを観察します。タスクが切り替わり、LDR値が光の強度に応じて変化していることがわかります。
注:異なるセンサー用に作成されたライブラリのほとんどは、ライブラリ内の遅延関数の実装のため、FreeRTOSカーネルではサポートされていません。遅延によりCPUが完全に停止するため、FreeRTOSカーネルも動作を停止し、コードはそれ以上実行されず、誤動作が始まります。そのため、FreeRTOSを使用するには、ライブラリを遅延なしにする必要があります。