FreeRTOS 入門チュートリアル (アイドル タスク、フック関数、タスク スケジューリング アルゴリズム)


序文

この記事では、アイドル タスクとフック関数とは何かを説明し、FreeRTOS のタスク スケジュール アルゴリズムを学習し、FreeRTOS でタスクがどのように切り替えられ、スケジュールされるかを理解します。

1. アイドルタスクの概念

アイドル タスクは、組み込みリアルタイム オペレーティング システム (RTOS) の特別なタスクです。これはシステム内で最も優先度の低いタスクであり、システム内で他のタスクを実行する必要がないときに実行されます。アイドル タスクの目的は、他の作業を実行する必要がないときにプロセッサをビジー状態に保ち、プロセッサがアイドル状態にならないようにすることです。

アイドル タスクは RTOS で重要な役割を果たします。アイドル タスクは、他のすべてのタスクに実行する作業がないときに実行されます。通常、低電力モードへの移行、システム統計の更新、スケジューラ処理などのいくつかの軽量操作を実行します。プロセッサーのリソースを最大限に活用するには、アイドル状態のタスクの実行時間をできるだけ短くする必要があります。

アイドル タスクはバックアップ タスクとみなすことができ、他のタスクの準備ができていない場合でも、システムに常に実行可能なタスクが確保されます。これは、外部イベントやユーザー要求に迅速に応答する必要があるリアルタイム システムにとって特に重要です。アイドル タスクを通じて、RTOS はシステムの継続性と応答性を確保できます。

FreeRTOS では、アイドル タスクはカーネルによって自動的に作成され、管理されます。

vTaskStartScheduler を使用してスケジューラを開くと、アイドル状態のタスクが自動的に作成されます。
ここに画像の説明を挿入します

2. フック機能の概念

FreeRTOS のフック関数は、FreeRTOS カーネルで特定のイベントが発生したときにカスタム コードを実行するために使用されるユーザー定義のコールバック関数です。これらのフック関数を使用すると、開発者は特定のニーズ、デバッグ、またはパフォーマンス分析に合わせて FreeRTOS の内部操作に介入できます。

フック関数を使用する場合、まず FreeRTOS で configUSE_IDLE_HOOK 設定マクロを有効にする必要があります。

FreeRTOSConfig.h:
ここに画像の説明を挿入します

ここに画像の説明を挿入します
フック関数を再実装します。

void vApplicationIdleHook( void )
{
    
    
	//用户自定义处理
}

3. タスクスケジューリングアルゴリズム

スケジューリング アルゴリズムは、利用可能なシステム リソース上でプロセスまたはスレッドを実行する順序とタイミングを決定する、オペレーティング システム内の一連のルールとポリシーです。スケジューリング アルゴリズムの機能は、システム リソースを合理的に利用し、システムのパフォーマンス、応答性、効率を向上させることです。

调度算法在多任务操作系统中起着重要的作用,它决定了各个任务之间的执行顺序、分配的时间片长度以及资源的分配策略。

在 FreeRTOS 中,调度算法和行为可以通过一些宏配置来决定,包括 configUSE_PREEMPTION、configUSE_TIME_SLICING 和 configIDLE_SHOULD_YIELD。

1.configUSE_PREEMPTION:

このマクロは、タスクのプリエンプションを有効にするかどうかを制御します。1 に設定すると、優先度の高いタスクは現在実行中のタスクに割り込むことができます。0 に設定すると、タスクのプリエンプションは許可されません。
タスク プリエンプションにより、優先度の高いタスクが即座にプロセッサの制御を取得して、リアルタイムのニーズを満たすことができます。ただし、プリエンプションによりコンテキスト切り替えのオーバーヘッドが発生し、パフォーマンスに影響を与える可能性があります。

2.configUSE_TIME_SLICING:

このマクロは、タイム スライシングを有効または無効にするために使用されます。タイムスライス ラウンドロビン スケジューリングは、複数のタスクが同じ優先度を持ち、実行可能な場合、タイムスライス方式で順番にプロセッサを使用するメカニズムです。
1 に設定すると、タイム スライス ラウンド ロビン スケジューリングが有効になり、0 に設定すると、タイム スライス ラウンド ロビン スケジューリングが無効になります。

3.configIDLE_SHOULD_YIELD:

このマクロは、アイドル状態のタスクがプロセッサを積極的に放棄するかどうかを構成するために使用されます。システムに他に実行する優先度の高いタスクがない場合、アイドル状態のタスクがプロセッサの制御を引き継ぎます。1 に設定すると、アイドル タスクは他の操作を実行する必要がない場合にプロセッサを積極的に放棄します。0 に設定すると、アイドル タスクはプロセッサを積極的に放棄しません。

