PCF8574 il piedino int e gli interrupt

Ciao,
nel mio progetto, utilizzo l'IC del titolo, come I/O expander per i tasti che l'utente utilizza quando vuole impostare/variare qualcosa, mano a mano però che implemento le varie funzioni e le faccio funzionare, perdo reattività sulla lettura dei tasti quando vengono premuti, in pratica, più cose chiedo di fare ad Arduino, e sempre meno è utilizzabile il tastierino, lo so per certo, perché ho fatto prove disabilitando a casaccio alcune funzioni ed il tastierino torna ad essere veloce nell'utilizzo...

Ho deciso quindi di iniziare ad usare gli interrupt per leggere i tasti forte del fatto che il PCF in questione ha un piedino int ( è Open drain, come mi ha spiegato uwefed in passato, quindi uso una pull-up da 10k), ed ho iniziato a fare prove collegando il piedino int del PCF al piedino 2 di arduino per vedere come variava l'ingresso... avrei dovuto saperlo prima in effetti, in ogni caso va da 1 a 0 ad ogni pressione di tasto e fa la stessa cosa al rilascio del tasto, quindi ho due variazioni in uscita dal piedino int, ogni volta che uso un tasto qualsiasi, già questo mi incarta parecchio, ma via software credo di poterlo risolvere...

Ho iniziato ad avere problemi quando ho provato a capire, utilizzando attachInterrupt, quale tasto premo:

#include <Wire.h>
#include <IOexp.h>



byte led = 13;
volatile int statoled = LOW;
volatile byte tasto;

IOexp tastiera(0x39);

  
void lampeggioled13letturatasto()
{
  statoled = !statoled;
  Wire.beginTransmission(0x39);
  Wire.requestFrom(0x39, 8);
  if(Wire.available() )
  {
    tasto = Wire.read();
  }
//tasto = tastiera.fullread();
}  
  
void setup()
{
 
 Wire.begin();
 Serial.begin(9600);

 pinMode(led, OUTPUT);
 attachInterrupt(0, lampeggioled13letturatasto, CHANGE);
}

void loop()
{
  digitalWrite(led, statoled);
  Serial.print("LED = ");
  Serial.print(statoled);
  //tasto = tastiera.fullread();
/*  Wire.beginTransmission(0x39);
  Wire.requestFrom(0x39, 8);
  if(Wire.available() )
  {
    tasto = Wire.read();
  }
*/
  Serial.print("    Tasto = ");
  Serial.println(tasto, DEC);


}

In pratica ho preso uno programmino già funzionate copiato da internet per fare delle prove ed ho aggiunto i comandi per leggere il tasto, inizialmento usando la libreria IOexp, ma anche usando i comandi della wire, ed ecco cosa succede:
(ho sempre compilazioni senza errori)

  • senza nessun comando per lettura tasto il led lampeggia (il piedino int varia due volte ogni volta che premo e rilascio qualsiasi pulsante, quindi non rimane acceso
  • Aggiungendo alternativamente i comandi di lettura tasto sia per IOexp che per wire, nel loop, tutto funziona e nel seriale ho i riscontri :sweat_smile:
  • Provo ad inserire i comandi di lettura tasti nella funzione che attacco all'interrupt carico senza errori e sia il seriale che il led si bloccano alla prima pressione di qualsiasi tasto sia con la libreria IOexp che con wire e non riesco a capire perché =(

=( =( =( Mi aiutate per favore?

Grazie Riccardo

Le ISR (Interrupt Service Routine), cioè le funzioni chiamate al momento della generazione dell'interrupt, non permettono al loro interno di chiamare altre funzioni basate anch'esse sugli interrupt perché per default una ISR è atomica, ossia non può essere interrotta da un altro interrupt.
Questo significa che nel momento in cui viene chiamata lampeggioled13letturatasto() vengono disabilitati gli interrupt. Siccome la Wire è basata sugli interrupt, si blocca tutto.

Lesto ha lavorato ad una versione della libreria TWI che non ha il problema che ti ho esposto. Cercala nella sez. "Megatopic" (mi pare di ricordare che fosse lì).

Grazie leo72,
ho letto tutto il topic di lesto: http://arduino.cc/forum/index.php/topic,117426.15.html
non ci ho capito molto, ma di quel poco mi sembra di capire che comunque si appoggia a wire, quindi non mi risolve il problema almeno credo :blush:, il fatto è che sto studiando tutto da autodidatta e non sono nemmeno sicuro di quello che ho letto/capito/scritto.

In ogni caso volendo usare i metodi "canonici", utilizzando I/O expander I2C, non c'è nessuna possibilità di usare gli interrupt...

Potrei leggere seplicemente il pin 2 di arduino collegato al piedino int del pcf e a quel punto fare la lettura del tasto tenendo in considerazioni che varierebbe due volte ad ogni pressione, creando un interrupt mio che però non è asincrono e quindi dipende comunque dalla complessità delle operazioni che faccio svolgere ad arduino...

Scusate, ma sono andato in confusione :frowning: e lavorando con le mie limitatissime conoscenze, non sono più sicuro di nulla... :blush:

Avete soluzioni per favore????

=( Riccardo...

Grazie Riccardo

Non ho provato la Wire modificata di lesto, non so come operi.
Un'alternativa è quella di modificare un flag all'interno della ISR e poi, da codice, controllare continuamente se questo flag è attivo e, in caso positivo, spedire i dati via I2C. In questo modo non usi funzioni basate su interrupt all'interno di ISR.

Grazie Leo72,
credo che non ci siano altre strade percorribili al momento, anche in riferimento alle mei conoscenze attuali ovviamente...

Ciao Riccardo.

Mentre rispondevo a Leo72, mi è venuto un tarlo in mente:
Ho appurato che lo stato del piedino int del PCF8574, varia due volte ogni volta che premo e rilascio uno qualsiasi dei pulsanti collegati, la logica mi dice che è corretto, in quanto:

  • Premo il pulsante, lo stato del pin a cui il pulsante è collegato cambia stato ed il piedino int cambia anche lui il suo stato (va da 1 a 0 e torna a 1 )
  • Rilasci il pulsante, lo stato del pin a cui il pulsante è collegato ricambia stato ed il piedino int ricambia anche lui il suo stato (va ancora una volta da 1 a 0 e torna a 1)

Ho verificato questa cosa parecchie volte ieri, finché non mi sono deciso a chiedere perche non appena usavo wire mi si bloccava tutto.
Il tarlo è: E se ai cambiamenti di stato si aggiungesse anche un eventuale bounce del tasto?
C'è un metodo per scoprire se ad esempio il PCF è in grado di riconoscere un eventuale bounce del tasto e di conseguenza regoli lo stato del suo piedino int?
Di fatto sembra che già lo faccia, ma come faccio ad esserne certo???

Grazie Riccardo

Non so aiutarti, leggi il datasheet.
Se vuoi eliminare il rimbalzo via HW prova a mettere una resistenza ed un condensatore:

debounce_switch.png

Grazie,
non avevo pensato a questa soluzione, meno male che ci sei/siete , ma sai però se il condensatore deve essere per forza polarizzato?

Ancora grazie Riccardo.

Va bene anche un ceramico, secondo me. Anzi, filtrando più in alta frequenza, forse toglie meglio gli spikes dei rimbalzi.

leo72:
spikes dei rimbalzi.

Se ogni volta che uso un pulsante, rischio una chiodata con tanto di rimbalzo, tra ieri e oggi è un miracolo se ho salvato le manine XD XD XD

Grazie, sei grande.

Riccardo