unsigned long to byte[4] to unsigned long

Ho trovato diversi esempi in c c++ per la conversione, ma non trovo quello che fa byte to long corretto

unsigned long n;
byte buf[4];


n = 4294967295; //valore a 32 bit
              buf[0] = (byte)((n & 0xFF000000) >> 24 );
              buf[1] = (byte)((n & 0x00FF0000) >> 16 );
              buf[2] = (byte)((n & 0x0000FF00) >> 8 );
              buf[3] = (byte)((n & 0X000000FF));
                            
              Serial.println((String)buf[0] + " " + (String)buf[1] + " " + (String)buf[2] + " " + (String)buf[3]);
              
              n =  ( (buf[0] << 24) 
                   + (buf[1] << 16) 
                   + (buf[2] << 8) 
                   + (buf[3] ) );
              Serial.println(" riconversione da byte a unsigned long "+(String)n);  <<<<<<< errore

sembrerebbe che il passaggio da long a byte sia corretto:

4294967295 to byte 255 255 255 255

ma tutti i valori da byte a unsigned long sono sbagliati

Dovrei scrivere su eeprom diversi valori long, mi fate capire dove sbaglio?

grazie ciao

pablos:
Dovrei scrivere su eeprom diversi valori long, mi fate capire dove sbaglio?

Il codice che stai usando è inutilmente complicato e lungo da eseguire, usa una union e hai risolto il problema in modo elegante e con pochi cicli macchina una volta compilato.

union SCOMP_LONG	// union per scomporre un long, sia signed che unsigned, in byte
{
 long MyLong;
 char byte_s[4];	
} S_LONG;

Se scrivi un valore in MyLong hai i quattro byte dentro byte_s[0-3], se scrivi i byte nell'array ha nuovamente la long in MyLong, la cosa si applica anche ai float semplicemente cambiando il tipo di variabile per MyLong in float.

Grazie Astro, ma non ho capito come usarla nello sketck, ho cercato su google qualche info su come usare union, maaaaa un ciò capito molto, non la conosco :roll_eyes:

Va dichiarata fuori dal loop ?
come ci mando il mio n=4294967295 che non accetta nessuna var dall'esterno della func?

mi faresti per favore vedere come usarla? :stuck_out_tongue:

ciao

Riusando il codice di astro, una cosa del genere (non testato):

union SCOMP_LONG	// union per scomporre un long, sia signed che unsigned, in byte
{
 long MyLong;
 char byte_s[4];	
} S_LONG;

void setup() {
    S_LONG.MyLong = 45600000L;
    Serial.begin(9600);
}

void loop() {
    for (byte i=0; i<4; i++) {
        Serial.println(S_LONG.byte_s[i], DEC);
    }
}

pablos:
mi faresti per favore vedere come usarla? :stuck_out_tongue:

La union va dichiarata esternamente allo sketch, esattamente come si fa per le variabili globali, va bene l'esempio che ha scritto Leo.
Per ulteriore chiarezza se scrivi:

S_LONG.MyLong = 45600000L;

Hai i quattro byte dentro S_LONG.byte_s[0],S_LONG.byte_s[1],S_LONG.byte_s[2],S_LONG.byte_s[3].

Al contrario se poni i quattro byte in S_LONG.byte_s[n] dentro S_LONG.MyLong ottieni il valore del long.

In pratica sia l'array che la variabile long sono lo stesso dato e condividono lo stesso spazio nella ram, è esattamente la stessa cosa di creare una variabile long/float e un puntatore in cui carichi l'indirizzo di memoria di questa variabile, usando il puntatore puoi indirizzare i singoli byte della variabile.

Ho capito, mi sfuggiva l'impiego di S_LONG. davanti a Byte, grazie a te, a lui .... a te no! XD XD (by Gianni Cyano)
Quindi per il reverse c'e' qualche calcolo particolare?

o basta fare

for (byte i=0; i<4; i++)
{
n = S_LONG.byte_s*; *

  • }*
    perchè il numero ottenuto con questo for non è quello originale
    long 3698328080 to byte 16 2 112 220
    byte 16 2 112 220 to long 4294967260
    mentre per
    long 4294967295 to byte 255 255 255 255
    byte 255 255 255 255 to long 4294967295 <<<<<< giusto
    ciao

pablos:
Quindi per il reverse c'e' qualche calcolo particolare?

Se fai:

byte A,B,C,D;

S_LONG.MyLong = 123456789;
A=S_LONG.byte_s[0];
B=S_LONG.byte_s[1];
C=S_LONG.byte_s[2];
D=S_LONG.byte_s[3];

A,B,C,D, contengono i quattro byte che compongono il long, poi ci fai quello che ti pare.

Se fai:

S_LONG.byte_s[0] = A;
S_LONG.byte_s[1] = B;
S_LONG.byte_s[2] = C;
S_LONG.byte_s[3] = D;

S_LONG.MyLong contiene il valore corrispondente ai quattro byte caricati con A,B,C,D, va da se che l'ordine di ripristino deve essere lo stesso con cui hai prelevato i valori altrimenti in S_LONG.MyLong avrai un valore diverso da quello atteso.

