tastierino 4x4 valori anomali in output solo su una colonna di tasti

#define riga1 11
#define riga2 10
#define riga3 9
#define riga4 8
#define col1 7
#define col2 6
#define col3 5
#define col4 4


void setup()
{
 pinMode(riga1,INPUT_PULLUP);
  pinMode(riga2,INPUT_PULLUP);
  pinMode(riga3,INPUT_PULLUP);
  pinMode(riga4,INPUT_PULLUP);
  
  pinMode(col1,OUTPUT);
  pinMode(col2,OUTPUT);
  pinMode(col3,OUTPUT);
  pinMode(col4,OUTPUT);
  
  digitalWrite(col1,HIGH);
  digitalWrite(col2,HIGH);
  digitalWrite(col3,HIGH);
  digitalWrite(col4,HIGH);
  
  Serial.begin(9600);
  
  
}

void loop()
{
  delay(30);
  digitalWrite(col1,LOW);
  delay(30);
  if (digitalRead(riga1)==LOW) {
    Serial.println("1");
    while (digitalRead(riga1)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga2)==LOW) {
    Serial.println("4");
    while (digitalRead(riga2)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga3)==LOW) {
    Serial.println("7");
    while (digitalRead(riga3)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga4)==LOW) {
    Serial.println("*");
    while (digitalRead(riga4)==LOW) {
      delay(100);
    }
   }
     
     digitalWrite(col1,HIGH);
  delay(30);
     
      digitalWrite(col2,LOW);
  if (digitalRead(riga1)==LOW) {
    Serial.println("2");
    while (digitalRead(riga1)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga2)==LOW) {
    Serial.println("5");
    while (digitalRead(riga2)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga3)==LOW) {
    Serial.println("8");
    while (digitalRead(riga3)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga4)==LOW) {
    Serial.println("0");
    while (digitalRead(riga4)==LOW) {
      delay(100);
    }
     
     digitalWrite(col2,HIGH);
  }
  
  delay(30);
  
   digitalWrite(col3,LOW);
  if (digitalRead(riga1)==LOW) {
    Serial.println("3");
    while (digitalRead(riga1)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga2)==LOW) {
    Serial.println("6");
    while (digitalRead(riga2)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga3)==LOW) {
    Serial.println("9");
    while (digitalRead(riga3)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga4)==LOW) {
    Serial.println("#");
    while (digitalRead(riga4)==LOW) {
      delay(100);
    }
   }
     
     digitalWrite(col3,HIGH);
  
  delay(30);
  
   digitalWrite(col4,LOW);
  if (digitalRead(riga1)==LOW) {
    Serial.println("A");
    while (digitalRead(riga1)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga2)==LOW) {
    Serial.println("B");
    while (digitalRead(riga2)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga3)==LOW) {
    Serial.println("C");
    while (digitalRead(riga3)==LOW) {
      delay(100);
    }
  }
  
   if (digitalRead(riga4)==LOW) {
    Serial.println("D");
    while (digitalRead(riga4)==LOW) {
      delay(100);
    }
   }
     
     digitalWrite(col4,HIGH);
  
}

Buongiorno, volendo imparare ad utilizzare un tastierino su Arduino, ma senza l'utilizzo di una libreria così da sfruttare l'occasione per imparare qualcosa di nuovo sia a livello pratico che logico, ho creato questo semplice sketch cercando vari spunti su internet. Premetto che ad ora non ho ancora avuto modo di provarlo fisicamente, ma solo su Tinkercad. Ma veniamo al dunque:
Riscontro un problema di output seriale sulla colonna 2: alla pressione di un qualsiasi tasto su questa colonna mi escono casualmente valori presenti sulla medesima riga, ma di altre colonne. Il problema è limitato, come già detto, a questa colonna. Negli altri casi i valori sono corretti.

Grazie a tutti per le risposte.

