Hur många avbrottsstift kan en Uno hantera?

Jag tittar på att använda en 7-kanals RC-mottagare med Arduino Uno R3. I dokumentationen nämns högst två avbrottsstift, medan jag på vissa andra bloggar har nämnt att använda upp till 20 stift som avbrott med PinChangeInt-biblioteket. Så hur många avbrott kan Arduino hantera inbyggt? Och skiljer sig detta från hur många som kan hanteras med programvarusupport som PinChangeInt?

Svar

Det finns två typer av ” avbrottstyp avbryter. De externa avbrotten, varav två finns på Uno. De kallas 0 och 1, men de hänvisar till digitala stift 2 och 3 på tavlan. Dessa kan konfigureras för att upptäcka stigande, fallande, förändring (stigande eller fallande) eller LÅG.

Utöver det finns ”stiftbyte” -avbrott, som detekterar en ändring av stifttillståndet i någon av de 20 stiften (A0 till A5 och D0 till D13). Dessa stiftbytesavbrott är också hårdvarubaserade så i sig kommer de att vara lika snabba som de externa avbrotten.

Båda typerna är lätt att använda på registernivå, men standard IDE inkluderar attachInterrupt (n) och detachInterrupt (n) som förenklar gränssnittet för externa avbrott. Du kan också använda Stiftbytebibliotek för att förenkla stiftbytesavbrott.

Men stänger av biblioteket i en minut, vi kan fastställa att avbrottsavbrott kan vara lika snabba eller snabbare än externa avbrott. För det första, även om stiftbyte avbryter arbete på satser med stift, behöver du inte aktivera hela satsen. Om du till exempel vill upptäcka ändringar på stift D4 räcker detta:

Exempel skiss:

 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 () { }  

Min testning tyder på att det tog 1,6 µs för ”testet ”pin (pin 5) för att reagera på en förändring på interrupt pin (pin 4).


Nu om du tar den enkla (lat?) metoden och använder attachInterrupt () hittar du resultaten är långsammare, inte snabbare.

Exempelkod:

 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 att byta ut teststiftet, mycket mer än 1,6 µs ovan. Varför? Eftersom koden kompilatorn måste generera för den ”generiska” avbrottshanteraren måste spara alla tänkbara register inträde till ISR och sedan återställa dem (pop dem) innan de återvänder. Plus att det finns omkostnader för ett annat funktionssamtal.


Nu kan vi komma runt det genom att undvika attachInterrupt () och göra det själva:

 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 är det snabbaste av dem alla vid 1,52 µs – det ser ut som om en klockcykel har sparats någonstans.


Det finns dock en försiktighet för avbrott i stiftbyte. De är grupperade, så om du vill ha avbrott på många stift måste du testa inuti avbrottet vilken en ändrade . Du kan göra det genom att spara den tidigare stiftstatusen och jämföra den med den nya stiftstatusen. Detta är inte nödvändigtvis särskilt långsamt, men ju fler stift du behöver kontrollera, desto långsammare blir det.

Satserna är:

  • A0 till A5
  • D0 till D7
  • D8 till D13

Om du bara vill ha ett par fler avbrottsstift kan du undvika testning genom att bara välja att använda stift från olika satser (t.ex. D4 och D8).


Mer information på http://www.gammon.com.au/interrupts

Svar

Det finns två typer av avbrott. Vad Arduino Playground sa:

Processorn i hjärtat av vilken Arduino som helst har två olika typer av avbrott: ”extern” och ”stiftbyte”. Det finns bara två externa avbrottsstift på ATmega168 / 328 (dvs. i Arduino Uno / Nano / Duemilanove), INT0 och INT1, och de mappas till Arduino-stift 2 och 3. Dessa avbrott kan ställas in för att utlösas vid RISING eller FALLANDE signalkanter eller på låg nivå. Utlösarna tolkas av hårdvara och avbrottet är väldigt snabbt. Arduino Mega har några fler externa avbrottsstift tillgängliga.

Å andra sidan kan avbrottsbrytningarna aktiveras på många fler stift. För ATmega168 / 328-baserade Arduinos kan de aktiveras på någon eller alla 20 av Arduinos signalstift; på ATmega-baserade Arduinos kan de aktiveras på 24 stift. De utlöses lika vid RISING- eller FALLING-signalkanter så det är upp till avbrottskoden att ställa in rätt stift för att ta emot avbrott, för att avgöra vad som hände (vilken stift? … steg signalen eller föll?) och att hantera den ordentligt.Vidare är stiftbytesavbrotten grupperade i 3 ”portar” på MCU, så det finns bara 3 avbrottsvektorer (underrutiner) för hela stiftkroppen. Detta gör jobbet att lösa åtgärden vid en enda avbrott ännu mer komplicerat.

I grund och botten är de externa avbrotten extremt snabba eftersom de alla är hårdvarubaserade Det finns emellertid också avbrott i stiftbyte, men de verkar vara mycket långsammare eftersom de mestadels är programvarubaserade.

tl; dr: de 20 avbrottsstiften tillsammans är mycket långsammare. De två avbrottsstiften är de snabbaste och mest effektiva.


EDIT: Jag tittade bara på databladet och det står att ett stiftbytesavbrott utlöses för någon av de valda stiften utan någon indikation på vilken stift som har ändrats (även om den är uppdelad i tre avbrottsvektorer).

  • För externa avbrott kommer den att berätta stift 3 har precis ändrats
  • För pin-ändring ”säger du en pin har ändrats som du övervakade!

Som du kan se, en stiftbytesavbrott lägger till mycket overhead i ISR som du måste hantera genom att lagra tidigare tillstånd och se om det är den stift du är orolig för. Det kan vara bra för viloläge, men det är bättre att använda de externa avbrotten.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *