FreeRTOS 入門チュートリアル (タスク ステータス)


序文

この記事では、FreeRTOS のタスクのステータスについて説明します。FreeRTOS のタスクにはさまざまなステータスがあり、これらのタスクのステータスを理解することは、タスクの実行と停止の仕組みを理解するのに役立ちます。

1. 簡単な実験

これを行う前に、タスクがどのように実行されるかを確認するための実験を行ってみましょう。
コード:

次のコードは、最初に、どのタスクが実行中であるかをマークする 3 つのフラグ ビットを定義します。

static int Task1Flag = 0;
static int Task2Flag = 0;
static int Task3Flag = 0;

//任务执行函数
void Task1(void * param)
{
    
    
	static int i = 0;
	while (1)
	{
    
    
		Task1Flag = 1;
		Task2Flag = 0;
		Task3Flag = 0;
	}
}

//任务执行函数
void Task2(void * param)
{
    
    
	while (1)
	{
    
    
		Task1Flag = 0;
		Task2Flag = 1;
		Task3Flag = 0;		
	}
}

//任务执行函数
void Task3(void * param)
{
    
    
	while (1)
	{
    
    
		Task1Flag = 0;
		Task2Flag = 0;
		Task3Flag = 1;		
	}
}

keil でシミュレートされたシリアル ポートを開きます。
ここに画像の説明を挿入します

keil でロジック アナライザーを開きます:
ここに画像の説明を挿入します
定義された 3 つの変数をロジック アナライザーに追加します:
ここに画像の説明を挿入します
ステータスを bit に設定します:
ここに画像の説明を挿入します
設定後、コードをフルスピードで実行します:
これら 3 つのタスクが同時に実行されていないことがわかります。は別々に実行されますが、実行時間が短く、誰が実行しているかわかりません。
ここに画像の説明を挿入します
各タスクの実行時間を観察すると、各タスクの実行時間が約 1ms であることがわかりますが、これはなぜでしょうか?

FreeRTOSにはTick割り込みがあり、割り込みが発生するたびにタスク切り替えが必要かどうかを判定するのですが、このTick割り込みは何msで発生するのでしょうか?

答えは FreeRTOSConfig ファイルにあります
ここに画像の説明を挿入します
。configTICK_RATE_HZ はカーネル クロック ビートの周波数をヘルツ (Hz) で指定します。

FreeRTOS では、カーネル クロック ティックは、タスクの実行時間、待機時間、タイマー、およびその他の機能の時間を測定するために使用される時間標準です。カーネル クロック ビートの周波数は configTICK_RATE_HZ で設定できます。デフォルト値は 1000 で、これは 1 秒あたり 1000 クロック ビート、つまりクロック ビート周期が 1 ミリ秒であることを意味します。

もう 1 つの疑問は、なぜタスク 3 が最初に実行されるのかということです。
タスク作成関数内にこのような関数があります この関数は作成したタスクを準備済みのリンクリストに追加します 後から作成したタスクがリンクリストの先頭になるので、後から作成したタスクを取り出して実行します初め。
ここに画像の説明を挿入します

2. タスクステータスの概念の説明

ここでは、Baiwen.com からのタスク変換の図を使用して説明します。
ここに画像の説明を挿入します
FreeRTOS では、各タスクには現在のタスクの状況を表すステータスがあります。FreeRTOS は、さまざまなタスクの状態を表すためにいくつかの特定のマクロ定義を使用します。これらのマクロ定義には次のものが含まれます。

eRunning: タスクが実行中であることを示します。

eReady: タスクが準備完了状態にあり、スケジューラによる実行のスケジュールを待っていることを示します。

eBlocked: タスクがブロック状態にあること、つまり、セマフォ、メッセージ キュー、タイマー タイムアウトなどの特定のイベントの発生を待機していることを示します。

eSuspended: タスクが一時停止状態にあることを示します。つまり、タスクは一時停止されており、スケジューリングには参加しませんが、ステータスとリソースは保持され、必要に応じて再開できます。

eDeleted: タスクが削除され、対応する制御ブロックとスタック領域が解放されたことを示します。

タスク状態間の遷移は、FreeRTOS カーネルによって自動的に管理されます。次の状況では、タスクのステータスが変更されることがよくあります。

タスクが作成されると、タスクのステータスが「未開始」から「準備完了」に変わります。