P.S: Ho provato anche ad eliminare i blocchi di codice relativi a colonna 1 mantenendo 2-3-4 e ad eliminare i blocchi 3-4 mantenendo 1-2, ma il risultato non cambia, riscontro il medesimo problema.

Se indentassi il codice lo potresti forse vedere da te...

Premi Ctrl-T nell'IDE di Arduino così te lo sistema lui (e da quel momento cerca di abituarti, se vuoi sapere perché, vedi nel regolamento, punto 17.2).

Poi dato che hai fatto in sostanza 4 blocchi simili per le 4 colonne, raggruppa insieme le istruzioni di ognuna delle colonne (ossia togli le inutili righe vuote in mezzo), lascia solo una riga vuota tra un blocco/colonna e l'altro (evita in generale di lasciare più di una riga vuota, altrimenti peggiori la leggibilità del codice), e penso che dovresti trovare il problema, ossia c'è "qualcosa" dentro una graffa che non dovrebbe stare lì...

PS: per quanto riguarda poi lo "stile" di programmazione, quando ti trovi nelle condizioni di fare copia/incolla di blocchi di codice praticamente identico, è il momento di imparare a creare una funzione...

Ciao, grazie dei consigli, ho trovato l'errore. Per quanto riguarda la funzione aspetterò ancora qualche tempo, ma é sulla lista delle cose da imparare.

Perfetto. Come vedi, più che darti "la pappa pronta" ho preferito fartici arrivare da solo, perché questo ti servirà anche per il futuro, e se in questi casi basta l'indentazione, abituati ad applicarla anche mentre scrivi il codice, ti troverai molto meglio quando le cose "non funzionano" come dovrebbero... :wink:

Per le funzioni, se vuoi posso darti una mano qui, perché non è poi così complicato. in linea di massima se hai dei blocchi che si ripetono quasi tutti in modo identico tranne ad esempio un valore (il numero del pin) puoi creare una funzione con il singolo blocco ed a parametro gli passi solo il numero del pin e ti restituisce il risultato.

Fammi sapere se ti va ed hai tempo di provare, e proseguo la descrizione. :wink:

Certamente, sono sempre ben felice di imparare, però, se potessi aspettare qualche giorno, vorrei tentare da me a creare la mia funzione e successivamente potresti dirmi cosa non va (perché qualcosa sarà facile che non vada) :slight_smile: nel mentre ti ringrazio.

Certo, la cosa migliore è in genere cercare di imparare da soli quindi dato che non ho fretta :wink: fai con calma, poi fammi sapere se riesci o hai bisogno di una mano. Ciao!

Più che una funzione, dovresti fare una matrice bidimensionale con i simboli. Poi fai qualcosa come: for (col da 1 a 4) digitalWrite(col, LOW); for (riga da 1 a 4) if (!digitalRead (riga)) Scrivi (simbolo [col][riga]).
Al posto dei delay antirimbalzo, che non puoi sostituire con dei condensatori a causa della scansione, metti una variabile t_tasto che legge millis() quando un tasto viene visto premuto. Finché millis()-tasto è minore di 200, ulteriori pressioni vengono ignorate.
I delay(30) non servono.

Datman:
Più che una funzione, dovresti fare una matrice bidimensionale con i simboli. Poi fai qualcosa come: for (col da 1 a 4) digitalWrite(col, LOW); for (riga da 1 a 4) if (!digitalRead (riga)) Scrivi (simbolo [col][riga])

Datman, scusa ma hai capito che sta imparando e non sa neanche cosa sono le funzioni? Perché devi introdurre cose che ancora deve capire (e che comunque per come l’hai scritta anche io fatico a capire) rischiando di confondergli le idee?

Ha detto che vuole provare a capire da solo, lo “spunto” già glie l’ho dato, ora quindi facciamogli fare un passo alla volta, prima di scrivere aspetta almeno di vedere cosa fa, senza aggiungere "carne al fuoco a quello che qualcun altro ha scritto… :wink:

