Problema nella programmazione di uno shift register (TI 74HC595)

Gentili utenti,
ho incontrato difficoltà nella realizzazione di un piccolo progetto e credo che il problema sia del mio codice che ho scritto sulla falsariga di un esempio trovato online (data la mia poca esperienza).

Il progetto consiste nell'accendere dei led numerati da 1 a 9 attraverso uno shift register (TI 74HC595). In teoria mandando alla scheda un numero da 1 a 9 inserito dal monitor seriale, l'arduino dovrebbe accendere il led corrispondente e scrivendo A sul monitor seriale si dovrebbero spegnere tutti i led. Mentre per lo spegnimento non ho problemi, quando inserisco un numero si accende sempre lo stesso led.

Ho provato a fare alcuni cambiamenti e una delle differenze che ho notato è che modificando nella funzione shiftOut alla penultima riga MSBFIRST con LSBFIRST il led che si accende per ogni numero che digito cambia.

Credo che il problema sia nella parte in cui definisco la funzione registerWrite, in particolare nella creazione del byte che poi dovrebbe essere inviato allo shift register.

Essendo il mio primo topic, spero di aver rispettato tutte le norme del regolamento e spero di essere stato sufficientemente chiaro ed esauriente.

 int dataPin = 10;
int latchPin = 11;
int clockPin = 12;

void setup() {
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
Serial.begin(9600);
Serial.println("Inizio");

}

void loop() {
if (Serial.available() > 0) {
  if (Serial.read() == 65) {
    registerWrite(1, LOW);
    registerWrite(2, LOW);
    registerWrite(3, LOW);
    registerWrite(4, LOW);
    registerWrite(5, LOW);
    registerWrite(6, LOW);
    registerWrite(7, LOW);
    registerWrite(8, LOW);
    registerWrite(9, LOW);
    delay(2000);
  }
 else {
  int BIT = Serial.read() -48;
  registerWrite(BIT, HIGH);
 }
}
delay(1000);
}

void registerWrite(int WhichPin, int WhichState) {
  byte bitsToSend;
  digitalWrite(latchPin, LOW);
  bitWrite(bitsToSend, WhichPin, WhichState);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);
  digitalWrite(latchPin, HIGH);
}

Buonasera,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Buonasera,
la ringrazio per la preziosa indicazione. Purtroppo avevo letto un po' distrattamente la parte finale del regolamento perchè, sinceramente, ero piuttosto impaziente di ricevere aiuto. Mi scusi per l'errore.
Cordiali saluti

Se fai una

Serial.print(bitsToSend, BIN);

vedi esattamente cosa stai per trasmettere in binario.
Occhio che gli zeri a sinistra non li mette per cui se trovi che stampa 1 equivale a 00000001, ecc. :wink:

MSBFIRST o LSBFIRST indicano il verso di invio, se partendo dal bit più significativo, quindi nell'esempio sopra verrebbero inviati in sequenza questi bit 0 0 0 0 0 0 0 1 oppure dal meno significativo e quindi verrebbe inviato in sequenza 1 0 0 0 0 0 0 0
Nei due casi accenderesti il primo o l'ultimo bit a seconda dei due valori.

Poi, un byte ha 8 bit, quindi puoi gestire fino a 8 led.
Tu invii il valore numerico letto dalla seriale, che non va molto bene.
Perchè prevedi di impostare a 1 il bit che va da 1 a 9, invece quelli a disposizione sono da 0 a 7.

Ho scritto un po' in modo criptico perchè sono di fretta, se non bastano come imbeccate, magari ci si risente in seguito.

Grazie per le "imbeccate", credo, forse, di aver capito dove è il problema.
Come prima cosa ho eliminato il nono led e li ho numerati, anzichè da 1 a 8, da 0 a 7.
Poi ho inserito all'interno della funzione loop, come suggerito, un

 Serial.println(bitsToSend, BIN);

In effetti, quando digitavo un numero, mi mostrava sempre 1.

Ho provato, quindi, a testare singolarmente le funzioni che avevo messo in gioco (e che non conosco ancora molto bene) e credo di essermi imbattuto nel problema.

