Arduinoの基礎 - 終了

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

Arduino UNOのファームウェアは、一般的に終了することを想定していない。
setup関数での初期化した後、loop関数が永続的に実行され続けることが標準的な動作である。

しかし、開発では重大なエラーや異常が発生した場合に、適切に終了または再起動する必要性がある。

終了処理の主要な方法として、以下に示す方法がある。

  • abort関数
  • ただし、適切なエラー通知やリソースの解放を行うことができない。
  • ウォッチドッグタイマ (WDT) の使用
    WDTは一定時間内にリセットされなければ、自動的にシステムを再起動する機構である。
  • LEDやブザー等のインジケータの使用
    実用的な終了処理では、エラー状態の通知も重要となる。
    また、EEPROM等の不揮発性メモリにエラー情報を記録しておくことにより、再起動後にトラブルシューティングが容易になる。


特に産業用途では、グレースフル・シャットダウンの実装が重要となる。

  • 進行中の処理の適切な終了
  • 重要なデータの保存
  • 外部機器との通信の終了
  • 各種リソースの解放


セーフティクリティカルなシステムでは、フェイルセーフモードへの移行も考慮する必要がある。
これは完全な停止ではなく、最小限の安全機能を維持しながらシステムを制御された状態に保つアプローチである。

デバッグを考慮した終了処理も考慮する必要がある。
シリアル通信を通じてエラー情報を出力することで、開発時のトラブルシューティングが容易になる。

また、マイコンのハードウェアの特性 (割り込み処理の適切な終了やI/Oピンの状態制御等) に合わせた終了処理を実装する必要がある。

以下に示すような要因を考慮して選択するとよい。

  • エラー状態をユーザに通知する必要性
  • デバッグのしやすさ
  • システムの復旧方法の要件
  • ハードウェアリソースの制約



abort関数

abort関数は、ファームウェアを強制終了する関数である。
ただし、プログラムを停止するだけであるため、エラーインジケータ等を使用することが推奨される。

 void setup()
 {
   if (!initializeSensor()) {
     Serial.println(F("Sensor initialization failed"));
     abort();
   }
 }



エラーインジケータの使用

エラーインジケータを使用した終了が推奨される。

  • エラーの種類を視覚的に示すことが可能である。
  • デバッグ時に問題の特定が容易である。
  • シリアル通信が使えない環境でも状態が理解できる。
  • システムの状態が完全に把握できる。


 const int ERROR_LED_PIN = 13;
 
 void errorHalt(int blinkCount)
 {
   while (true) {
     for (int i = 0; i < blinkCount; i++) {
       digitalWrite(ERROR_LED_PIN, HIGH);
       delay(500);
 
       digitalWrite(ERROR_LED_PIN, LOW);
       delay(500);
     }
     delay(1000);  // LED点滅の間隔
   }
 }
 
 void setup()
 {
   pinMode(ERROR_LED_PIN, OUTPUT);
 
   if (!initializeSensor()) {
     // 例えば、3回点滅でセンサ初期化エラーを示す
     Serial.println(F("Sensor initialization failed"));
     errorHalt(3);
   }
 }



ウォッチドッグタイマを使用した再起動

ウォッチドッグタイマによる再起動は、一時的な問題で初期化が失敗した場合に有効である。

ただし、根本的な問題が解決されない限り、再起動ループに陥る可能性があることに注意する。

 #include <avr/wdt.h>
 
 void setup()
 {
   if (!initializeSensor()) {
     Serial.println(F("Sensor initialization failed"));
     Serial.println(F("Triggering watchdog reset..."));
 
     // ウォッチドッグタイマを設定 (15[ms]で再起動)
     wdt_enable(WDTO_15MS);
     while(1) {}  // ウォッチドッグタイマが開始するまで待機
   }
 
   // 正常初期化時はウォッチドッグを無効化
   wdt_disable();
 }