Differenze tra le versioni di "HotAirGun/I2cController"

Da raspibo.
Jump to navigation Jump to search
Riga 34: Riga 34:
 
Abbiamo visto sopra che bottoni ed encoder generano interrupt per risparmiare i tempi di polling ad ogni ciclo.  
 
Abbiamo visto sopra che bottoni ed encoder generano interrupt per risparmiare i tempi di polling ad ogni ciclo.  
  
Scrivere un programma per microcontrollori usando gli eventi e' un po' diverso rispetto alla programmazione tradizionale vedi [https://it.wikipedia.org/wiki/Programmazione_a_eventi Wikipedia].  
+
Scrivere un programma per microcontrollori usando gli eventi e' un po' diverso rispetto alla programmazione tradizionale vedi [https://it.wikipedia.org/wiki/Programmazione_a_eventi Wikipedia], in pratica non dovremo mai bloccare arduino per gestire un interrupt per evitare di perdere eventi.  
  
Nel nostro caso imposteremo arduino per gestire un evento di fronte di discesa sul pin D3 che genera all'interno di arduino un [https://www.arduino.cc/en/Reference/AttachInterrupt Interrupt] chiamato int1 (la funzione digitalPinToInterrupt in base al pin ed al tipo di board utilizzata si occupa di calcolare quale sia l'interrupt corrispondente sulla nostra board.
+
Questo comporta dover ripensare la progrmmazione in modo asincrono e non e' cosi' immediato, ma sicuramente ci mette di fronte ad un modello interessante.
 +
 
 +
Nel nostro caso imposteremo arduino per gestire un evento di fronte di discesa sul pin D3 che genera all'interno di arduino un [https://www.arduino.cc/en/Reference/AttachInterrupt Interrupt] chiamato int1.
 +
La funzione digitalPinToInterrupt (che ho scoperto scrivendo questa pagina) in base al pin ed al tipo di board utilizzata si occupa di calcolare quale sia l'interrupt corrispondente sulla nostra board.
 +
<source lang=c>
 
  // Interrupts from the MCP will be handled by this PIN on Arduino
 
  // Interrupts from the MCP will be handled by this PIN on Arduino
 
  byte arduinoIntPin = 3;
 
  byte arduinoIntPin = 3;
 
  attachInterrupt(digitalPinToInterrupt(arduinoIntPin), intCallBack, FALLING);
 
  attachInterrupt(digitalPinToInterrupt(arduinoIntPin), intCallBack, FALLING);
 +
</source>
 +
Al verificarsi di un evento sul MCP23017 viene abbassato un pin chiamati INTA connesso al pin D3 di arduino. Quando il valore logico sul pin D3 scende da 1 a 0 (FALLING) si verifica un interrupt che interrompe il ciclo di loop principale ed esegue la funzione intCallBack.
 +
 +
Vediamo ora il dettaglio della funzione
 +
<source lang=c>
 +
void intCallBack() {
 +
awakenByInterrupt = true;
 +
}
 +
</source>
 +
semplicemente viene settata una variabile, questa operazione occupa qualche microsecondo per essere eseguita e poi si torna all'esecuzione del programma principale.
 +
 +
Nel ciclo di loop possiamo eseguire alcune operazioni (sempre non bloccanti o che non blocchino il flusso del programma per troppo tempo) e andare a richiamare una funzione di gestione degli interrupt solo se un evento si e' verificato (cioe' la variabile awakenByInterrupt e' stata settata dalla funzione intCallBack).
 +
<source lang=c>
 +
void loop() {
 +
        contr.setCursor(0, 1);
 +
        contr.print(millis()/1000);
 +
if (awakenByInterrupt) handleInterrupt();
 +
delay(30);
 +
}
 +
</source>

Versione delle 13:05, 28 apr 2017

I2cController

Come Questa board usa un GPIO expander i2c per interfacciare:

  • display LCD compatibile con hd44780
  • encoder digitale a rotella + click
  • pulsanti (fino a 5 se usati assieme a display ed encoder)

MCP23017

Il controller e' basato sull'integrato MCP23017 un GPIO expander di Microchip che permettere di aggiungere pin digitali sul bus i2c. Questa pagina [GPIO aggiuntivi MCP23x17] fornisce diverse informazioni sul chip.

MCP23017 supporta la gestione degli interrupt sui pin in ingresso, e' possibile qui attivare una segnalazione di avviso verso Arduino in caso un pulsante cambi di stato o l'encoder venga ruotato.

L'integrato ha due port chiamati PORT A e PORT B ognuno con 8 pin, ogni PORT ha un pin dedicato per la gestione degli interrupt, noi comunque useremo per input solo il PORT A.

I pin in input vengono configurati con pullup perciò verranno collegati a massa e l'interrupt verrà generato quando il segnale ha un fronte di discesa.

Software

Per la gestione del controller abbiamo utilizzato due librerie già sviluppate da altri:

Alle due librerie che abbiamo fuso per sfruttare il lavoro già fatto e rendere più intuitivi i settaggi abbiamo aggiunto qualche funzione per velocizzare la configurazione dell'encoder e dei bottoni.

contr.setupEncoder(EN_A,EN_B,EN_C); // Encoder setup 

Per settare l'encoder basta specificare i due pin dei contatti della rotella e quello connesso al click.

uint8_t btnCross[BTN_NUM] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5}; // Five button on cross disposition, setup function
contr.setIntCross(btnCross, BTN_NUM);

Configuriamo anche i 5 bottoni che useremo disposti a croce con una funzione specifica.

Gestione degli interrupt

Abbiamo visto sopra che bottoni ed encoder generano interrupt per risparmiare i tempi di polling ad ogni ciclo.

Scrivere un programma per microcontrollori usando gli eventi e' un po' diverso rispetto alla programmazione tradizionale vedi Wikipedia, in pratica non dovremo mai bloccare arduino per gestire un interrupt per evitare di perdere eventi.

Questo comporta dover ripensare la progrmmazione in modo asincrono e non e' cosi' immediato, ma sicuramente ci mette di fronte ad un modello interessante.

Nel nostro caso imposteremo arduino per gestire un evento di fronte di discesa sul pin D3 che genera all'interno di arduino un Interrupt chiamato int1. La funzione digitalPinToInterrupt (che ho scoperto scrivendo questa pagina) in base al pin ed al tipo di board utilizzata si occupa di calcolare quale sia l'interrupt corrispondente sulla nostra board.

 // Interrupts from the MCP will be handled by this PIN on Arduino
 byte arduinoIntPin = 3;
 attachInterrupt(digitalPinToInterrupt(arduinoIntPin), intCallBack, FALLING);

Al verificarsi di un evento sul MCP23017 viene abbassato un pin chiamati INTA connesso al pin D3 di arduino. Quando il valore logico sul pin D3 scende da 1 a 0 (FALLING) si verifica un interrupt che interrompe il ciclo di loop principale ed esegue la funzione intCallBack.

Vediamo ora il dettaglio della funzione

 void intCallBack() {
 	awakenByInterrupt = true;
 }

semplicemente viene settata una variabile, questa operazione occupa qualche microsecondo per essere eseguita e poi si torna all'esecuzione del programma principale.

Nel ciclo di loop possiamo eseguire alcune operazioni (sempre non bloccanti o che non blocchino il flusso del programma per troppo tempo) e andare a richiamare una funzione di gestione degli interrupt solo se un evento si e' verificato (cioe' la variabile awakenByInterrupt e' stata settata dalla funzione intCallBack).

void loop() {
        contr.setCursor(0, 1);
        contr.print(millis()/1000);
	if (awakenByInterrupt) handleInterrupt();
	delay(30);
}