スケジューラは優先度に基づいてタスクを選択し、そのステータスを「実行中」に変更します。

タスクがイベント(セマフォなど)を待っている場合、タスクのステータスは「ブロック」になります。

タスクが他のタスクのリソースの解放を待っている間、タスクのステータスは「保留中」に変わることがあります。

タスクが削除関数を呼び出して自身を削除すると、タスクのステータスは「削除済み」に変わります。

3. vTaskDelay と vTaskDelayUntil

1.vタスク遅延

vTaskDelay 関数は、実行を継続する前に現在のタスクを一定期間一時停止するために使用されます。そのパラメータは整数で、遅延するシステム ティック数を示します。たとえば、デフォルト構成では、カーネル ビート サイクルは 1 ミリ秒であるため、vTaskDelay(100) は現在のタスクを 100 ミリ秒間一時停止します。

需要注意的是,vTaskDelay会引起任务阻塞,同时该延迟时间不是绝对准确的。在等待期间FreeRTOS会尝试进行其他任务的调度,因此实际的延迟时间可能会比指定的时间长。

コード例:

void Task1(void * param)
{
    
    
	static int i = 0;
	while (1)
	{
    
    
		printf("Task1\r\n");
		vTaskDelay(1000);
	}
}

//任务执行函数
void Task2(void * param)
{
    
    
	while (1)
	{
    
    
		printf("Task2\r\n");
		vTaskDelay(2000);
	}
}

//任务执行函数
void Task3(void * param)
{
    
    
	while (1)
	{
    
    
		printf("Task3\r\n");
		vTaskDelay(3000);
	}
}

シリアル ポートの印刷結果を観察します。
ここに画像の説明を挿入します

2.vTaskDelayUntil

vTaskDelayUntil は、タスクを特定の時点まで待機させてから再び準備ができるようにする正確なタイミング関数です。

vTaskDelayUntil を呼び出すときは、タイムスタンプ (TickType_t 型で表される) を指定する必要があります。タスクは、システム クロックがタイムスタンプに達するかそれを超えるまでスリープします。

これにより、タスクを正確な時間間隔で実行できるため、リアルタイム要件の高いアプリケーションに最適です。

// 定义一个任务,该任务会每隔1秒输出一次消息
void Task1(void* pvParameters)
{
    
    
    TickType_t xLastWakeTime;
    const TickType_t xFrequency = pdMS_TO_TICKS(1000); // 1秒的时间间隔

    // 获取当前时间作为初始时间
    xLastWakeTime = xTaskGetTickCount();

    while (1)
    {
    
    
        // 执行任务1的操作,例如输出消息
        printf("Task1 is running...\n");

        // 等待到达下一个时间间隔
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
    }
}

int main(void)
{
    
    
    // 初始化FreeRTOS内核和硬件

    // 创建任务1
    xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 此处不会执行,因为调度器会接管控制权
    return 0;
}

3.vTaskDelay と vTaskDelayUntil の違い

vTaskDelay 関数と vTaskDelayUntil 関数は両方とも、FreeRTOS でタスクの時間遅延を実装するために使用されますが、その方法は異なります。

vTaskDelay 関数は、ティックの相対遅延数を渡すことによって機能します。タスクは指定されたティック数の間ブロックされ、その後実行を継続します。これは、vTaskDelay の遅延時間は現在のタスクの実行時間に相対的であり、実際の遅延時間はタスクの切り替えやシステム負荷の影響を受ける可能性があることを意味します。したがって、正確な遅延時間を保証することはできず、一定の誤差が生じる可能性があります。

vTaskDelayUntil 関数は、ティックで表現された絶対時点を渡すことによって機能します。タスクは、現在時間が経過した絶対時点に達するか超えるまで待機し、その後実行を続行します。これは、vTaskDelayUntil がより正確な遅延制御を提供し、正確なタイミング タスクを達成できることを意味します。必要に応じて次の実行時点を計算し、それを vTaskDelayUntil 関数に渡すと、タスクがその時点でブロックされ、正確な遅延時間が保証されます。

vTaskDelay用于相对延迟,而vTaskDelayUntil用于绝对时间点延迟,使得在实现定时任务时更加方便和精确。

要約する

この記事ではここで説明します。

おすすめ

転載: blog.csdn.net/m0_49476241/article/details/130451344