【工事中】このサイトは現在作成中です。正式公開までしばらくお待ちください。

delay() を使わない『モメンタム(加減速)』の処理

 鉄道模型の実感的な走行に欠かせないのが、実車のような慣性を再現する「モメンタム(加減速制御:CV3/CV4)」機能です。スロットルを急に上げても「じわっと加速」し、ダイヤルを戻しても「じわっと滑らかに減速・停止」するあの動きです。

 プログラミング初心者向けの電子工作(Arduinoなど)解説書では、時間を待つために delay(50);(50ミリ秒待つ)といった関数がよく使われます。しかし、ワンコインデコーダXのようなDCCデコーダの内部でこれを行うことは「絶対にあってはならない処理」とされています。

 DCC信号の受信と滑らかな加減速を同時に、完全に並行して行うための「ノンブロッキング(非同期)処理」の設計思想を紐解いてみましょう。

なぜデコーダで delay() を使ってはならないのか?

 delay() 関数は、指定された時間が経過するまで「CPUに何もさせずにその場で足止め(ループ)させる」処理です。これを「ブロッキング(占有)処理」と呼びます。

 仮に、速度を1ステップ変化させるごとに delay(20);(20ミリ秒待つ)を挟んで加速させたとしましょう。
人間にとってはわずか0.02秒という一瞬ですが、線路から流れてくるDCC信号は1辺が数10〜100マイクロ秒(1マイクロ秒は1ミリ秒の1000分の一)という超高速なパルスです

 もしモメンタムの途中で delay() によってCPUが20ミリ秒も足止めされたら、デコーダはその間、線路の信号を完全に無視することになります。結果として、コントローラから届く「ライトを消せ」「緊急停止しろ」といったDCCパケットを大量に取りこぼし、最悪の場合はデコーダが暴走・フリーズしてしまいます。

1msタイマーによるカウントダウン方式(motor_ctrl.c)

 ワンコインデコーダXでは、CPUを1マイクロ秒すら引き止めない「ノンブロッキング(非同期)設計」を採用しています。

 メインループ(main.c)は常にDCCパケットの受信に全神経を集中させて全力で回り続け、加減速のタイマー演算はすべてハードウェアのタイマー割り込みが管理する「1ms定期タスク(Process_1ms_Timer_Tasks)」に委ねられています。

内部ロジックの仕組み
  • コマンドステーションから新しい速度(目標速度:target_speed)が届くと、メイン処理は変数に数字を書き込むだけですぐに次のパケット待ちに戻ります。(待ち時間はゼロ)。
  • 一方、1msごとに呼び出される定期タスクの中では、以下のようなカウントダウン処理が密かに行われています。
c
void Process_1ms_Timer_Tasks(void) {
    static uint16_t momentum_counter = 0;

    // 現在の速度と、目標の速度にズレがあるかチェック
    if (current_speed != target_speed) {
        momentum_counter++;

        // CV3(加速)またはCV4(減速)で設定された時間に達したか判定
        uint16_t interval = Read_CV(3) * 10; // CVの値を時間に変換
        if (momentum_counter >= interval) {
            momentum_counter = 0; // カウンタをリセット

            // 1ステップだけ速度を目標に近づける
            if (current_speed < target_speed) current_speed++;
            else current_speed--;
        }
    }
}

 このプログラムには、時間を止めて待つ命令(delay)がどこにもありません。「1msごとにここを通りかかった際、もし設定時間が経っていたら速度の変数を1だけ書き換える」という処理をしています。

 これにより、CPUを一切拘束することなく、「DCCパケットの100%完全受信」と「1ms単位の超滑らかな加減速」という2つのタスクを、まるで同時に実行しているかのようにマルチタスク風に処理しているのです。

組み込みプログラミングの応用

 ワンコインデコーダXのソースコード(motor_ctrl.c)が極めて短い行数で書かれているにもかかわらず、どんな複雑なレイアウトでもカチカチと完璧に動作するのは、この「割り込み(Interrupt)とノンブロッキング処理」が徹底されているためです。

 自分でファームウェアを改造して新機能(例えば、ライトの残光エフェクトや踏切の自動音出しなど)を追加したくなった時も、この「1ms定期タスクの中にカウンターを作る」というルールさえ守れば、デコーダの基本性能を落とすことなく、いくらでも機能を拡張していくことができます!