Ada dua jenis interupsi tipe "perubahan pin". Interupsi eksternal, yang ada dua di Uno. Mereka disebut 0 dan 1, namun mereka merujuk pada pin digital 2 dan 3 di papan tulis. Ini dapat dikonfigurasi untuk mendeteksi naik, turun, berubah (naik atau turun) atau RENDAH.
Selain itu, interupsi "perubahan pin", yang mendeteksi perubahan ke status pin di salah satu dari 20 pin (A0 ke A5, dan D0 ke D13). Interupsi penggantian pin ini juga berbasis perangkat keras sehingga, dalam dirinya sendiri, akan secepat interupsi eksternal.
Kedua jenis ini sedikit rumit untuk digunakan pada level register, tetapi IDE standar mencakup attachInterrupt (n) dan detachInterrupt (n) yang menyederhanakan antarmuka ke interupsi eksternal. Anda juga dapat menggunakan Perpustakaan Perubahan Pin untuk menyederhanakan interupsi perubahan pin.
Namun, menjauhi perpustakaan selama satu menit, kita dapat menetapkan bahwa interupsi penggantian pin bisa lebih cepat, atau lebih cepat, daripada interupsi eksternal. Untuk satu hal, meskipun perubahan pin mengganggu bekerja pada batch pin, Anda tidak harus mengaktifkan seluruh batch. Misalnya, jika Anda ingin mendeteksi perubahan pada pin D4, ini sudah cukup:
Contoh sketsa:
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 ()
{
}
Pengujian saya menunjukkan bahwa butuh 1,6 μs untuk pin "test" (pin 5) untuk bereaksi terhadap perubahan pada pin interrupt (pin 4).
Sekarang jika Anda mengambil pendekatan sederhana (malas?) Dan menggunakan attachInterrupt () Anda akan menemukan hasilnya lebih lambat, tidak lebih cepat.
Kode contoh:
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 ()
{
}
Ini membutuhkan 3,7 μs untuk mengubah pin tes, jauh lebih banyak daripada 1,6 μs di atas. Mengapa? Karena kode yang harus dikompilasi oleh kompiler untuk penangan interupsi "generik" harus menyimpan setiap register yang dapat dibayangkan (dorong mereka) saat masuk ke ISR, dan kemudian pulihkan (pop) sebelum kembali. Plus ada overhead panggilan fungsi lain.
Sekarang kita dapat mengatasinya dengan menghindari attachInterrupt () dan melakukannya sendiri:
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 ()
{
}
Itu adalah yang tercepat dari semuanya pada 1,52 μs - sepertinya satu siklus clock disimpan di suatu tempat.
Namun ada satu peringatan, untuk interupsi pin-change. Mereka batch, jadi jika Anda ingin memiliki interupsi pada banyak pin, Anda perlu menguji di dalam interupsi mana yang diubah. Anda bisa melakukannya dengan menyimpan status pin sebelumnya, dan membandingkannya dengan status pin baru. Ini belum tentu sangat lambat, tetapi semakin banyak pin yang perlu Anda periksa, semakin lambat itu.
Batch adalah:
- A0 ke A5
- D0 hingga D7
- D8 ke D13
Jika Anda hanya ingin beberapa pin interupsi lagi, Anda dapat menghindari pengujian dengan hanya memilih untuk menggunakan pin dari batch yang berbeda (mis. D4 dan D8).
Lebih detail di http://www.gammon.com.au/interrupts