Non capisco che cosa gli suggerivi, allora... Semplicemente fare una funzione con digitalRead?... Dovrebbe comunque mettere una fila di Serial.print...

e poi… E’ giovane e forte! Ce la può fare! :slight_smile:

Si, provo a spiegarmi (così magari terminiamo qui ed evitiamo di “floodare” pure questo thread con discorsi teorici che esoluano dal problema dell’OP, come è già capitato…).

Se non sa ancora creare funzioni, e visto che lui ha di fatto, come dicevo, fatto “copia/incolla” di blocchi di codice cambiando solo un riferimento, si, intendevo fargli intanto prendere uno di quei blocchi e trasformarlo in funzione, e quindi “parametrizzare” quello che ha fatto.

Chiaramente ciò che hai consigliato tu non è sbagliato, ma è una soluzione “da esperto” e descritta come se stessi parlando ad un esperto… Invece quello che speravo avessi capito era che gli suggerivo di fare un passo per volta (come dico sempre tra l’altro…) e studiare una cosa per volta.

Se aggiungi interventi che “divergono” dal discorso corrente, e soprattutto in questo caso se gli metti in mezzo matrici bidimensionali, for(), eccetera (tra l’altro senza scrivere almeno il codice dentro ad un blocco “code”) generi solo confusione in chi vorrebbe imparare.

Quindi ti prego, non aggiungere altri post, aspettiamo e lasciamolo fare con calma, una cosa per volta.

Dunque, innanzi tutto grazie per l'aiuto che mi state dando! Vorrei esporvi il come pensavo di creare la funzione:
-Innanzitutto ho pensato di fare un ciclo for che "girasse" tra le colonne con all'interno un ciclo for che "girasse" tra le righe. Ho desistito perché mi sono accorto che per ogni tasto avrei dovuto comunque riscrivere tutto.
-A questo punto ho pensato di usare un ciclo for per le colonne ed un ciclo for per le righe come sopra, ma di aggiungere una matrice lineare (con una sola riga, spero si dica così) per ogni colonna di tasti e prendere i valori da lì:
passando con il for da una colonna ad un' altra (di tasti) vado a leggere la relativa matrice, ed in base al pin che mi da il LOW (della riga), stampo a terminale il tasto corrispondente.
-A questo punto avevo anche pensato ad una soluzione simile a quella consigliata (matrice bidimensionale) essendo la naturale evoluzione del secondo punto, MA prima vorrei tentare la soluzione 2. Vi aggiornerò appena possibile.

Una matrice unidimensionale (array) di 4 elementi per ognuna delle 4 colonne equivale a una sola matrice 4x4.
Vai, inizia! :slight_smile:

Buonasera, dopo qualche ora a spaccarmi la testa sono giunto ad un punto verosimilmente morto: l'utilizzo di 4 matrici (colonna1,colonna2, colonna3 e colonna4) mi permette tramite un ciclo for di spaziare tra tutte le colonne. Aggiungendo un ciclo switch vado a capire in quale matrice prendere i valori, ma poi mi trovo un secondo ciclo for per leggere i pin delle righe e relativo ciclo switch per estrapolare il valore char del tasto come return. In tutto questo ho dovuto creare le variabili di riferimento alle matrici di colonna e le altre variabili che mi permettano di "far funzionare" (tra virgolette perchè devo ancora finire) il tutto. Credo di stare andando nella direzione opposta perché mi pare tutto più incasinato di prima :confused: :confused:

teius92:
Credo di stare andando nella direzione opposta perché mi pare tutto più incasinato di prima

Appunto, come dicevo (e dico sempre) fare UNA cosa per volta. Inutile cercare di rivoluzionare completamente un codice se non hai un pieno controllo del linguaggio. Tra l'altro in genere è sempre consigliabile postare il codice, anche non funzionante, al quale sei giunto altrimenti come possiamo consigliarti?

