PCF8574AP e lettura tasti

Ciao a tutti,
scrivo perché non riesco a risolvere un problema di lettura tasti, utilizzando come IOexpander il PCF8574AP, la configurazione piedini che uso è

scusate ma non ho capito come si inserisce un’immagine :~

Il problema che ho consiste nel fatto che per un certo numero di pressioni dei tasti fatte sia a casaccio che non, leggo i tasti, poi si blocca tutto e devo resettare…
La tastiera, così come l’ho prevista andrà integrata con un lcd 20x4 già pilotato con un altro ic identico e senza nessun problema riscontrato e con un rtc ds1307, anche questo fino ad ora senza nessun problema.

Ho fatto le prove sia collegando tutto insieme sia con la tastiera separata, ed ho testato resistenze di pullup sul bus i2c da 2,2k da 4,7k e da 10k

Ed il risultato non cambia mai…

Ho provato ad usare la libreria IOexp, qui di seguito il codice:

/*
Configurazione piedini PCF 8574AP 

piedino 1 = A0 = +5v
piedino 2 = A1 = GND
piedino 3 = A2 = GND
piedino 4 = P0 = tasto destra
piedino 5 = P1 = tasto sinistra
piedino 6 = P2 = tasto decremento
piedino 7 = P3 = tasto incremento
piedino 8 = Vss = GND

piedino 9 = P4 = tasto OK
piedino 14 = SCL = A5 su Arduino
piedino 15 = SDA = A4 su Arduino
piedino 16 = Vdd = +5v
*/
#include <Wire.h>
#include <IOexp.h>



IOexp tastiera(0x39);
boolean inc, dec, dx, sx, ok; 
boolean incremento = false;

boolean tastopremuto = false;
int tempo;

#define bip 200   // Tono acustico per pulsante ok
#define bop 220   // Tono acustico per pulsanti inc e dec
#define bep 240   // Tono acustico per pulsanti dx e sx
#define buzzer 14

void Cicalino (int tono)
    {
      for (int i = 0; i < 90; i++)
      {
        digitalWrite(buzzer,HIGH);
        delayMicroseconds(tono);
        digitalWrite(buzzer,LOW);
        delayMicroseconds(tono);
      }
    }

void setup()
{
  Wire.begin(); 
  pinMode(buzzer, OUTPUT); 
  //Serial.begin(9600);
  
}



void loop()
{
  //tastiera.fullwrite(0x0);
  inc = tastiera.read(P3);
  dec = tastiera.read(P2);
  sx = tastiera.read(P1);
  dx = tastiera.read(P0);
  ok = tastiera.read(P4);
  
  if (inc == true && tastopremuto == false)
    {
      //Serial.println("Prova tasti: Incremento");
      Cicalino(bop);
      tastopremuto = true;
      tempo = millis();
    }
    
  if (dec == true && tastopremuto == false)
    {
      //Serial.println("Prova tasti: Incremento");
      Cicalino(bop);
      tastopremuto = true;
      tempo = millis();
    }
  
  if (dx == true && tastopremuto == false)
    {
      //Serial.println("Prova tasti: Incremento");
      Cicalino(bep);
      tastopremuto = true;
      tempo = millis();
    }
  
  if (sx == true && tastopremuto == false)
    {
      //Serial.println("Prova tasti: Incremento");
      Cicalino(bep);
      tastopremuto = true;
      tempo = millis();
    }
  
  if (ok == true && tastopremuto == false)
    {
      //Serial.println("Prova tasti: Incremento");
      Cicalino(bip);
      tastopremuto = true;
      tempo = millis();
    }  
    
  if (millis() >= (tempo + 300))
    {
      tastopremuto = false;
    }  
  
  
 /* Serial.print("Prova tasti: ");
  //if (incremento == true) { Serial.println(" Incremento"); }
  if (dec == true) { Serial.println(" Decremento"); }
  if (dx == true) { Serial.println(" Destra"); }
  if (sx == true) { Serial.println(" Sinistra"); }
  if (ok == true) { Serial.println(" OK!"); }

  Serial.print(" \n ");*/
  
}

ed ho provato anche con wire direttamente:

/*
Configurazione piedini PCF 8574AP 

piedino 1 = A0 = +5v
piedino 2 = A1 = GND
piedino 3 = A2 = GND
piedino 4 = P0 = tasto destra
piedino 5 = P1 = tasto sinistra
piedino 6 = P2 = tasto decremento
piedino 7 = P3 = tasto incremento
piedino 8 = Vss = GND

piedino 9 = P4 = tasto OK
piedino 14 = SCL = A5 su Arduino
piedino 15 = SDA = A4 su Arduino
piedino 16 = Vdd = +5v
*/
#include <Wire.h>


#define buzzer 14