Si certo il caricamento dei byte nell'array byte_s[] lo avevo capito.
La mia domanda era visto che ora ho i 4 byte, con quale calcolo ritorno al long di partenza?

Pensavo quindi che la stessa funzione potesse inversamente restituirmi il long dai 4 byte :roll_eyes:

ciao

ahhhh Ok .... ho capito grazie :slight_smile:

byte LongToByte[] = {0,0,0,0};
const unsigned long test = 1234567890;

union SCOMP_LONG// union per scomporre un long, sia signed che unsigned, in byte
{
 unsigned long MyLong;
 char byte_s[4];	
} S_LONG;

void setup() {
    Serial.begin(9600);
    S_LONG.MyLong = test;
    Serial.println("Unsigned long numero test >> "+(String)test);  
    
    for (byte i=0; i<4; i++) LongToByte[i] = S_LONG.byte_s[i];  //long to byte     
    Serial.println("Long to byte >> "+(String)LongToByte[0]+" "+(String)LongToByte[1]+" "+(String)LongToByte[2]+ " "+(String)LongToByte[3]); 
   
    for (byte i=0; i<4; i++) S_LONG.byte_s[i] = LongToByte[i];  //byte to long
    Serial.println("Byte to unsigned long >> "+(String)S_LONG.MyLong);      
}

void loop() {}

pablos:
La mia domanda era visto che ora ho i 4 byte, con quale calcolo ritorno al long di partenza?
Pensavo quindi che la stessa funzione potesse inversamente restituirmi il long dai 4 byte :roll_eyes:

Nessun calcolo, cosa non ti è chiaro del fatto che se riscrivi i 4 byte nell'array, nello stesso ordine, hai nuovamente il long nella variabile S_LONG.MyLong ?
Esempio pratico, se dentro all'array S_LONG.byte_s[] metti in tutti gli elementi 0xff in S_LONG.MyLong trovi il valore 4294967295.
Se in S_LONG.byte_s[] poni 0xff, 0xff, 0x00, 0x00, in S_LONG.MyLong trovi 4294901760.

hai nuovamente il long nella variabile S_LONG.MyLong ?

Si si Astro tutto chiaro ho nuovamente il long.

ciao

@pablos:
ma non avevi visto il mio esempio? :sweat_smile:

leo72:
@pablos:
ma non avevi visto il mio esempio? :sweat_smile:

Mi sa tanto che devi cambiare l'avatar con Calimero come Michele :grin:

E' il terzo post che dico "ho risolto" ahahahahahahhaha

leo72:
@pablos:
ma non avevi visto il mio esempio? :sweat_smile:

Si che l'ho usato, ho pubblicato anche lo sketch, ma il tuo esempio estraeva solo i byte da long e basta, poi ho cercato di usare la formula inversa per convertire i byte ottenuti in long, dopo prova e riprova ci sono riuscito.

Sarà l'ansia del 21/12/12 XD XD XD a proposito, sapete a che ora succede? avrei degli appuntamenti di lavoro..... :grin:

PS.
Siccome i miei long provengono da segnali 32bit IR che vanno confrontati con quelli pre-memorizzati su eeprom, ho notato che la libreria EthernetUdp.h usata nello stesso sketch va in conflitto con la IRremote.h
soluzione:
Reinizializzare la IRremote dopo aver interagito con la Udp ... irrecv.enableIRIn();

ciao .... addio

Visto che siamo ancora qui posso continuare il programma 8)

Come si potrebbero salvare 50 unsigned long senza uccidere la memoria? Sono intervalli del contatore millis(), 200 byte mi pesano un po' però.

Mi spiego meglio, si scatena l'evento n°10 e fallo durare per 2 minuti (120.000 ms), nel frattempo si scatena l'evento n°8 che va fatto durare 0.5 sec (500 ms), sono obbligato in qualche modo a registrare il timer e confrontarlo
a meno che non mi accontento di fare un impulso di durata massima 1 minuto usando un int array[] (valore max 60.000) ciascuno, non mi piace molto però.
Oppure un array di byte da moltiplicare poi x 1000 con un range da 1 sec a 4 min

@leo

Non voglio fare una cosa ogni tot tempo in task, ma solo allo scatenarsi di un evento, la libreria Leos potrebbe farlo?

ciao

Se gli intervalli devono durare più di 60 secondi, ti serve per forza un long. Quindi 200 byte.
Però potresti usare anche un chip SRAM esterno e salvare nelle sue celle gli intervalli, che recuperi con un indice.
O anche EEPROM, se non hai bisogno di riscriverlo continuamente.

Il leOS può essere usato per lanciare un task onetime, ossia che ne imposti l'intervallo, lui parte, esegue ciò che deve fare e poi si autocancella, rendendo quel posto nuovamente disponibile allo scheduler per un nuovo task.
Se non hai bisogno di un numero eccessivo di task, può forse fare al caso tuo.