第2章: ベアメタルからの出発#

OS を使わずに(ベアメタルで)、loop() の中の自作の協調的スケジューラが、LED の点滅・ サーボ角度の計算(表示だけで、サーボは不要)・A0 の読み取りの 3 つのタスクを順番に 回すところから始めます。

サンプルコード#

  • ディレクトリ: docs/os-on-arduino/code/02_baremetal

  • ビルドと書き込み:

uv run pio run -d 02_baremetal -t upload
uv run pio device monitor -b 115200

コードを見る: docs/os-on-arduino/code/02_baremetal

ソースコード#

この章のスケッチです。ファイル名をクリックすると開きます。コードは原稿リポジトリから自動で同期されているので、ここに出ているものが常に最新です。

src/main.cpp — 119 行

GitHub で開く

  1/**
  2 * Chapter 2: Cooperative Multitasking Scheduler
  3 *
  4 * Demonstrates cooperative (non-preemptive) multitasking.
  5 * Each task runs to completion before another task can run.
  6 *
  7 * Problem: If one task takes too long (like heavy_task),
  8 * all other tasks are delayed.
  9 */
 10
 11#include <Arduino.h>
 12
 13#define LED_PIN LED_BUILTIN
 14#define SERVO_PIN 9
 15
 16// --- Scheduler Definition ---
 17typedef void (*TaskFunc)(void);
 18
 19struct Task {
 20    TaskFunc func;
 21    unsigned long interval;
 22    unsigned long last_run;
 23    const char* name;
 24};
 25
 26#define MAX_TASKS 4
 27Task tasks[MAX_TASKS];
 28int task_count = 0;
 29
 30void scheduler_add_task(TaskFunc func, unsigned long interval, const char* name)
 31{
 32    if (task_count < MAX_TASKS) {
 33        tasks[task_count].func = func;
 34        tasks[task_count].interval = interval;
 35        tasks[task_count].last_run = 0;
 36        tasks[task_count].name = name;
 37        task_count++;
 38    }
 39}
 40
 41void scheduler_run(void)
 42{
 43    unsigned long now = millis();
 44    for (int i = 0; i < task_count; i++) {
 45        if (now - tasks[i].last_run >= tasks[i].interval) {
 46            tasks[i].last_run = now;
 47
 48            Serial.print("[");
 49            Serial.print(now);
 50            Serial.print("ms] Running: ");
 51            Serial.println(tasks[i].name);
 52
 53            tasks[i].func();
 54        }
 55    }
 56}
 57
 58// --- Task Definitions ---
 59void led_task(void)
 60{
 61    static bool state = false;
 62    state = !state;
 63    digitalWrite(LED_PIN, state);
 64    Serial.println("  LED toggled");
 65}
 66
 67void servo_task(void)
 68{
 69    static int angle = 0;
 70    angle = (angle + 10) % 180;
 71    Serial.print("  Servo angle: ");
 72    Serial.println(angle);
 73}
 74
 75void sensor_task(void)
 76{
 77    int value = analogRead(A0);
 78    Serial.print("  Sensor value: ");
 79    Serial.println(value);
 80}
 81
 82void heavy_task(void)
 83{
 84    // Simulate heavy processing
 85    Serial.println("  Heavy task start...");
 86    delay(200);  // 200ms blocking!
 87    Serial.println("  Heavy task end");
 88}
 89
 90// --- Setup and Loop ---
 91void setup()
 92{
 93    Serial.begin(115200);
 94    while (!Serial) { }
 95
 96    pinMode(LED_PIN, OUTPUT);
 97    pinMode(SERVO_PIN, OUTPUT);
 98
 99    Serial.println("=== Cooperative Scheduler Demo ===");
100    Serial.println();
101    Serial.println("This demonstrates cooperative multitasking.");
102    Serial.println("Uncomment heavy_task to see the problem with blocking tasks.");
103    Serial.println();
104
105    // Register tasks
106    scheduler_add_task(led_task, 500, "LED");
107    scheduler_add_task(servo_task, 100, "Servo");
108    scheduler_add_task(sensor_task, 200, "Sensor");
109    // Uncomment the following line to see the problem:
110    // scheduler_add_task(heavy_task, 1000, "Heavy");
111
112    Serial.println("Tasks registered. Starting scheduler...");
113    Serial.println();
114}
115
116void loop()
117{
118    scheduler_run();
119}

実機での出力#

Arduino UNO R4 WiFi の実機で実際に取得した出力です(macOS / Windows の 両方で同じ結果を確認しています)。手元の出力と見比べてください。

協調的スケジューラが 3 つのタスクを順に回しています。Sensor value は可変抵抗をつないでいなければ端子が拾うノイズです。

Servo タスクは角度を計算して表示するだけで、サーボには信号を出しません。サーボをつなぐ必要はありません。

../_images/ch02_tasks.gif

Servo angle が 10 度ずつ動き、その合間に LED と Sensor が 挟まるところ。3 つのタスクが順番に回っているのが見えます#

[2500ms] Running: LED
  LED toggled
[2500ms] Running: Servo
  Servo angle: 70
[2600ms] Running: Servo
  Servo angle: 80
[2600ms] Running: Sensor
  Sensor value: 219
[2700ms] Running: Servo
  Servo angle: 90
[2800ms] Running: Servo
  Servo angle: 100
[2800ms] Running: Sensor
  Sensor value: 219
...

つまずきやすいポイント#

(読者からの質問に応じて随時追記します。質問は GitHub Issues へどうぞ)