Ho caricato nella scheda il codice qui allegato:

 void setup() {
Serial.begin(9600);

}

void loop() {
byte A = B00000000;

if (Serial.available() > 0) {
 Serial.print(Serial.read(), DEC);
 Serial.print("___");
 bitWrite(A, Serial.read()-47, HIGH);
 Serial.println(A, BIN);
 delay(1000);
}

}

Ho digitato sul monitor seriale alcuni numeri a caso e infine la lettera A. Questo è quello che è apparso:
20:02:36.920 -> 50___1
20:02:39.276 -> 53___1
20:02:40.280 -> 54___1
20:02:43.543 -> 49___1
20:02:45.195 -> 51___1
20:02:47.457 -> 48___1
20:02:49.062 -> 65___1

Non riesco a capire come mai la funzione bitWrite non mi dia i risultati attesi (come 1000, 1000000, 10000000,100, ecc.).

Potrebbe essere dovuto al fatto che

maubarzi:
Tu invii il valore numerico letto dalla seriale, che non va molto bene.

?

Cordiali saluti

P.S. Perchè inviare il valore dalla seriale non va molto bene?

G__1:
P.S. Perchè inviare il valore dalla seriale non va molto bene?

Posso aver sbagliato,
mi pareva prendessi il carattere e lo inviassi come fosse un numero, quindi avevo scritto così perchè invece di 1 pensavo gli inviassi il valore ascii del carattere '1'.

Controlla il valore effettivo di

Serial.read()-47

A te serve un valore numerico, tipo int o meglio byte
Io dichiarerei una variabile di tipo byte e proverei a salvarci il valore che ti serve e terrei d'occhio la cosa finchè non ci finisce dentro il valore che mi aspetto

Ora scappo perchè devo innannare il cucciolo

Eccomi,
il post precedente era per stimolarti a verificare i casi, per essere sicuro che non faccia conversioni inattese, guardando però con più calma, si nota il vero errore.
Tu scrivi:

 Serial.print(Serial.read(), DEC);
 Serial.print("___");
 bitWrite(A, Serial.read()-47, HIGH);

Le due Serial.read() leggono due valori differenti, ti ricordo che la read rimuove il valore letto dal buffer.
Se hai digitato un solo carattere, la prima legge il carattere, la seconda non trova più nulla da leggere e ritorna -1.
Ora, il reference non lo specifica, ma secondo me se alla bitWrite, come indice del bit da modificare passi un valore non ammesso, viene considerato a 0 e quindi con questo codice metti sempre a 1 il bit in posizione 0 cioè quello meno significativo, in accordo con quello che ottieni come output.
Se vuoi usare più volte il carattere letto per fare più elaborazioni, te lo devi salvare su una variabile.

Grazie mille!
Ho creato una variabile su cui salvare il valore letto dalla seriale come hai suggerito e adesso non ci sono più intoppi. Allego la versione finale del codice per lo shift register per completezza.

int dataPin = 10;
int latchPin = 11;
int clockPin = 12;

void setup() {
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
Serial.begin(9600);
Serial.println("Inizio");

}

void loop() {
if (Serial.available() > 0) {
  int IN=Serial.read();
  if (IN == 65) {
    registerWrite(0, LOW);
    registerWrite(1, LOW);
    registerWrite(2, LOW);
    registerWrite(3, LOW);
    registerWrite(4, LOW);
    registerWrite(5, LOW);
    registerWrite(6, LOW);
    registerWrite(7, LOW);
    delay(1000);
  }
 else {
  int BIT = IN - 48;
  registerWrite(BIT, HIGH);
 }
}
delay(1000);

}

void registerWrite(int WhichPin, int WhichState) {
  byte bitsToSend = B00000000;
  digitalWrite(latchPin, LOW);
  bitWrite(bitsToSend, WhichPin, WhichState);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);
  digitalWrite(latchPin, HIGH);
  Serial.println(bitsToSend, BIN);
}

Ottimo!
Sei l'op tipo che tutti vorremmo :wink: due imbeccate veloci e poi si è arrangiato... :wink:
E grazie per il feedback finale, pare scontato ma anche questo in genere non lo è affatto.