boolean tastopremuto = false;
int tasto;
int tempo;

#define bip 200   // Tono acustico per pulsante ok
#define bop 220   // Tono acustico per pulsanti inc e dec
#define bep 240   // Tono acustico per pulsanti dx e sx


void Cicalino (int tono)
    {
      for (int i = 0; i < 90; i++)
      {
        digitalWrite(buzzer,HIGH);
        delayMicroseconds(tono);
        digitalWrite(buzzer,LOW);
        delayMicroseconds(tono);
      }
    }

void setup()
{
  Wire.begin(); 
  pinMode(buzzer, OUTPUT); 
  //Serial.begin(9600);
}



void loop()
{
    Wire.beginTransmission(0x39);
    Wire.send(0);
    Wire.endTransmission();
    Wire.requestFrom(0x39, 1);

    tasto = Wire.receive(); 
    
    //Serial.print("Tasto premuto: ");
    
    if ((tasto == 8) && (tastopremuto == false))
      {
       Cicalino(bop);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Incremento");
      }
      
    if ((tasto == 4) && (tastopremuto == false))
      {
       Cicalino(bop);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Decremento");
      }  
     
    if ((tasto == 2) && (tastopremuto == false))
      {
       Cicalino(bip);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Sinistra");
      }
      
    if ((tasto == 1) && (tastopremuto == false))
      {
       Cicalino(bip);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Destra");
      }  
      
    if ((tasto == 16)  && (tastopremuto == false))
      {
       Cicalino(bep);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("OK!!!");
      } 
      
    if (millis() >= (tempo + 300))
      {
        tastopremuto = false;
      }
    
    //Serial.println(" ");  
      
      
}

ma sono sempre al punto di prima, dopo un po’ non leggo più i tasti, qualcuno riesce a capire dove sbaglio???
inizialmente, ho creduto anche che ci fosse qualche conflitto con il serial monitor, tanto che ho scritto una funzioncina per il buzzer in modo da avere un feedbak sonoro, ma niente da fare…

E’ una settimana che faccio tentativi senza nessun successo…

Grazie in anticipo a chiunque voglia aiutarmi…

tastiera.jpg

anche a me l'i2c da qualche problema.. però solo nell'inizializzazione, dopo funziona tutto ok...

prova a controllare DOVE si blocca il programma (la funzione precisa) e magari anche la ram disponibile (la funzione la rubi dalla libreria per le FAT16)

Anche io in passato ci persi una settimana senza riuscire a venirne fuori per una cosa simile, ricordo però che avevo parecchie cosette sul bus i2c (rtc, 2 PCF8574 per 2 display lcd, 3 atmega168 e forse anche qualcos’altro…)
Ho risolto collegando i pulsanti ad uno shift register tipo CD4021… la soluzione non è ottima infatti ti occupa 3 pin dell’atmega ma se proprio non ne vieni fuori tienilo in considerazione, costa anche molto meno del PCF8574 e nel playground ci sono pure diversi tutorial per leggere lo stato dei pulsanti http://www.arduino.cc/en/Tutorial/ShiftIn.
Il bello dell’elettronica per quel poco che conosco è che esistono molti modi per fare una cosa.
Saluti

