Jeg ser på å bruke en 7-kanals RC-mottaker med Arduino Uno R3. I dokumentasjonen er det nevnt maksimalt 2 avbruddspinner, mens jeg på visse andre blogger har sett omtaler å bruke opptil 20 pinner som avbrudd, med PinChangeInt-biblioteket. Så hvor mange avbrudd kan Arduino håndtere naturlig? Og er dette forskjellig fra hvor mange som kan håndteres med programvarestøtte som PinChangeInt?
Svar
Det er to typer » pin-endringstype avbryter. De eksterne forstyrrelsene, hvorav det er to på Uno. De kalles 0 og 1, men de refererer til digitale pinner 2 og 3 på tavlen. Disse kan konfigureres til å oppdage stigende, fallende, endring (stigende eller fallende) eller LAV.
I tillegg til det er «pinneskift» -avbrudd, som oppdager en endring i pinnetilstanden i en av de 20 pinnene (A0 til A5, og D0 til D13). Disse pin-endringsavbruddene er også maskinvarebasert så i seg selv vil det være like raskt som de eksterne avbruddene.
Begge typene er lett å bruke på registernivå, men standard IDE inkluderer attachInterrupt (n) og detachInterrupt (n) som forenkler grensesnittet til eksterne avbrudd. Du kan også bruke Pin Change Library for å forenkle pin-endringsavbrudd.
Imidlertid styrer du biblioteket i et minutt, vi kan fastslå at pinneskiftavbrudd kan være like raske eller raskere enn eksterne avbrudd. For det første, selv om pin-endring avbryter arbeidet med batcher av pins, trenger du ikke å aktivere hele batchen. Hvis du for eksempel vil oppdage endringer på pin D4, vil dette være tilstrekkelig:
Eksempel skisse:
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 () { }
Testingen min indikerer at det tok 1,6 µs for «testen «pin (pin 5) for å reagere på en endring på interrupt pin (pin 4).
Nå hvis du tar den enkle (late?) tilnærmingen og bruker attachInterrupt () finner du resultatene er tregere, ikke raskere.
Eksempelkode:
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 () { }
Det tar 3,7 µs å skifte testpinnen, mye mer enn 1,6 µs ovenfor. Hvorfor? Fordi koden kompilatoren må generere for den «generiske» avbryterbehandleren, må du lagre alle tenkelige register (skyv dem) på inngang til ISR, og deretter gjenopprette dem (pop dem) før du returnerer. Pluss at det er overhead for en annen funksjonsanrop.
Nå kan vi omgå det ved å unngå attachInterrupt () og gjøre det selv:
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 () { }
Det er den raskeste av dem alle på 1,52 µs – det ser ut til at en kloksyklus ble lagret et sted.
Det er imidlertid en advarsel for avbrudd med pin-endring. De er batches, så hvis du vil ha avbrudd på mange pinner, må du teste inne i avbruddet hvilken en endret . Du kan gjøre det ved å lagre forrige pin-status, og sammenligne den med den nye pin-statusen. Dette er ikke nødvendigvis spesielt tregt, men jo flere pinner du trenger å sjekke, desto tregere vil det være.
Partiene er:
- A0 til A5
- D0 til D7
- D8 til D13
Hvis du bare vil ha et par flere avbruddspinner, kan du unngå testing ved å velge å bruke pinner fra forskjellige batcher (f.eks. D4 og D8).
Flere detaljer på http://www.gammon.com.au/interrupts
Svar
Det er to typer avbrudd. Hva Arduino Playground sa:
Prosessoren i hjertet av enhver Arduino har to forskjellige typer avbrudd: «ekstern» og «pin-endring». Det er bare to eksterne avbryterpinner på ATmega168 / 328 (dvs. i Arduino Uno / Nano / Duemilanove), INT0 og INT1, og de er kartlagt til Arduino pinner 2 og 3. Disse avbruddene kan settes til å utløse på RISING eller FALLENDE signalkanter, eller på lavt nivå. Utløserne tolkes av maskinvare, og avbruddet er veldig raskt. Arduino Mega har noen flere eksterne avbrytingspinner tilgjengelig.
På den annen side kan pin-endringsavbrudd aktiveres på mange flere pinner. For ATmega168 / 328-baserte Arduinos, kan de aktiveres på hvilken som helst eller alle 20 av Arduinos signalpinner; på ATmega-baserte Arduinos kan de aktiveres på 24 pinner. De utløses likt på RISING eller FALLING signalkanter, så det er opp til avbruddskoden å stille inn riktige pinner for å motta avbrudd, for å bestemme hva som skjedde (hvilken pin? … steg signalet, eller falt det?), og for å håndtere det riktig.Videre er pin-endringsavbruddene gruppert i 3 «porter» på MCU, så det er bare 3 avbruddsvektorer (subrutiner) for hele kroppen av pins. Dette gjør jobben med å løse handlingen ved en enkelt avbrudd enda mer komplisert.
I utgangspunktet er de eksterne avbruddene ekstremt raske siden de alle er maskinvarebaserte Imidlertid er det også avbrudd med pin-skift, men de ser ut til å være mye tregere fordi de for det meste er programvarebasert.
tl; dr: de 20 avbruddspinnene sammen er mye langsommere. De to avbruddspinnene er de raskeste og mest effektive.
EDIT: Jeg så nettopp på databladet og det står at en pin-endringsavbrudd utløses for noen av pinnene som er valgt uten indikasjon på hvilken pin har endret seg (selv om den er delt inn i tre avbruddsvektorer).
- For eksterne avbrudd vil den fortelle deg pin 3 nettopp endret
- For pin change it «fortell deg en pin endret som du overvåket!
Som du kan se, en pin-endringsavbrudd legger til mye overhead i ISR som du må håndtere ved å lagre tidligere tilstander og se om det er pinnen du er bekymret for. Det kan være greit for en hvilemodus, men det er bedre å bruke de eksterne avbruddene.