Go Down

Topic: [RISOLTO] Problema nel pilotaggio di 4 shift register (SN74HC595N) +32 LED (Read 255 times) previous topic - next topic

brun0filipp0

Salve,
sto riscontrando dei problemi nel pilotaggio di 4 registri a scorrimento e 32 LED in quanto il programma che ho provato a scrivere non sembra avere problemi di sintassi ma a quanto pare non fa bene il suo lavoro. Il mio intento era quello di far scorrere l'accensione di un led alla volta per tutti e 32 i led partendo da destra verso sinistra e poi da sinistra verso destra(a ripetizione ovviamente).
Allego anche una piccola gif del funzionamento attuale del progetto:

Code: [Select]
#define data_ 2
#define latch_ 3
#define clock_ 4
void setup() {
 pinMode(data_, OUTPUT);
 pinMode(latch_, OUTPUT);
 pinMode(clock_, OUTPUT);

}

void loop() {
animazione1(30);   //tempo di accensione tra un LED e l'altro
}

void scritturaregistro(unsigned long valore){          //funzione che si occupa del passaggio dei bit al registro
  digitalWrite(latch_, LOW);
  shiftOut(data_ ,clock_ ,MSBFIRST , valore >> 24 );   //sposto le cifre più significative "in fondo" fino al 32 esimo LED
  shiftOut(data_ ,clock_ ,MSBFIRST , valore >> 16 );
  shiftOut(data_ ,clock_ ,MSBFIRST , valore >> 8 );
  shiftOut(data_ ,clock_ ,MSBFIRST , valore);
  digitalWrite(latch_, HIGH);      }

void animazione1(unsigned int animationdelay){     //funzione che si occupa dell'unica (fin ora) animazione che ho creato
 for(long i = 0 ; i < 32 ; i++){
  scritturaregistro(0x1 << i);      //il problema sembra essere qui (scorrimento da sinistra verso destra)
  delay(animationdelay);
  }
  for(long i = 0 ; i < 32 ; i++){
  scritturaregistro(0x80000000 >> i);    //quest'animazione di scorrimento di LED verso sinistra sembra funzionare correttamente
  delay(animationdelay);
  }
                             }


Il problema è che nella prima animazione di scorrimento verso destra, per la prima metà dei led (i primi 16) l'animazione sembra andare correttamente , ma poi nella seconda metà (gli ultimi 16 led) si accendono tutti i led mancanti insieme e si spengono subito, e il programma attende il tempo che avrebbe messo a fare l'animazione correttamente e subito dopo parte con la seconda animazione verso sinistra che funziona correttamente. (tutto questo ovviamente si ripete a loop).
Ho provato a modificare l'esadecimale che definisce quali led devono essere accesi (perchè il problema dovrebbe essere quello) ma la cosa rimane invariata, o in certi casi peggiora. Qualcuno saprebbe risolvere questo problema?
Grazie in anticipo...   :)

fabpolli

Buona sera,
essendo il tuo primo post nella sezione Italiana del forum, nel rispetto del nostro regolamento, ti chiedo cortesemente di presentarti QUI (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 il su citato REGOLAMENTO ... Grazie. :)

brun0filipp0

Eh, ho subito fatto la mia presentazione ma il per quanto riguarda il regolamento l'ho letto prima di creare questo post, solo che la parte della presentazione non l'ho proprio guardata...

Errore mio. Ad ogni modo, sapresti darmi qualche consiglio riguardo al mio problema?

fabpolli

Non sono molto pratico della funzione shiftout e ammetto di non averci ragionato più di tanto sul tuo codice, comunque...
Da quel che sembra nella gif è che solo i primi due funzionino regolarmente (quindi zero shift e shift di 8 bit). Credo che il problema sia nel tipo del dato passato alla funzione shiftout. Puoi provare a racchiudere tra parentisi tonde l'operazione di shift dei bit
Code: [Select]

