Hobby Science&Experiment

愛と工作の日々

趣味でやっている工作や勉強したことのメモ書きです。

Arduinoで割り込みISR()を使うコード例(1)ボタン押下監視を割り込みで

Arduinoでタクトスイッチの押下を監視したいのですが、一回のloopが長い場合、degitalread(polling)の丁度いいタイミングでスイッチを押さないといけなかったりします。先日作ったドラムマシンが一回のループが長い典型例(1秒越え)でした。
そこでInterruptというのを使うと、メインのループに割り込んだ操作が行えるようなのでサンプルコード試してみました。あまり私にとって分りやすい情報が多くなく、現時点では仕組みをあまり理解しておりませんが、動いたので記しておきます。

Arduino側の配線

9pin、13pinにLEDを接続、2pinにタクトスイッチを接続しています。

コードと動作

こちらのコードを一部改変しました。メインのloop内ではLEDが500ms周期で明滅します。一方でISR(INT0_vect)という関数?が定義されており、メインループとは独立にボタンが押された瞬間に実行されます。ISRが実行された場合13pin(ledPin_ISR)のON/OFFが切り替わり、ついでにCHANNEL=1が代入されます。

#include <avr/io.h>
#include <avr/interrupt.h>

byte ledPin = 9;
byte ledPin_ISR = 13;
byte BUTTON = 2;
boolean CHANNEL =0;

void setup(void)
{
  Serial.begin( 9600 );
  pinMode(BUTTON, INPUT);
  digitalWrite(BUTTON, HIGH);    // Enable pullup resistor
  pinMode(ledPin_ISR, OUTPUT);
  digitalWrite(ledPin_ISR, LOW);
  
  EICRA |= (1 << ISC01);    // Trigger on falling edge
  EIMSK |= (1 << INT0);     // Enable external interrupt INT0
  sei();                    // Enable global interrupts
}

// Interrupt Service Routine attached to INT0 vector
ISR(INT0_vect)
{
  digitalWrite(ledPin_ISR, !digitalRead(ledPin_ISR));    // Toggle LED on pin 13
  CHANNEL = 1;
  Serial.println("Interrupted!");
}

void loop(void)
{
    analogWrite(ledPin, 30);
    delay(500);  
    analogWrite(ledPin, 255);
    delay(500);
    Serial.println(CHANNEL);
    CHANNEL=0;
}

疑問と調べたこと

このコードの中で、どの部分が2pinをISRの実行トリガーに指定しているのか調べてみました。怪しい部分は以下の部分です。

  EICRA |= (1 << ISC01);    // Trigger on falling edge
  EIMSK |= (1 << INT0);     // Enable external interrupt INT0
  sei();                    // Enable global interrupts

ググってみたところ、
こちらのサイトにて説明が見つかりました。とりあえず2pinと3pinが使用可能なようですね。

  • EICRAは、割り込みの検出方法を制御
  • EIMSK(外部割り込みマスクレジスタ)は、外部割り込みを有効または無効にする
  • Arduino Unoでは、INT0(ピン2)とINT1(ピン3)を使用できる
  • ISC01とISC00はINT0(ピン2)の状態を制御
  • ISC11とISC10の組み合わせは、INT1(ピン3)の状態を制御

課題

・複数ボタンを監視したい場合の方法が分からない。
・アナログピンでも使えるのかな?