Quanti pin di interruzione può gestire Uno?


16

Sto cercando di utilizzare un ricevitore RC a 7 canali con Arduino Uno R3. Nella documentazione, ci sono menzioni di un massimo di 2 pin di interruzione, mentre su alcuni altri blog ho visto menzioni di usare fino a 20 pin come interruzioni, con la libreria PinChangeInt. Quindi, quanti interrupt Arduino può gestire in modo nativo? Ed è diverso da quanti possono essere gestiti con supporto software come PinChangeInt?

Risposte:


13

Esistono due tipi di interrupt di tipo "cambio pin". Gli interrupt esterni, di cui ce ne sono due su Uno. Sono chiamati 0 e 1, tuttavia si riferiscono ai pin digitali 2 e 3 sulla scheda. Questi possono essere configurati per rilevare salita, discesa, modifica (salita o discesa) o BASSO.

Inoltre, vi sono interruzioni "cambio pin", che rilevano una modifica dello stato del pin in uno qualsiasi dei 20 pin (da A0 a A5 e da D0 a D13). Questi interruttori di cambio pin sono anch'essi basati su hardware quindi, di per sé, saranno veloci quanto gli interrupt esterni.

Entrambi i tipi sono leggermente complicati da usare a livello di registro, ma l'IDE standard include attachInterrupt (n) e detachInterrupt (n) che semplifica l'interfaccia agli interrupt esterni. È inoltre possibile utilizzare la Libreria di modifica pin per semplificare gli interrupt di modifica pin.

Tuttavia, allontanandoci dalla libreria per un minuto, possiamo stabilire che gli interrupt di cambio pin possono essere più veloci o più veloci degli interrupt esterni. Per prima cosa, sebbene l'interruzione della sostituzione dei pin funzioni su lotti di pin, non è necessario abilitare l'intero batch. Ad esempio, se si desidera rilevare le modifiche sul pin D4, questo sarà sufficiente:

Esempio di schizzo:

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

Il mio test indica che ci sono voluti 1,6 µs per il pin "test" (pin 5) per reagire a una modifica sul pin di interruzione (pin 4).


Ora se prendi l'approccio semplice (pigro?) E usi attachInterrupt () scoprirai che i risultati sono più lenti, non più veloci.

Codice di esempio:

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

Questo richiede 3,7 µs per cambiare il pin di test, molto più degli 1,6 µs sopra. Perché? Poiché il codice che il compilatore deve generare per il gestore di interrupt "generico" deve salvare ogni registro concepibile (spingerli) all'entrata dell'ISR e quindi ripristinarli (pop) prima di tornare. Inoltre c'è il sovraccarico di un'altra chiamata di funzione.


Ora possiamo aggirare il problema evitando attachInterrupt () e facendolo da soli:

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

Questo è il più veloce di tutti a 1,52 µs - sembra che un ciclo di clock sia stato salvato da qualche parte.


C'è un avvertimento però, per gli interruzioni di cambio pin. Sono in batch, quindi se si desidera avere interruzioni su molti pin, è necessario verificare all'interno dell'interrupt quale è stato modificato. Si potrebbe fare che salvando lo stato perno precedente, e confrontandolo con il nuovo stato perno. Questo non è necessariamente particolarmente lento, ma più pin è necessario controllare, più lento sarebbe.

I lotti sono:

  • Da A0 a A5
  • Da D0 a D7
  • Da D8 a D13

Se vuoi solo un paio di pin di interruzione in più, puoi evitare qualsiasi test semplicemente scegliendo di usare pin di lotti diversi (es. D4 e D8).


Maggiori dettagli su http://www.gammon.com.au/interrupts


9

Ci sono due tipi di interrupt. Cosa ha detto il parco giochi di Arduino :

Il processore alla base di qualsiasi Arduino ha due diversi tipi di interrupt: "esterno" e "cambio pin". Esistono solo due pin di interrupt esterni su ATmega168 / 328 (ovvero, in Arduino Uno / Nano / Duemilanove), INT0 e INT1, e sono mappati sui pin Arduino 2 e 3. Questi interrupt possono essere impostati per attivarsi su RISING o Bordi del segnale di CADUTA o a basso livello. I trigger sono interpretati dall'hardware e l'interrupt è molto veloce. Arduino Mega ha alcuni pin di interrupt esterni disponibili.

D'altra parte, gli interrupt di cambio pin possono essere abilitati su molti più pin. Per gli Arduinos basati su ATmega168 / 328, possono essere abilitati su uno o tutti e 20 i pin di segnale dell'Arduino; sugli Arduinos basati su ATmega possono essere abilitati su 24 pin. Vengono attivati ​​equamente sui fronti del segnale RISING o FALLING, quindi spetta al codice di interrupt impostare i pin corretti per ricevere gli interrupt, per determinare cosa è successo (quale pin? ... il segnale è aumentato o diminuito?), E per gestirlo correttamente. Inoltre, gli interrupt di cambio pin sono raggruppati in 3 "porte" sull'MCU, quindi ci sono solo 3 vettori di interrupt (subroutine) per l'intero corpo dei pin. Questo rende ancora più complicato il compito di risolvere l'azione su un singolo interrupt.

Fondamentalmente, gli interrupt esterni sono estremamente veloci poiché sono tutti basati su hardware. Tuttavia, c'è anche l'interruzione del cambio pin, ma quelli sembrano essere molto più lenti perché sono principalmente basati su software.

tl; dr: i 20 pin di interruzione insieme sono molto più lenti. I 2 pin di interruzione sono i più veloci ed efficienti.


EDIT: Ho appena guardato il foglio dati e dice che viene attivato un interrupt di cambio pin per uno qualsiasi dei pin selezionati senza alcuna indicazione di quale pin sia cambiato (sebbene sia diviso in tre vettori di interrupt).

  • Per gli interrupt esterni, ti dirà che il pin 3 è appena cambiato
  • Per il cambio pin ti dirà un pin cambiato che stavi monitorando!

Come puoi vedere, un interrupt di cambio pin aggiunge un sacco di overhead nell'ISR che devi gestire memorizzando gli stati precedenti e vedendo se è il pin di cui ti preoccupi. Potrebbe andare bene per uno stato di sonno, ma è meglio usare gli interrupt esterni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.