LoginSignup
3
2

More than 5 years have passed since last update.

ファームウェア、外部信号取り込みの注意点

Posted at

Arduino、IoTのおかげでファームウェアの活躍の場が増えています。
ファームウェアは時間に対してシビア。モーターの回転パルスを取得して速度検出、タイマー割り込みで一定間隔で発光など。

この外部信号処理の扱いを間違えると、機能追加でプログラムが大きくなった時に「あれ、信号、取得できてなくない?」という、時限爆弾になります。

パルス数の取得

目的

外部からのパルス数を数える(たとえば、モーター回転速度など)

NG1: メインルーチンで頑張る

割り込みを使わなくてもできる!というモチベーションで行うもの。

Arduino
int pin = 13;
volatile int pin_state = LOW;   // パルス入力ピンの状態保持
unsigned int cnt = 0;  // パルスカウンター

void setup()
{
  pinMode(pin, INPUT);
}

void loop()
{
  /*
    色々な処理
  */

  int pin_now;
  pin_now = digitalRead(pin);  // パルス信号入力ピン読み込み

  if ( pin_now != pin_state ){
    // ピンの状態が遷移
    pin_state = pin_now;

    if ( pin_now == HIGH ){
      cnt++;  // ピンがLOWからHIGHになったので、カウントアップ
    }
  }
}

何が問題か

メインルーチン(上記の loop 関数)で処理を行う場合、色々な処理 が問題になる可能性があります。
作り始めはちゃんと機能していても、機能追加でメインルーチンはどんどん重くなる方向です。そしてある時、この色々な処理をしているうちに、パルスが立ち上がり、立下がる、という状況が起きます。認識できなくなります。

NG2: 割り込み内で色々な処理

「xx回に一回はこれをやる」といったとき、割り込み内でやるパターン

C
int pin = 13;
volatile int pin_state = LOW;

void pluse()
{
  cnt++;

  if ( cnt == 10 ){
    /* 
      色々な処理
    */
  }
}


void setup()
{
  attachInterrupt(0, pluse, RISING);
}

void loop()
{
} 

何が問題か

これも、色々な処理 が、次のパルスが来るまでに重くなれば間に合わなくなります。
特に、特にこのパターンは色々形を変えて、入り込んできます。油断すると、処理を書いてしまう場所です。

おすすめパターン

割り込み処理内はとにかくシンプルに。基本はフラグ処理。必要な変数はglobal変数に格納

C
boolean flag = false;
volatile int pin_state = LOW;

void pluse()
{
  cnt++;

  if ( cnt == 10 ){
    flag = true;
  }
}


void setup()
{
  attachInterrupt(0, pluse, RISING);
}

void loop()
{
  if ( flag )
  {
    /*
      色々な処理
    */
    flag = false;
  }
}

まとめ

言いたいことは簡単ですが、
「プログラムはメインルーチンで。割り込み処理内は最低限の処理のみ。」
です。
この基本からずれたコードを仕事でも見かけます。後々問題を起こす危険のある時限爆弾は、未然に防ぎたいです。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2