Hoeveel interrupt-pinnen kan een Uno aan?

Ik kijk naar het gebruik van een 7-kanaals RC-ontvanger met de Arduino Uno R3. In de documentatie zijn er vermeldingen van maximaal 2 interrupt-pinnen, terwijl ik op bepaalde andere blogs vermeldingen heb gezien van het gebruik van maximaal 20 pinnen als interrupts, met de PinChangeInt-bibliotheek. Dus, hoeveel interrupts kan de Arduino native aan? En is dit anders dan hoeveel kunnen worden afgehandeld met softwareondersteuning zoals PinChangeInt?

Answer

Er zijn twee soorten ” pin change “type onderbreekt. De externe interrupts, waarvan er twee op de Uno zijn. Ze worden 0 en 1 genoemd, maar ze verwijzen naar digitale pinnen 2 en 3 op het bord. Deze kunnen worden geconfigureerd om stijgen, dalen, veranderen (stijgend of dalend) of LOW te detecteren.

Daarnaast zijn er “pin change” -onderbrekingen, die een verandering in de pin-status detecteren in een van de 20 pinnen (A0 tot A5 en D0 tot D13). Deze interrupts voor het wijzigen van de pincode zijn ook hardware-gebaseerd , dus op zichzelf zullen ze net zo snel zijn als de externe interrupts.

Beide typen zijn enigszins onhandig te gebruiken op registerniveau, maar de standaard IDE bevat attachInterrupt (n) en detachInterrupt (n) die de interface naar externe interrupts vereenvoudigen. U kunt ook de Pin Change Library gebruiken om de onderbrekingen voor het wijzigen van de pin te vereenvoudigen.

Als we echter even uit de bibliotheek blijven, willen we kan vaststellen dat interrupts voor het wisselen van pinnen even snel of sneller kunnen zijn dan externe interrupts. Om te beginnen, hoewel pinnenwisselonderbrekingen werken op batches van pinnen, hoeft u niet de hele batch in te schakelen. Als u bijvoorbeeld wijzigingen op pin D4 wilt detecteren, is dit voldoende:

Voorbeeld sketch:

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

Mijn testen geven aan dat het 1,6 µs duurde voor de “test “pin (pin 5) om te reageren op een verandering op de interrupt pin (pin 4).


Als je nu de simpele (luie?) benadering kiest en attachInterrupt () gebruikt, zul je de resultaten zijn langzamer, niet sneller.

Voorbeeldcode:

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

Het kost 3,7 µs om de testpin te veranderen, veel meer dan de 1,6 µs hierboven. Waarom? Omdat de code die de compiler moet genereren voor de “generieke” interrupthandler elk denkbaar register moet opslaan (erop drukken). toegang tot de ISR, en herstel ze (pop ze) voordat ze terugkeren. Bovendien is er de overhead van een andere functieaanroep.


Nu kunnen we dat omzeilen door attachInterrupt () te vermijden en het zelf te doen:

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

Dat is de snelste van allemaal met 1,52 µs – het lijkt erop dat er ergens een klokcyclus is opgeslagen.


Er is echter een voorbehoud voor onderbrekingen bij het wisselen van pincodes. Ze zijn in batches, dus als je interrupts op veel pinnen wilt hebben, moet je binnen de interrupt testen welke er één is gewijzigd . U zou dat kunnen doen door de vorige pin-status op te slaan en deze te vergelijken met de nieuwe pin-status. Dit is niet per se bijzonder traag, maar hoe meer pinnen u moet controleren, hoe langzamer het zou zijn.

De batches zijn:

  • A0 tot A5
  • D0 tot D7
  • D8 tot D13

Als je gewoon nog een paar interrupt-pins wilt, kun je testen vermijden door er gewoon voor te kiezen om pins van verschillende batches (bijv. D4 en D8).


Meer details op http://www.gammon.com.au/interrupts

Antwoord

Er zijn twee soorten interrupts. Wat de Arduino Playground zei:

De processor in het hart van elke Arduino heeft twee verschillende soorten interrupts: “extern” en “pin wijzigen”. Er zijn slechts twee externe interrupt-pinnen op de ATmega168 / 328 (dwz in de Arduino Uno / Nano / Duemilanove), INT0 en INT1, en ze zijn toegewezen aan Arduino-pinnen 2 en 3. Deze interrupts kunnen worden ingesteld om te worden geactiveerd bij RISING of VALLENDE signaalflanken, of op laag niveau. De triggers worden geïnterpreteerd door hardware en de onderbreking is erg snel. De Arduino Mega heeft nog een paar externe interrupt-pinnen beschikbaar.

Aan de andere kant kunnen de pin-change-interrupts op veel meer pinnen worden ingeschakeld. Voor op ATmega168 / 328 gebaseerde Arduinos kunnen ze worden ingeschakeld op een van de 20 of alle 20 signaalpinnen van de Arduino; op de op ATmega gebaseerde Arduinos kunnen ze worden ingeschakeld op 24 pinnen. Ze worden gelijkelijk geactiveerd op RISING of FALLING signaalflanken, dus het is aan de interruptcode om de juiste pinnen in te stellen om interrupts te ontvangen, om te bepalen wat er is gebeurd (welke pin? … is het signaal gestegen of gedaald?), en om het correct af te handelen.Bovendien zijn de onderbrekingen voor het wisselen van pinnen gegroepeerd in 3 “poort” op de MCU, dus er zijn slechts 3 interruptvectoren (subroutines) voor het hele lichaam van pinnen. Dit maakt het oplossen van de actie op een enkele interrupt nog ingewikkelder.

In feite zijn de externe interrupts extreem snel omdat ze allemaal op hardware zijn gebaseerd. Er zijn echter ook onderbrekingen voor het wisselen van pinnen, maar die lijken veel langzamer te zijn omdat ze meestal op software zijn gebaseerd.

tl; dr: de 20 interruptpinnen samen zijn veel langzamer. De 2 interruptpinnen zijn de snelste en meest efficiënte.


EDIT: Ik heb zojuist naar het gegevensblad gekeken en er staat dat een pinwisselonderbreking wordt geactiveerd voor elk van de geselecteerde pinnen zonder indicatie van welke pin is veranderd (hoewel deze is opgesplitst in drie interruptvectoren).

  • Voor externe interrupts “zal het je vertellen pin 3 zojuist gewijzigd
  • For pin change it “Ik zal je vertellen een pin die je aan het volgen was!

Zoals je kunt zien, een pin change interrupt voegt veel overhead toe aan de ISR die je moet afhandelen door vorige statussen op te slaan en te kijken of het de pin is waar je je zorgen over maakt. Het is misschien prima voor een slaapstand, maar het is beter om de externe interrupts te gebruiken.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *