回答:
「ピン変更」タイプの割り込みには2つのタイプがあります。外部割り込み。そのうちの2つはUnoにあります。これらは0および1と呼ばれますが、ボード上のデジタルピン2および3を指します。これらは、上昇、下降、変化(上昇または下降)、またはLOW を検出するように構成できます。
それに加えて、20個のピン(A0からA5、およびD0からD13)のいずれかのピン状態への変更を検出する「ピン変更」割り込みがあります。これらのピン変更割り込みもハードウェアベースであるため、それ自体は外部割り込みと同じくらい高速です。
どちらのタイプもレジスタレベルで使用するには多少手間がかかりますが、標準IDEにはattachInterrupt(n)とdetachInterrupt(n)が含まれており、外部割り込みへのインターフェイスが簡素化されます。ピン変更ライブラリを使用して、ピン変更割り込みを簡素化することもできます。
ただし、ライブラリを1分間クリアすると、ピン変更割り込みが外部割り込みよりも速く、または速くなることを確認できます。まず、ピン変更割り込みはピンのバッチで機能しますが、バッチ全体を有効にする必要はありません。たとえば、ピンD4の変更を検出する場合は、これで十分です。
スケッチ例:
ISR (PCINT2_vect)
{
// handle pin change interrupt for D0 to D7 here
if (PIND & bit (4)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of PCINT2_vect
void setup ()
{
// pin change interrupt (example for D4)
PCMSK2 |= bit (PCINT20); // want pin 4
PCIFR |= bit (PCIF2); // clear any outstanding interrupts
PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7
pinMode (4, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
私のテストでは、「テスト」ピン(ピン5)が割り込みピン(ピン4)の変化に反応するのに1.6 µsかかったことを示しています。
これで、単純な(遅延?)アプローチを使用してattachInterrupt()を使用すると、結果は遅くなり、速くなりません。
サンプルコード:
void myInterrupt ()
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of myInterrupt
void setup ()
{
attachInterrupt (0, myInterrupt, CHANGE);
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
これには、テストピンの変更に3.7 µsかかります。これは上記の1.6 µsよりもはるかに長くなります。どうして?「汎用」割り込みハンドラー用にコンパイラーが生成する必要があるコードは、ISRへの入り口で考えられるすべてのレジスターを保存(プッシュ)し、次に戻る前にそれらを復元(ポップ)する必要があるためです。さらに、別の関数呼び出しのオーバーヘッドがあります。
attachInterrupt()を回避して自分で実行することで、この問題を回避できます。
ISR (INT0_vect)
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of INT0_vect
void setup ()
{
// activate external interrupt 0
EICRA &= ~(bit(ISC00) | bit (ISC01)); // clear existing flags
EICRA |= bit (ISC00); // set wanted flags (any change interrupt)
EIFR = bit (INTF0); // clear flag for interrupt 0
EIMSK |= bit (INT0); // enable it
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
これはすべて1.52 µsで最速です。1クロックサイクルがどこかに保存されたように見えます。
ただし、ピン変更割り込みについては、注意点が1つあります。あなたは、ピンの多くの割り込みを持つようにしたい場合は、あなたは割り込みの内側にテストする必要があるので、彼らは、バッチ処理されるかが変更します。以前のピンステータスを保存し、それを新しいピンステータスと比較することで、それを行うことができます。これは必ずしも特に遅いとは限りませんが、チェックする必要があるピンが多いほど遅くなります。
バッチは次のとおりです。
割り込みピンをさらに2つだけ必要とする場合は、異なるバッチ(D4とD8など)のピンを使用するだけでテストを回避できます。
割り込みには2つのタイプがあります。何Arduinoの遊び場は言いました:
Arduinoの中心にあるプロセッサには、「外部」と「ピン変更」の2種類の割り込みがあります。ATmega168 / 328(つまり、Arduino Uno / Nano / Duemilanove)には、INT0とINT1の2つの外部割り込みピンのみがあり、それらはArduinoピン2と3にマップされます。これらの割り込みは、RISINGまたは信号エッジの立ち下がり、または低レベル。トリガーはハードウェアによって解釈され、割り込みは非常に高速です。Arduino Megaには、さらにいくつかの外部割り込みピンがあります。
一方、ピン変更割り込みは、さらに多くのピンで有効にできます。ATmega168 / 328ベースのArduinoの場合、Arduinoの20本の信号ピンのいずれかまたはすべてで有効にできます。ATmegaベースのArduinoでは、24ピンで有効にできます。信号はRISINGまたはFALLING信号エッジで等しくトリガーされるため、割り込みコードによって適切なピンを設定して割り込みを受信し、何が起こったのかを判断します(どのピン?...信号が上昇または下降したのか?)適切に処理します。さらに、ピン変更割り込みはMCUの3つの「ポート」にグループ化されているため、ピン本体全体に対して3つの割り込みベクトル(サブルーチン)しかありません。これにより、単一の割り込みでアクションを解決する作業がさらに複雑になります。
基本的に、外部割り込みはすべてハードウェアベースであるため、非常に高速です。ただし、ピン変更割り込みもありますが、それらはほとんどソフトウェアベースであるため、はるかに遅いようです。
tl; dr: 20個の割り込みピンを一緒に使用すると非常に遅くなります。2つの割り込みピンは、最も高速で最も効率的です。
編集:データシートを見ると、ピン変更割り込みは、どのピンが変更されたかを示すことなく、選択されたピンのいずれかに対してトリガーされます(ただし、3つの割り込みベクトルに分割されます)。
ご覧のとおり、ピン変更割り込みは、以前の状態を保存し、それが心配しているピンであるかどうかを確認することにより、処理する必要があるオーバーヘッドをISRに追加します。スリープ状態には問題ないかもしれませんが、外部割り込みを使用する方が適切です。