#include <Arduino_FreeRTOS.h>
TaskHandle_t TaskA_Handler;
TaskHandle_t TaskB_Handler;
void functionX(void *p); //タスクに用いる関数は1つだけ
void setup() {
Serial.begin(115200);
Serial.println("start");
//タスクは2つ定義
xTaskCreate(functionX, "TaskA", 128, (void *)"TaskA", 2, &TaskA_Handler);
xTaskCreate(functionX, "TaskB", 128, (void *)"TaskB", 1, &TaskB_Handler);
/*
第4引数で、タスク名(文字列)をvoid *型にcastして渡すことができる
void *型の引数は、タスクで受取った後にchar *型にキャストできる
*/
vTaskStartScheduler(); //FreeRTOSのスケジューラを開始
}
void loop() {} //loop関数は使わないので空
void functionX(void *pValue) {
//タスクが最後に実行された時間を記録するための変数xLastWakeTimeを宣言
TickType_t xLastWakeTime;
//xLastWakeTime変数に、現在のTick値を代入。RTOS内で時間を扱う作法
xLastWakeTime = xTaskGetTickCount();
//3秒をTick(FreeRTOSの時間単位)に変換し、定数xDelay1sに格納
//「3000 / portTICK_PERIOD_MS」でも可能
const TickType_t xDelay = pdMS_TO_TICKS(3000);
while(1) {
char *p_taskName = (char *)pValue; //char *型にキャスト
Serial.print(p_taskName); //ポインタの引数を扱える
Serial.println(" は今から3秒停止します");
//xLastWakeTimeからxDelay1s(今回は1秒)だけ遅延させる
//タスクを一時停止状態にし、指定された時間が経過するまでスケジューラに制御を戻す
//この間に、スケジューラが次の優先度のタスクBを実行する
//仮にタスクBが長期停止しても、3秒後には優先度の高いタスクAが再開される
vTaskDelayUntil(&xLastWakeTime, xDelay);
Serial.print(p_taskName);
Serial.print(" は再開します → ");
/*ここでvTaskDelay()を使うことはできないのか?
vTaskDelay()を使うことは可能だが、完全に周期的な制御はできなくなる
▼vTaskDelay()
単純に指定した時間(Tick数)だけタスクを停止(ブロック)させる
タスクはその時間が経過するまで実行されず、他のタスクにCPU時間を譲る
各タスクが実行されるタイミングはスケジューリングの影響を受ける
つまり、周期的な動作を保証するのが難しくなる
例えば、他のタスクが多くのCPU時間を消費した場合、このタスクの次の実行が遅れる可能性がある
▼vTaskDelayUntil
前回タスクが実行された時点から、指定した時間が正確に経過するように制御される
周期的な動作を正確に保証することが可能
▼なぜdelay()ではダメなのか?
delay() は指定されたミリ秒数だけ、CPUが他の処理を行わずに待機する。
この間、他のコードやタスクは実行されないので、ブロッキング動作といえる。
他の動作がブロックされるので、マルチタスクの環境には向いていない。
*/
}
}