In ogni caso ripeto, riparti dal primo codice (ovviamente la versione nella quale hai trovato e corretto l'errore) ed inizia ad identificare esattamente il singolo "blocco" di codice relativo ad una colonna.

Provo a spiegarti, dandoti il primo spunto.
Questo è il primo "blocco" relativo alla prima colonna:

  digitalWrite(col1, LOW);
  delay(30);
  if (digitalRead(riga1) == LOW) {
    Serial.println("1");
    while (digitalRead(riga1) == LOW) {
      delay(100);
    }
  }
  if (digitalRead(riga2) == LOW) {
    Serial.println("4");
    while (digitalRead(riga2) == LOW) {
      delay(100);
    }
  }
  if (digitalRead(riga3) == LOW) {
    Serial.println("7");
    while (digitalRead(riga3) == LOW) {
      delay(100);
    }
  }
  if (digitalRead(riga4) == LOW) {
    Serial.println("*");
    while (digitalRead(riga4) == LOW) {
      delay(100);
    }
  }
  digitalWrite(col1, HIGH);
  delay(30);

In cosa differisce questo blocco dai successivi? Il pin di colonna ed i 4 caratteri corrispondenti, esatto?

Quindi per iniziare a generalizzarlo potresti creare una funzione alla quale passare a parametro questi valori (ci sono anche altri modi, sicuramente migliori, ma più complicati e questo è quello più semplice e "diretto" per passare dal vecchio codice), ossia:

void leggiColonna(int pinCol, char car1, char car2, char car3, char car4) {
  digitalWrite(pinCol, LOW);
  delay(30);
  if (digitalRead(riga1) == LOW) {
    Serial.println(car1);
    while (digitalRead(riga1) == LOW) {
      delay(100);
    }
  }
  if (digitalRead(riga2) == LOW) {
    Serial.println(car2);
    while (digitalRead(riga2) == LOW) {
      delay(100);
    }
  }
  if (digitalRead(riga3) == LOW) {
    Serial.println(car3);
    while (digitalRead(riga3) == LOW) {
      delay(100);
    }
  }
  if (digitalRead(riga4) == LOW) {
    Serial.println(car4);
    while (digitalRead(riga4) == LOW) {
      delay(100);
    }
  }
  digitalWrite(pinCol, HIGH);
  delay(30);
}

Come vedi, ho cambiato il riferimento al pin di colonna con un parametro "pinCol", ed i 4 caratteri con altrettanti parametri di tipo char, che uso per fare il Serial.println().

Quindi ora nel loop() la userai così:

void loop() 
{
  leggiColonna(col1, '1', '4', '7', '*');
  leggiColonna(col2, '2', '5', '8', '0');
  leggiColonna(col3, '3', '6', '9', '#');
  leggiColonna(col4, 'A', 'B', 'C', 'D');
}

Vedi in che modo evitare di replicare blocchi di codice e creare invece una funzione parametrica ti semplifica di molto il loop? :wink: E questo tipo di semplificazione è sempre più essenziale all'aumentare della dimensione del codice!

Come "compito a casa", se vuoi divertirti a provare ad approfondire e quindi imparare a gestire queste cose, ti lascio questo:
come puoi vedere, anche all'interno della leggiColonna() ci sono 4 blocchi quasi uguali, e relativi alla singola riga:

  if (digitalRead(riga1) == LOW) {
    Serial.println(car1);
    while (digitalRead(riga1) == LOW) {
      delay(100);
    }
  }

Quali sono i "parametri" ossia cos'è che cambia tra un blocco e l'altro? Prova a creare una funzione "void leggiRiga()" alla quale passi come parametro il pin della riga ed il carattere da mostrare, e modifica la leggiColonna() per richiamare "leggiRiga(riga1, car1);" al posto del primo blocco "if", e così via per tutti e 4.
Ovviamente in caso di difficoltà, scrivi includendo sia il "nuovo" codice sia qual è il problema che hai riscontrato.

Ti ringrazio, ora ho capito l'errore che ho commesso nel nuovo caso: non passavo alla funzione i valori char, ma degli interi con i pin di riga da cui poi andare a trovare una corrispondenza con le matrici. Insomma non ho capito cosa dover usare per semplificare e così facendo ho incasinato tutto! :confused: ora cerco di capire la logica che hai usato e vi aggiorno. Grazie ancora e buona giornata!

Buonasera, ho provato e riprovato a creare una funzione ed ho capito che non ho la minima idea di come si faccia una trasformazione in funzione di uno sketch così “complesso”. Non ho ben chiaro il dove partire proprio :confused: :confused: perciò ho tentato un approccio diverso e sono passato per la strada iniziale usando le matrici, che è un metodo di cui riesco a capirne la logica. Dopo varie ore di studio ne è uscito questo:

int riga1=11;
int riga2=10;
int riga3=9;
int riga4=8;
int col1=7;
int col2=6;
int col3=5;
int col4=4;

char tastiera[4][4]={ {'1','2','3','A'},
                      {'4','5','6','B'},
                      {'7','8','9','C'},
                      {'*','0','#','D'}  };

int righe [4]={riga1,riga2,riga3,riga4};
int colonne[4]={col1,col2,col3,col4};


void setup() {
    pinMode(col1,OUTPUT);
    pinMode(col2,OUTPUT);
    pinMode(col3,OUTPUT);
    pinMode(col4,OUTPUT);
    
    pinMode(riga1,INPUT_PULLUP);
    pinMode(riga2,INPUT_PULLUP);
    pinMode(riga3,INPUT_PULLUP);
    pinMode(riga4,INPUT_PULLUP);
    
    digitalWrite(col1,HIGH);
    digitalWrite(col2,HIGH);
    digitalWrite(col3,HIGH);
    digitalWrite(col4,HIGH);
    
    Serial.begin(9600); 
}


void loop() {
    
    for (int x=0;x<4;x++) {
        digitalWrite(colonne[x],LOW);
        for (int y=0;y<4;y++) {
            if (digitalRead(righe[y])==LOW) { 
                Serial.println(tastiera[y][x]);
                while (digitalRead(righe[y])==LOW) {
                    ;
                }
            }
        }       
        digitalWrite(colonne[x],HIGH);
    }
}

Ho provato e funziona su Tinkercad, ma appena ne avrò il tempo lo testerò “dal vivo”.
Verrei però riuscire a capire anche le funzioni usando magari questo sketch perché mi incasina meno le idee del primo. Magari impostando il setup tramite funzioni ::slight_smile:

Bravo! 10+! :slight_smile: Lo dicevo che ce la potevi fare! :slight_smile:
…ma mi hai letto nel pensiero o sei riuscito a entrare nell’hard disk del mio computer?.. :o
Questo l’ho scritto e collaudato ieri:

byte col;
byte riga;
//           C  R   4 colonne per 4 righe
char simbolo[4][4]={{'1', '2', '3', 'A'}, // Riga 1
                    {'4', '5', '6', 'B'}, // Riga 2
                    {'7', '8', '9', 'C'}, // Riga 3
                    {'*', '0', '#', 'D'}};// Riga 4
void setup()
{
//   I/O 76543210
 DDRD|=0b00111100; // I/O 2,3,4,5: uscite.
PORTD|=0b11111100; // I/O 6,7: input pullup; uscite 2,3,4,5 a livello alto.

//   I/O(d)1111  // Leggere in verticale: 13-12-11-10-9-8.
//   I/O(u)321098
PORTB|=0b00000011; // I/O 8,9: input pullup.
Serial.begin(9600);
}

void loop()
{
for(col=2; col<=5; col++)
  {
  digitalWrite(col, LOW);
  for(riga=6; riga<=9; riga++)
    {
    if(!digitalRead(riga)) // Se è a livello basso:
      {
      Serial.println(simbolo[col-2][riga-6]);
      delay(300);
      }
    }
  digitalWrite(col, HIGH);
  }
}

Sinceramente la parte iniziale del tuo sketch non la capisco proprio, mi sembra arabo…tempo al tempo però avrà senso anche lei.
Nel frattempo ho tentato la creazione di funzioni per snellire il setup() e fare un po’ di pratica, spero siano fatte correttamente(funzionare funzionano, però vorrei sapere un vostro parere).

void setColTastiera(int coln1, int coln2, int coln3,int coln4) {
    int arrayColn[4]={coln1,coln2,coln3,coln4};
    for (int a=0;a<4;a++) {
        pinMode(arrayColn[a],OUTPUT);
        digitalWrite(arrayColn[a],HIGH);
    }
}

void setRigheTastiera(int rig1,int rig2,int rig3,int rig4) {
    int arrayRighe[4]={rig1,rig2,rig3,rig4};
    for (int b=0;b<4;b++) {
        pinMode(arrayRighe[b],INPUT_PULLUP);
    }
}

int riga1=11;
int riga2=10;
int riga3=9;
int riga4=8;
int col1=7;
int col2=6;
int col3=5;
int col4=4;

char tastiera[4][4]={ {'1','2','3','A'},
                      {'4','5','6','B'},
                      {'7','8','9','C'},
                      {'*','0','#','D'}  };

int righe [4]={riga1,riga2,riga3,riga4};
int colonne[4]={col1,col2,col3,col4};


void setup() {
    setColTastiera(col1,col2,col3,col4);
    setRigheTastiera(riga1,riga2,riga3,riga4);
    Serial.begin(9600);
}


void loop() {
    
    for (int x=0;x<4;x++) {
        digitalWrite(colonne[x],LOW);
        for (int y=0;y<4;y++) {
            if (digitalRead(righe[y])==LOW) { 
                Serial.println(tastiera[y][x]);
                while (digitalRead(righe[y])==LOW) {
                    ;
                }
            }
        }       
        digitalWrite(colonne[x],HIGH);
    }
}

Ma ora incontro un nuovo dubbio: non potrei tramite una funzione modificare o meglio creare una variabile utilizzabile al di fuori della funzione stessa? Ovvero, prendendo le sketch precedente come esempio:
-Richiamo funzione colonne con relativi parametri
-Richiamo funzione righe con relativi parametri
-Mi ritrovo “compilate” le 2 matrici usate nel ciclo for contenuto nel loop()

Chiedo questo perché così facendo creando una funzione per il ciclo contenuto nel loop() potrei paradossalmente impostare N tastierini in tempi molto brevi facendo un impostazione del tipo(esempio 2 tastierini):

-char array tastiera1
-char array tastiera2
setup()
-Funzione colonne tastiera 1
-Funzione righe tastiera 1
-Funzione colonne tastiera 2
-Funzione righe tastiera 2
loop()
Funzione tasti tastiera 1
Funzione tasti tastiera 2

Vi ringrazio per le risposte e chiedo scusa anticipatamente se dovessi essere stato poco chiaro.

teius92:
Buonasera, ho provato e riprovato a creare una funzione ed ho capito che non ho la minima idea di come si faccia una trasformazione in funzione di uno sketch così "complesso". Non ho ben chiaro il dove partire proprio

Scusa, ma hai notato che nel mio post ti ho SCRITTO la funzione e come richiamarla? L'hai visto? Hai cercato di capire come ho fatto? E l'hai provata?

Quello che eventualmente ti chiedevo poi di fare, come esercizio, era solo di provare a crearne una nuova per snellire ulteriormente la prima, seguendo l'esempio che ti ho fatto.
Ripeto, se ti metti a trafficare con cose che non conosci affatto diventa difficile, fai un passo alla volta.