Pelletta: Anche io in passato ci persi una settimana senza riuscire a venirne fuori per una cosa simile, ricordo però che avevo parecchie cosette sul bus i2c (rtc, 2 PCF8574 per 2 display lcd, 3 atmega168 e forse anche qualcos'altro...) Ho risolto collegando i pulsanti ad uno shift register tipo CD4021... la soluzione non è ottima infatti ti occupa 3 pin dell'atmega ma se proprio non ne vieni fuori tienilo in considerazione, costa anche molto meno del PCF8574 e nel playground ci sono pure diversi tutorial per leggere lo stato dei pulsanti http://www.arduino.cc/en/Tutorial/ShiftIn. Il bello dell'elettronica per quel poco che conosco è che esistono molti modi per fare una cosa. Saluti

Ciao Pelletta, grazie per il link, non conoscevo questo tutorial ed è molto interessante, però vorrei capire prima cosa sto sbagliando e poi visto che altri hanno avuto lo stesso problema, forse questa è l'occasione per capire dove o come si deve operare. Inoltre vorrei usare gli shift per pilotare una scheda di potenza come quella che in questi giorni un altro utente di questo forum, Gladio, sta condividendo generosamente con tutti:

http://arduino.cc/forum/index.php/topic,58108.0.html

Ciao Riccardo

Purtroppo son scarsissimo in inglese, ma c'è quelcosa inerente il pin INT sul datasheet del pcf:

http://www.alldatasheet.com/datasheet-pdf/pdf/18212/PHILIPS/PCF8574.html

Che non capisco, inoltre in caso di uso come input, se traduco bene, scrivono che tutti i pin andrebbero forzati in alto (pag. 11), se fosse così dopo ogni lettura, dovrei scrivere un uno logico su tutti i pin o sbaglio? Se così fosse però dovrei invertire l'uso dei pulsanti e delle resistenze in modo di avere sempre 1 in ingresso e zero solo quando premo un tasto... solo che mi sembra poco logico, cmq. ormai ho fatto tante di quelle prove che una in più per quanto poco convincente non mi sconvolge, il fatto è che non sono un principiante e non ci capisco molto, spero che qualcuno mi aiuti.

Riccardo

Non mi sono messo a leggere tutto il doc ma mi pare di capire che il pin INT/ è un pin di output, che serve ad informare un processore esterno che un pin del PCF è cambiato di stato, così da poter avviare una lettura/scrittura.

Cmq nel forum vedo che l'argomento è stato trattato spesso. Qui c'è anche un esempio di codice: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1256915868

È giusto quello che dice Leo. L' uschita INT serve per dare un interrupt al controller in modo che questo possa reagire ad un cambio di stato di una delle entrate. In questo modo si puó evitare di dover continuamente leggere il PCF8574 per controllare se un pin di ingresso abbia cambiato stato.

L' uscita é un transistore open drain percui serve una resistenza pullup.

Ciao Uwe

Ciao Leo72 e uwefed, grazie per i vostri interventi, appena possibile proverò a leggere gli ingressi del pcf utilizzando l'int. Come resistenza di pullup, basterà la solita 10k o c'è un valore specifico?

Altrimenti quali altri IOexpander, potrei usare per implementare una tastierina via I2C?

Grazie ancora a tutti,

Riccardo

P.S. Qualcuno mi potrebbe spiegare come si inserisce un'immagine in un post?

Ancora io, :cold_sweat:
mi vergogno un pò ma devo chiedere ancora…
In pratica il codice non funzionava perché usavo la variabile tempo dichiarata come una int, ma la uguagliavo a millis() quindi ogni volta che millis superava il valore massimo di una int si bloccava tutto :~

Ad ogni modo, ho provato ad usare AttachInterrupt, perché mi sembra sensato agire in questa direzione, ma senza successo, premetto che ho collegato il piedino 13 (INT) con una pullup da 10k (grazie ad uwefed) al pin 2 di Arduino che corrisponde allo 0 degli interrup esterni, di seguito inserisco il codice,

#include <Wire.h>

#define buzzer 14

boolean tastopremuto = false;
int tasto;
unsigned long tempo;

#define bip 200   // Tono acustico per pulsante ok
#define bop 220   // Tono acustico per pulsanti inc e dec
#define bep 240   // Tono acustico per pulsanti dx e sx


void Cicalino (int tono)
    {
      for (int i = 0; i < 90; i++)
      {
        digitalWrite(buzzer,HIGH);
        delayMicroseconds(tono);
        digitalWrite(buzzer,LOW);
        delayMicroseconds(tono);
      }
    }

void setup()
{
  Wire.begin(); 
  attachInterrupt(0, leggitasto, LOW);
  pinMode(buzzer, OUTPUT); 
  //Serial.begin(9600);
}

void leggitasto()
    {
      Wire.beginTransmission(0x39);
      Wire.send(0);
      Wire.endTransmission();
      Wire.requestFrom(0x39, 1);
      tasto = Wire.receive();
      tempo = millis();
      //detachInterrupt(0);
    }


void loop()
{
    /*Wire.beginTransmission(0x39);
    Wire.send(0);
    Wire.endTransmission();
    Wire.requestFrom(0x39, 1);

    tasto = Wire.receive(); */
    
    //Serial.print("Tasto premuto: ");
    
    if ((tasto == 8) && (tastopremuto == false))
      {
       Cicalino(bop);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Incremento");
      }
      
    if ((tasto == 4) && (tastopremuto == false))
      {
       Cicalino(bop);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Decremento");
      }  
     
    if ((tasto == 2) && (tastopremuto == false))
      {
       Cicalino(bip);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Sinistra");
      }
      
    if ((tasto == 1) && (tastopremuto == false))
      {
       Cicalino(bip);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("Destra");
      }  
      
    if ((tasto == 16)  && (tastopremuto == false))
      {
       Cicalino(bep);
       tastopremuto = true;
       tempo = millis();
       //Serial.print("OK!!!");
      } 
      
    if (millis() >= (tempo + 300))
      {
        tastopremuto = false;
      }
    
    //Serial.println(" ");  
     
}

Cosa sbaglio?

Riccardo

ciao ho visto che il topic è fermo da molto. percaso ci sono stati sviluppi riguardo all'uso del PCF perchè vorrei usare anch'io per pilotare una serie di relè, risparmiando contatti.