システム内に実行する必要がある他の優先度の低いタスクがある場合、アイドル状態のタスクにプロセッサを積極的に放棄させると、応答時間とシステム パフォーマンスが向上します。

Baiwen.com が提供するデータ マップは次のとおりです。
ここに画像の説明を挿入します

4. タスクスケジューリングアルゴリズムの実験

1. 実験コード

volatile int flagIdleTaskrun = 0;  // 空闲任务运行时flagIdleTaskrun=1
volatile int flagTask1run = 0;     // 任务1运行时flagTask1run=1
volatile int flagTask2run = 0;     // 任务2运行时flagTask2run=1
volatile int flagTask3run = 0;     // 任务3运行时flagTask3run=1

/*-----------------------------------------------------------*/

void vTask1( void *pvParameters )
{
    
    
	/* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
    
    
		flagIdleTaskrun = 0;
		flagTask1run = 1;
		flagTask2run = 0;
		flagTask3run = 0;
		
		/* 打印任务的信息 */
		printf("T1\r\n");				
	}
}

void vTask2( void *pvParameters )
{
    
    	
	/* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
    
    
		flagIdleTaskrun = 0;
		flagTask1run = 0;
		flagTask2run = 1;
		flagTask3run = 0;
		
		/* 打印任务的信息 */
		printf("T2\r\n");				
	}
}

void vTask3( void *pvParameters )
{
    
    	
	const TickType_t xDelay5ms = pdMS_TO_TICKS( 5UL );		
	
	/* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
    
    
		flagIdleTaskrun = 0;
		flagTask1run = 0;
		flagTask2run = 0;
		flagTask3run = 1;
		
		/* 打印任务的信息 */
		printf("T3\r\n");				

		// 如果不休眠的话, 其他任务无法得到执行
		vTaskDelay( xDelay5ms );
	}
}

void vApplicationIdleHook(void)
{
    
    
	flagIdleTaskrun = 1;
	flagTask1run = 0;
	flagTask2run = 0;
	flagTask3run = 0;	
	
	/* 故意加入打印让flagIdleTaskrun变为1的时间维持长一点 */
	//printf("Id\r\n");				
}

int main( void )
{
    
    
	prvSetupHardware();
	
	xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);
	xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);
	xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);

	/* 启动调度器 */
	vTaskStartScheduler();

	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

2. プリエンプトするかどうか

抢占:
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 1
ここに画像の説明を挿入します

不使用:
#define configUSE_PREEMPTION 0
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 1

ここに画像の説明を挿入します

ここで、プリエンプトするように構成されている場合、優先度の高いタスクは準備ができた直後に実行できることがわかります。

非プリエンプティブルとして構成されている場合、タスクは実行を継続し、他のタスクが実行権限をプリエンプトすることはできません。

3. タイムスライスが回転するかどうか

タイム スライスの回転をサポートします。

#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 1

ここに画像の説明を挿入します

タイム スライスの回転はサポートされていません:

#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 0
#define configIDLE_SHOULD_YIELD 1

ここに画像の説明を挿入します
タイム スライスの回転をサポートするように構成されている場合、Tick で中断するとタスクの切り替えが発生します。

タスクの切り替えは、優先度の高いタスクの準備ができたときに発生し、優先度の高いタスクが実行されなくなったときに発生します
タスク 3 は準備が整うとすぐに実行できることがわかりますが、タスク 3 が完了するとタスクの切り替えが発生します。それ以外の時間ではタスクの切り替えはなく、
タスク 1 とタスク 2 の両方が長時間実行されていることがわかります。

当 FreeRTOS 配置为支持时间片轮转(即 configUSE_TIME_SLICING 设置为 1)时,任务会按照时间片的方式进行调度。每个任务被分配一个时间片,在时间片用尽之前,如果发生 Tick 中断,则会引起任务切换。

4. アイドルタスクの譲歩

アイドルタスクの譲歩
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 1

ここに画像の説明を挿入します

アイドルタスクは結果を生成しません
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 0

ここに画像の説明を挿入します
アイドル タスクが譲歩するように構成されている場合、アイドル タスクは短時間実行され、他のタスクに実行を譲ることがわかります。

アイドル タスクが譲歩しないように設定されている場合、アイドル タスクの実行時間はタスク 1 およびタスク 2 の実行時間と同様であり、譲歩は行われないことがわかります。

要約する

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

おすすめ

転載: blog.csdn.net/m0_49476241/article/details/133387013
おすすめ