3 shift register in cascata, bit, byte, ShiftOut

Per "il solito" progetto che piano piano quando ho tempo sviluppo, dopo aver affrontato un po' di problemi hw, ora sono al lato sw....
Riassunto delle puntate precedenti: ho 12 coppie di relè, (1-12) e per ciascuna coppia ho un relè A e uno B (24 totali). Il sistema prevede di scegliere quali coppie attivare, e poi con un comando finale scegliere se di queste coppie attivare tutti i relè "A" o tutti i "B".

  • Per questioni di carico, qualunque siano i relè attivati, vengono eccitati a distanza di 250msec.
  • Per questioni realizzazione pratica, i 24 relè sono divisi su 3 pcb, quindi 8 relè (4 coppie) su ogni pcb.
  • Per questioni di pin/cablaggio, i 3 pcb sono comandati da 3 shift register (74HC595) collegati in cascata.

E veniamo al problema sw: trasmettere alla cascata di pcb/shiftregister un treno di 24 comandi ogni 250msec.
Poniamo che ho un array di 12 0/1 (integer?) che corrispondono alle coppie. A seconda che voglio attivare gli "A" o i "B", questo viene poi trasformato in un array di 24 posti, costituito da 0 nelle posizioni pari (per gli A) o dispari (per i B) alternati ai valori del primo array.
Ok, fin qua (come teoria) ci siamo con un po' di if e for.

Prima domanda: ma 'sto array di 24 0/1 occupa 3 byte, o è una obesa stringa di 24 byte? mi sa la seconda, vero? specie se lo dichiaro integer. Ma ho letto che anche i boolean sono memorizzati come byte e non bit... sono confuso.

Secondo tema: per come è fatto in sè uno shift register, per come sono collegati 3 in cascata, e per come sono collegati ai relè, l'ordine di trasmissione dei dati non è sequenziale, ma i bit vanno trasmessi in ordine particolare. In pratica dei 24 bit (o 24 byte?!?) devo trasmettere prima il 3° "byte" (posizioni da 17 a 24), poi il 2°(da 9 a 16) e infine il 1° (da 1 a 8).

Quindi: l'array di 24 0/1 che temo siano 24 byte integer e non 24 bit boolean, può essere convertito (e spezzato) in 3 byte cioè 24 bit?
posso applicare robe tipo highByte() o lowByte()?

Se me ne fregassi e passassi un array di 8 integer ad uno ShiftOut() per comandare il 74HC595, questo li piglia come 8 bit o come 64 bit (cioè 8 byte)? cioè piglia l'integer "0" (00000000) come 0 e l'integer "1" (00000001) come 1, o dopo il primo integer dell'array è già "saturo" e gli altri 7 elementi lo incasinano?

non posto codice perchè per ora sono alla fase di "bozza logica" a base di "qui fa questo e qua fa quell'altro", tipo dei dati, come li deve manipolare, ecc, e quindi sintatticamente "non c'è".
Grazie dei chiarimenti :slight_smile:

Sono solo tre byte da inviare. Il primo trasmesso finisce sul registro più lontano da Arduino. Se hai un array di 24 valori hai due possibilità, crearti i byte prendendo questi valori a gruppi di 8 e trasmetterli con shiftOut, oppure scriverti uno shiftOut da 24 bit (è un semplice ciclo for con delle digitalWrite... non serve neppure pensare ai bit).

Non sono riuscito a capire come creare il byte a partire da un array.
basta che l'array sia lungo 8 e dichiarato bool, ed è "automaticamente" un byte, o va fatto in altro modo?

per es:

bool[8] mioByte={1,1,1,1,1,1,1,1};

mioByte è davvero un byte che posso passare a ShiftOut o no? :confused:

byte mioByte = 0xFF; // inizializza tutti i bit a 1
byte mioByte = 0; // inizializza tutti i bit a 0 puoin anche scrivere 0x00 per simmetria rispetto alla riga sopra.

per leggere il primo bit a destra:

bitRead(mioByte, 0));

per scriverci 0:

bitClear(mioByte, 0);

per scriverci 1:

bitSet(mioByte, 0);

per scriverci il valore 0 o 1:

bitWrite(mioByte, 0, 0) oppure bitWrite(mioByte, 0 , 1);

puoi anche fare bitWrite(mioByte, 0, digitalRead(PIN_DIGITARE));

per scrivere il valore sulla seriale:

Serial.print(mioByte, BIN);

ecc. ecc. ecc.

Per lo shiftOut() ti rimando al reference...

cinquevolt:

bool[8] mioByte={1,1,1,1,1,1,1,1};

mioByte è davvero un byte che posso passare a ShiftOut o no? :confused:

Un array di 8 bool sono in realtà 8 byte (su Arduino byte, uint8_t, bool/boolean, unsigned char sono la stessa cosa).

Si può usare una funzioncina per assemblare un vero byte dall'array e dall'indice di partenza (non testata):

byte makeByte(byte[] data, int addr)
{
    byte myByte;
    for (int i=addr;  i < addr+8;  i++) { myByte = (myByte << 1) | data[i]; }
    return myByte;
}

maubarzi:
byte mioByte = 0B11111111; // inizializza tutti i bit a 1
byte mioByte = 0; // inizializza tutti i bit a 0 puoin anche scrivere 0B00000000 per simmetria rispetto alla riga sopra.

per leggere il primo bit a destra:

bitRead(mioByte, 0));
....

funziona anche con tipi di dati diversi da byte, giusto? tipo o unsigned long (32bit)?

Claudio_FF:
Un array di 8 bool sono in realtà 8 byte (su Arduino byte, uint8_t, bool/boolean, unsigned char sono la stessa cosa).

Ah, ecco, mi pareva... Peccato!

Si può usare una funzioncina per assemblare un vero byte dall'array e dall'indice di partenza (non testata):

byte makeByte(byte[] data, int addr)

{
    byte myByte;
    for (int i=addr;  i < addr+8;  i++) { myByte = (myByte << 1) | data[i]; }
    return myByte;
}

hmm qua vado un po' in overflow delle mie competenze di C... :smiley:
non capisco bene
"(byte[] data, int addr)" : significa che gli passi l'array e il punto da cui estrarre il byte, esatto?
"(myByte << 1) | data*". questo è proprio oscuro, devo leggermi un po' di references << - Arduino Reference*
Grazie a tutti :wink:

cinquevolt:
funziona anche con tipi di dati diversi da byte, giusto? tipo o unsigned long (32bit)?

Si

Occhio che la notazione 0Bnnnn NON è standard del 'C' , che riconosce solo la notazione decimale, ottale (0nnnn) ed esadecimale (0xnnnn). Un estensione di GCC ne permette l'uso, ma in altri compilatori può dare errore.

Non per nulla, il "core" Arduino, ha sempre incluso un file di nome "binary.h" che definisce, con delle vere e proprie #define, tutti i valori da 0B00000000 a 0B11111111 (quindi solo byte) perché, un tempo, la detta notazione NON era ammessa.

Solo a fini documentativi, comunque, l'eventuale mancanza, si risove facilemente con una piccola funzioncina definità così:

#define B(x) S_to_binary_(#x)
static inline uint32_t S_to_binary_(const char *s)
{
        uint32_t i = 0;
        while (*s) {
                i <<= 1;
                i += *s++ - '0';
        }
        return i;
}

... da richiamare con la seguente sintassi:

uint8_t pippo;
...
pippo = B(00110101);

Guglielmo

Ok, ho corretto in notazione esadecimale che è anche più compatta :wink:
Grazie per la precisazione.