Arduino UnoR3で7チャンネルRCレシーバーを使用することを検討しています。ドキュメントには、最大2つの割り込みピンについての言及がありますが、他の特定のブログでは、PinChangeIntライブラリで最大20のピンを割り込みとして使用することについての言及を見てきました。では、Arduinoはネイティブにいくつの割り込みを処理できますか?また、これは、PinChangeIntなどのソフトウェアサポートで処理できる数とは異なりますか?
回答
2種類の “ピンチェンジ」タイプの割り込み。宇野に2つある外部割り込み。これらは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 () { }
私のテストでは、「テストに1.6 µsかかった」と示されています。 “ピン(ピン5)は、割り込みピン(ピン4)の変更に反応します。
ここで、単純な(遅延?)アプローチを使用して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つの注意点があります。それらはバッチ処理されているため、多数のピンで割り込みが必要な場合は、割り込みの内部をテストする必要があります 。以前のピンステータスを保存し、それを新しいピンステータスと比較することでこれを行うことができます。これは必ずしも特に遅いわけではありませんが、チェックする必要のあるピンが多いほど遅くなります。
バッチは次のとおりです。
- A0からA5
- D0からD7
- D8からD13
さらに2、3の割り込みピンが必要な場合は、異なるピンを使用することを選択するだけで、テストを回避できます。バッチ(例:D4およびD8)。
http://www.gammon.com.au/interrupts で詳細を確認してください。
回答
割り込みには2つのタイプがあります。 Arduino Playground のコメント:
Arduinoの中心にあるプロセッサには、「外部」と「ピン変更」の2種類の割り込みがあります。 ATmega168 / 328(つまり、Arduino Uno / Nano / Duemilanove)にはINT0とINT1の2つの外部割り込みピンしかなく、それらはArduinoピン2と3にマップされます。これらの割り込みは、RISINGまたは信号エッジの低下、または低レベル。トリガーはハードウェアによって解釈され、割り込みは非常に高速です。 Arduino Megaには、さらにいくつかの外部割り込みピンがあります。
一方、ピン変更割り込みは、さらに多くのピンで有効にできます。 ATmega168 / 328ベースのArduinoの場合、Arduinoの信号ピンのいずれかまたはすべてで有効にできます。ATmegaベースのArduinoでは、24ピンで有効にできます。これらは、RISINGまたはFALLING信号エッジで等しくトリガーされます。したがって、割り込みを受信するための適切なピンを設定し、何が起こったのか(どのピン?…信号が上昇または下降したか?)を判別し、それを適切に処理するのは、割り込みコード次第です。さらに、ピン変更割り込みはMCUの3つの「ポート」にグループ化されているため、ピン本体全体に対して3つの割り込みベクトル(サブルーチン)しかありません。これにより、単一の割り込みに対するアクションを解決する作業がさらに複雑になります。
基本的に、外部割り込みはすべてハードウェアベースであるため、非常に高速です。 。ただし、ピン変更割り込みもありますが、ほとんどがソフトウェアベースであるため、はるかに遅いようです。
tl; dr: 20個の割り込みピンを合わせるとはるかに遅くなります。2個の割り込みピンが最も速く最も効率的です。
編集:データシートを見たところ、選択されたピンの に対して、ピン変更割り込みがトリガーされたと表示されています。どのピンが変更されたか(ただし、3つの割り込みベクトルに分割されます)。
- 外部割り込みの場合、「ピン3が変更されたばかり
- ピン変更の場合は、監視していたピンが変更されたことを通知します!
ご覧のとおり、ピン変更割り込みは、以前の状態を保存し、それが「あなたが心配しているピン」であるかどうかを確認することによって処理しなければならないISRに多くのオーバーヘッドを追加します。スリープ状態では問題ないかもしれませんが、外部割り込みを使用することをお勧めします。