İki tip "pin değiştirme" tipi kesinti vardır. Uno'da iki tane olan harici kesintiler. Bunlar 0 ve 1 olarak adlandırılır, ancak karttaki 2 ve 3 dijital pimlerini ifade ederler. Bunlar yükselen, düşen, değişim (yükselen veya düşen) veya DÜŞÜK algılamak için yapılandırılabilir .
Buna ek olarak, 20 pimden herhangi birinde (A0 ila A5 ve D0 ila D13) pim durumunda bir değişiklik tespit eden "pim değiştirme" kesintileri vardır. Bu pim değiştirme kesintileri de donanım tabanlıdır, bu nedenle kendi içlerinde dış kesintiler kadar hızlı olacaktır.
Her iki tür de kayıt düzeyinde biraz kullanışlıdır, ancak standart IDE, arabirimi harici kesintilere basitleştiren attachInterrupt (n) ve detachInterrupt (n) içerir. Pim değiştirme kesintilerini basitleştirmek için Pim Değiştirme Kitaplığı'nı da kullanabilirsiniz .
Bununla birlikte, bir dakika boyunca kütüphaneden uzaklaşarak, pin değiştirme kesintilerinin harici kesintilerden daha hızlı veya daha hızlı olabileceğini belirleyebiliriz. Bir kere, pin değiştirme kesintileri pim grupları üzerinde çalışsa da, tüm partiyi etkinleştirmeniz gerekmez. Örneğin, D4 pimindeki değişiklikleri tespit etmek istiyorsanız, bu yeterli olacaktır:
Örnek çizim:
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 ()
{
}
Testlerim, "test" piminin (pim 5) kesme pimindeki (pim 4) bir değişikliğe tepki vermesinin 1.6 µs sürdüğünü göstermektedir.
Şimdi basit (tembel?) Yaklaşımı kullanır ve attachInterrupt () kullanırsanız, sonuçların daha yavaş değil daha yavaş olduğunu göreceksiniz.
Örnek kod:
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 ()
{
}
Bu, test pimini değiştirmek için 3.7 µs alır, yukarıdaki 1.6 µs'den çok daha fazla. Neden? Derleyicinin "genel" kesme işleyicisi için üretmesi gereken kod, akla gelebilecek her bir kaydı ISR'ye girdikten sonra kaydetmeli (onları itmeli) ve geri dönmeden önce (onları pop) geri yüklemelidir. Ayrıca başka bir işlev çağrısının ek yükü vardır.
Artık attachInterrupt () yönteminden kaçınarak ve bunu kendimiz yaparak çözebiliriz:
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'de en hızlısı bu - bir saat döngüsü bir yere kaydedilmiş gibi görünüyor.
Pim değişikliği kesintileri için bir uyarı var. Bunlar topludır, bu yüzden çok sayıda pimde kesmeler yapmak istiyorsanız, hangisinin değiştiği kesmenin içinde test etmeniz gerekir . Önceki pin durumunu kaydedip yeni pin durumu ile karşılaştırarak bunu yapabilirsiniz. Bu özellikle yavaş değildir, ancak kontrol etmeniz gereken daha fazla iğne, daha yavaş olacaktır.
Partiler:
- A0 - A5
- D0 - D7
- D8 ila D13
Sadece birkaç kesme pimi istiyorsanız, sadece farklı gruplardan (örneğin D4 ve D8) pimler kullanmayı seçerek herhangi bir testten kaçınabilirsiniz.
Daha fazla ayrıntı için http://www.gammon.com.au/interrupts