ESPr Developerでの割り込み処理

ESPr Developer をIoTで使う場合、外から取り込んだ信号をトリガーとして処理を行なったり、一定時間ごとに処理を行なったりすることが多くあります。

このような用途に対し、これまではloop関数の中で直接対処していましたが、今回、「割り込み処理」について少し調べたのでまとめておきます。

タイマー割り込み

ESPr Developerでタイマー割り込みを行う方法は、以下のとおりです。

【使用例】

#include <Ticker.h>
Ticker ticker;

void function() {
  // 定期的な処理
}

void setup() {
  ticker.attach(30, function);
}

【主な関数】

  • ticker.attach(sec, function):タイマー割り込み(秒単位)
  • ticker.attach_ms(msec, function):タイマー割り込み(msec単位)
  • ticker.detach():タイマー割り込みを停止
    • sec:割り込み時間(sec単位)
    • msec:割り込み時間(msec単位)
    • function:割り込み発生時に呼び出す関数(割り込み関数)

なお、割り込み関数の中では、ネットワーク通信などの処理は行えません。
これを行うためには、割り込み関数の中でフラグを立て、loop関数内でフラグに応じて処理を行なったあと、フラグを落とします。

【使用例】

#include <Ticker.h>
Ticker ticker;

volatile boolean flag = false;

void function_flag() {
  flag = true;
}

void function_exec() {
  // 定期的な処理
  flag = false;
}

void setup() {
  ticker.attach(30, function_flag);
}

void loop() {
  if(flag) {
    function_exec();
  }
}
端子割り込み

入力端子の信号変化に応じて、割り込みを行う方法は、以下のとおりです。

【関数】

  • attachInterrupt(digitalPinToInterrupt(pin), function, mode)
    • pin:ピン番号 ※digitalPinToInterruptで「ピン番号」を「割り込み番号」に変換する。
    • function:割り込み発生時に呼び出す関数(割り込み関数)
      • 割り込み関数は引数と戻り値が不要なもののみ。
      • delay関数は機能しない。
      • millis関数の戻り値は増加しない。
      • シリアル通信により受信したデータは、失われる可能性がある。
      • 割り込み関数の中で値が変化する変数には、volatile修飾子をつけて宣言する。
    • mode:割り込みを発生させるトリガ
      • LOW:ピンがLOWのとき。
      • CHANGE:ピンが変化したとき。
      • RISING:ピンがLOWからHIGHに変化したとき。
      • FALLING:ピンがHIGHからLOWに変化したとき。

ESPr Developerでは、IO16以外のGPIO端子が、割り込みに使用できる模様です。

この関数では、入力端子の変化に応じて割り込みを行います。内部での処理結果に応じて割り込みを行いたい場合は、内部処理の結果を一旦外に出し、それを外部信号として再び取り込む必要があるようです。

 

これらを踏まえて、以下の処理を行うスケッチを作ってみました。

  • スイッチを押すと、LEDが点灯する。
  • 10秒たつと、LEDが消灯する。
  • LED点灯中にスイッチを押すと、それから10秒LEDが点灯し続ける。
#include <Ticker.h>
Ticker ticker;

volatile boolean state = false;

#define PIN_SW 12
#define PIN_LED 4

void onDetected() {
  if(state) {
    ticker.detach();
    ticker.attach(10, onTimer);
  } else {
    ticker.attach(10, onTimer);
    digitalWrite(PIN_LED, HIGH);
    state = true;
  }
}

void onTimer() {
  ticker.detach();
  digitalWrite(PIN_LED, LOW);
  state = false;
}

void setup() {
  pinMode(PIN_SW, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIN_SW), onDetected, RISING);

  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);
}

void loop() {
}