Mă uit la utilizarea unui receptor RC cu 7 canale cu Arduino Uno R3. În documentație, sunt menționate maximum 2 pini de întrerupere, în timp ce pe anumite alte bloguri am văzut mențiuni despre utilizarea a până la 20 de pini ca întreruperi, cu biblioteca PinChangeInt. Deci, câte întreruperi poate gestiona nativ Arduino? Și este diferit acest lucru de cât de multe pot fi tratate cu suport software, cum ar fi PinChangeInt?
Răspuns
Există două tipuri de ” pin change „întrerupe tipul. Întreruperile externe, dintre care există două pe Uno. Acestea se numesc 0 și 1, cu toate acestea se referă la pinii digitali 2 și 3 de pe placă. Acestea pot fi configurate pentru a detecta creșterea, scăderea, schimbarea (creșterea sau scăderea) sau LOW.
În plus, există și întreruperi de „schimbare a pinului”, care detectează o modificare a stării pinului în oricare dintre cei 20 de pini (A0 la A5 și D0 la D13). Aceste întreruperi de modificare a pinului sunt, de asemenea, bazate pe hardware , astfel încât, în sine, vor fi la fel de rapide ca întreruperile externe.
Ambele tipuri sunt ușor de utilizat la nivel de registru, dar IDE standard include attachInterrupt (n) și detachInterrupt (n) care simplifică interfața cu întreruperile externe. De asemenea, puteți utiliza Biblioteca de schimbare a pinilor pentru a simplifica întreruperile de modificare a pinului.
Cu toate acestea, îndepărtându-ne de bibliotecă pentru un minut, poate stabili că întreruperile schimbării pinului pot fi la fel de rapide sau mai rapide decât întreruperile externe. În primul rând, deși schimbarea pinului întrerupe funcționarea pe loturi de pini, nu trebuie să activați întregul lot. De exemplu, dacă doriți să detectați modificări pe pinul D4, acest lucru va fi suficient:
Exemplu schiță:
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 () { }
Testarea mea indică faptul că a fost nevoie de 1,6 µs pentru „test „pin (pin 5) pentru a reacționa la o schimbare a pinului de întrerupere (pin 4).
Acum, dacă luați abordarea simplă (leneșă?) și utilizați attachInterrupt () veți găsi rezultatele sunt mai lente, nu mai rapide.
Exemplu de cod:
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 () { }
Acest lucru necesită 3,7 µs pentru a schimba pinul de testare, mult mai mult decât 1,6 µs de mai sus. De ce? Deoarece codul pe care compilatorul trebuie să îl genereze pentru gestionarul de întreruperi „generic” trebuie să salveze fiecare registru posibil (apăsați-le) pe intrare în ISR, apoi restaurați-le (deschideți-le) înainte de a vă întoarce. În plus, există cheltuielile generale pentru o altă funcție de apel.
Acum putem rezolva acest lucru evitând attachInterrupt () și făcându-l singuri:
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 () { }
Aceasta este cea mai rapidă dintre toate la 1,52 µs – se pare că un ciclu de ceas a fost salvat undeva.
Există totuși o singură avertizare, pentru întreruperile de modificare a pinului. Acestea sunt grupate, deci dacă doriți să aveți întreruperi pe o mulțime de pini, trebuie să testați în interiorul întreruperii pe care o schimbați . Puteți face acest lucru salvând starea anterioară a pinului și comparându-l cu noua stare a pinului. Acest lucru nu este neapărat deosebit de lent, dar cu cât trebuie să verificați mai mulți pini, cu atât ar fi mai lent.
Loturile sunt:
- A0 până la A5
- D0 la D7
- D8 la D13
Dacă doriți doar încă câteva pini de întrerupere, puteți evita orice testare doar alegând să utilizați pini din diferite loturi (de exemplu, D4 și D8).
Mai multe detalii la http://www.gammon.com.au/interrupts
Răspuns
Există două tipuri de întreruperi. Ce a spus Arduino Playground :
Procesorul din centrul oricărui Arduino are două tipuri diferite de întreruperi: „extern” și „schimbare pin”. Există doar doi pini de întrerupere externi pe ATmega168 / 328 (adică în Arduino Uno / Nano / Duemilanove), INT0 și INT1 și sunt mapați la pinii Arduino 2 și 3. Aceste întreruperi pot fi setate să se declanșeze pe RISING sau Marginile semnalului în cădere sau la un nivel scăzut. Declanșatoarele sunt interpretate de hardware, iar întreruperea este foarte rapidă. Arduino Mega are încă câțiva pini de întrerupere externi disponibili.
Pe de altă parte, întreruperile de schimbare a pini pot fi activate pe mai mulți pini. Pentru Arduino-uri bazate pe ATmega168 / 328, acestea pot fi activate pe oricare sau pe toate cele 20 de pini de semnal Arduino; pe Arduino-uri pe bază de ATmega pot fi activate pe 24 de pini. Sunt declanșate în mod egal pe marginile semnalelor RISING sau FALLING, deci depinde de codul de întrerupere pentru a seta pinii corespunzători pentru a primi întreruperi, pentru a determina ce s-a întâmplat (care pin? … a crescut sau a scăzut semnalul?) și să îl gestionați corect.Mai mult, întreruperile de schimbare a pinilor sunt grupate în 3 „porturi” pe MCU, deci există doar 3 vectori de întrerupere (subrutine) pentru întregul corp de pini. Acest lucru face ca sarcina de a rezolva acțiunea pe o singură întrerupere să fie și mai complicată.
Practic, întreruperile externe sunt extrem de rapide, deoarece acestea sunt toate bazate pe hardware Cu toate acestea, există și întreruperile de modificare a pinului, dar acestea par a fi mult mai lente, deoarece acestea sunt în mare parte bazate pe software.
tl; dr: cei 20 de pini de întrerupere împreună sunt mult mai lenti. Cei 2 pini de întrerupere sunt cei mai rapizi și mai eficienți.
EDIT: Tocmai m-am uitat la foaia tehnică și se spune că se declanșează o întrerupere a modificării pinului pentru oricare dintre pinii selectați, fără indicație de care pin s-a schimbat (deși este împărțit în trei vectori de întrerupere).
- Pentru întreruperile externe, vă va spune pinul 3 tocmai s-a schimbat
- Pentru modificarea PIN-ului, vă va spune un PIN modificat pe care îl monitorizați!
După cum puteți vedea, un întreruperea schimbării pinului adaugă o mulțime de cheltuieli generale în ISR pe care trebuie să le gestionați stocând stările anterioare și văzând dacă este „pinul” de care sunteți îngrijorat. Ar putea fi bine pentru o stare de somn, dar este mai bine să utilizați întreruperile externe.