shiftOut(data_ ,clock_ ,MSBFIRST , (valore >> 16) );

e comunque quando si illuminano tutti penso sia la seconda parte dell'animazione a farglielo fare. Finché non funziona in un verso io commenterei la seconda parte per tentare di discriminare quando funziona correttamente da destra a sinistra e solo allora riattiverei la parte opposta.
Se, come penso, racchiudere tra parentesi non sortisce l'effetto desiderato prova ad usare varibili appoggio di tipo byte (o uint8_t) per ospitare lo shift dei bit e stampare il valore sulla seriale, in quel mdoo vedi subito se l'operazione va a buon fine leggendo i vari valori che passano sulla seriale, a tal scopo rallenta l'animazione innalzando il delay.

Claudio_FF

Potrebbe essere che: 0x1 << i

debba essere scritto: (unsigned long)0x1 << i

?
* * * * Una domanda ben posta è già mezza risposta * * * *

fabpolli

anche si, ora che mi ci hai fatto guardare c'è una differnza di definizione tra il parametro della funzione e il tipo definito nel for, magari è quello

brun0filipp0

Grazie!!
Esatto il problema era quello!
Code: [Select]

scritturaregistro((unsigned long)0x1 << i);


Una volta sostituito quella riga di codice con quello suggerito da voi, tutto sembra funzionare!
ringrazio tutti e due. Ora vorrei capire bene il motivo di questa cosa. Perchè qui ho dovuto inserire questa variabile mentre nel ciclo for andava bene come stava?
Grandissimi comunque... :)

fabpolli

Provo a spiegartelo, avevo intuito guardando il problema che tutto girasse attorno ad un problema di tipi di dato ma avevo indicato un punto errato poi @Claudio_FF, più bravo di me, ha individuato il punto corretto :)
Nei cicli for il problema non si manifestava in quanto tu hai definito il parametro (correttamente) unsigned long, questo tipo di dato è necessario e corretto per ospitare tutti i bit necessari a pilotare il dispositivo secondo quello che vuoi realizzare quindi li lo shift dei bit e il loro invio funziona correttamente.
Nella chiamata della funzione scritturaregistro fai un operazione tra un byte (0x1) ed un long (i), il compilatore che cerca sempre di ottimizzare al massimo risorse, velocità, ecc. tratta il dato come long e non come unsigned long. Quando ha spostato i bit di una valore pari a i per passare il dato alla funzione effettua un cast implicito ad unsigned long, però il valore contenuto nella variabile non è "corretto" rispetto a quanto ti aspetti di ottenere (il primo bit a sinistra del long viene usato per determinare se un numero è negativo, mentre nell'unsigned no, tale bit è trattato al pari degi altri) da qui il lampeggio simultaneo degli ultimi led.
Con il cast dichiarato ad unsigned long forzi il compilatore ad utilizzare tale tipo, perché tratta l'operazione non più tra un byte ed un long ma tra un unsigned long ed un long, e i valori contenuti nella variabile sono aderenti a quanto ti aspetti di ottenere nel tuo progetto.
Un po' lungo ma spero preciso e chiaro :)

brun0filipp0

Grazie, credo di aver capito cosa volevi spiegarmi. La prossima volta sarò più attento a precisare queste variabili.
Volevo fare un ultima domanda: potrei io inserire delle sequenze di bit casuali?(immagino di si) In modo da fare accendere i led randomicamente? Se provassi a fare questo tipo di animazione dovrei poter usare comunque le variabili che sto usando ora giusto?
forse utilizzando la funzione random di arduino... anche se quella ancora non la conosco...

fabpolli

Bhe si puoi fare quel che vuoi, passi alla tua funzione un valore a caso incluso nel range del unsigned long e la shiftout posizionerà i relativi bit 1 e 0 per l'output parallelo.
La funzione random è abbastanza banale da usare, leggi il reference e via

brun0filipp0


Go Up