Problema con unsigned e or

Salve a tutti,

illustro brevemente il mio problema.

Sto cercando di inizializzare un pacchetto a 17 bit contenente diversi campi.

Precisamente è formato da :
campo A : 3 bit
campo B : 5 bit
campo C : 8 bit
campo D : 1 bit

AAAB BBBB CCCC CCCC D

come variabile ho scelto l'unsigned long per via della lunghezza (maledetto bit di parità...che mi fa sforare a 17 bit !!!)

In linguaggio C ho fatto nel seguente modo , e va tutto bene :

#include <stdio.h>
#include <stdlib.h>

int main(void) {


	int campoA = 3;
	int campoB = 4;
	int campoC = 10;
	unsigned long pacchetto = 0;
	int parity;



	campoA = campoA << 14;
	campoB = campoB << 9;
	campoC = campoC << 1;

	tag = campoA | campoB | campoC ;

	printf("%X",pacchetto );

       // controllo di parità da completare


	return EXIT_SUCCESS;
}

e naturalmente il risultato è il seguente :

C814

tradotto in binario

011 00100 00001010 0

Quindi tutto ok in C.

Per arduino, con il seguente sorgente, ho dei problemi :

int CampoA = 3;
int CampoB = 4;
int CampoC = 10;
int Parity=0;
unsigned long pacchetto = 0;

void pac()  {
  CampoA = CampoA << 14;
  CampoB = CampoB << 9;
  CampoC = CampoC  << 1;
  pacchetto = CampoA | CampoB | CampoC ;
 }

void setup() {
  Serial.begin(9600);
  pac();
  Serial.println(pacchetto,BIN);
}

void loop() {
}

e il risultato è il seguente :

11111111111111111100100000010100

Ovvero ho i i primi 16 bit tutti settati ad uno.

Mi è sfuggito qualcosa oppure ho commesso qualche errore ?

Grazie in anticipo

E' questione di formato della variabile.
Invece di unsigned long usa:

uint16_t pacchetto = 0;

Grazie mille,

un caffè e un cornetto al primo incontro :slight_smile:

Direi che accetto volentieri! XD

prova a informati sui bit fields... :grin:

dalubar mi spieghi perchp con uint funziona e con unsigned long no? io pensavo che unsigned long fosse una "label" di uint.... e comunque perchè anche se non lo fosse dovrebbe avere un comportamento simile

...io pensavo che unsigned long fosse una "label" di uint.... e comunque perchè anche se non lo fosse dovrebbe avere un comportamento simile

E' in effetti è proprio così. La prova di ciò è che velocino usando il linguaggio C non ha problemi usando unsigned int.
In effetti il comportamento su Arduino ha il sapore di un vero e proprio bug; io stesso ho dovuto scontrarmi con questo problema diverso tempo fa, in un progetto nel quale mi serviva manipolare i bit in modo simile a quanto fa velocino ed è per questo che ho potuto rispondere con sicurezza al post.
Il sospetto che sia un bug mi è dato dal fatto che lo strano riempimento di "1" della parte più significativa della variabile avviene solo dopo un certo numero di shift a sx, e non da subito. La prima cosa che mi viene in mente osservando questo comportamento è che ci sia un problema di "riporto" durante la "rotazione" dei bit e che quindi dopo un certo numero di posizioni il valore sia trasformato (erroneamente) in "signed" ovvero nel suo corrispondente negativo (ennesimo problema della toolchain?).
Secondo me, comunque, occorrerebbe far presente questa sorta di "anomalia", dato che, in determinati impieghi a livello di codice, si potrebbe impazzire cercando un errore nel proprio codice che in effetti "non c'è", dando per scontato che la variabile si comporti nel modo in cui ci si aspetta.

sarebbe da capire se il nuymero di shift è 8 o 16...

però l'errore secondo me può risiedere in

campoA = campoA << 14;

molto probabilemnte campoA (che è int) va in overflow nel bit del segno..

quando poi cerchi di buttarla in int il compilatore la riporta ad un numero positivo, ma per farlo passa dal complemento a 2, sfalsando ulteriormente la già falsata variabile.

notare che se nel bit del segno finisce a caso uno 0, o campoA prima dello shif è 0 o 1, non succede nulla.

quando poi cerchi di buttarla in int il compilatore la riporta ad un numero positivo, ma per farlo passa dal complemento a 2, sfalsando ulteriormente la già falsata variabile.

Si, potrebbe essere.

ho avuto anch'io un problema simile, cioè dopo lo shift mi si è tramutato in negativo per via dell'1 al primo (ultimo) posto.
risolto dichiarandolo byte.
non so se applicabile anche qui.

se dichiara byte smena 8 bit e incasina tutto... semmai unsigned int

dalubar:

...io pensavo che unsigned long fosse una "label" di uint.... e comunque perchè anche se non lo fosse dovrebbe avere un comportamento simile

E' in effetti è proprio così. La prova di ciò è che velocino usando il linguaggio C non ha problemi usando unsigned int.
In effetti il comportamento su Arduino ha il sapore di un vero e proprio bug; io stesso ho dovuto scontrarmi con questo problema diverso tempo fa, in un progetto nel quale mi serviva manipolare i bit in modo simile a quanto fa velocino ed è per questo che ho potuto rispondere con sicurezza al post.
Il sospetto che sia un bug mi è dato dal fatto che lo strano riempimento di "1" della parte più significativa della variabile avviene solo dopo un certo numero di shift a sx, e non da subito. La prima cosa che mi viene in mente osservando questo comportamento è che ci sia un problema di "riporto" durante la "rotazione" dei bit e che quindi dopo un certo numero di posizioni il valore sia trasformato (erroneamente) in "signed" ovvero nel suo corrispondente negativo (ennesimo problema della toolchain?).
Secondo me, comunque, occorrerebbe far presente questa sorta di "anomalia", dato che, in determinati impieghi a livello di codice, si potrebbe impazzire cercando un errore nel proprio codice che in effetti "non c'è", dando per scontato che la variabile si comporti nel modo in cui ci si aspetta.

Anche io ho pensato ad un "bug", ma non essendo molto ferrato sul core di Arduino ho pensato subito ad un mio errore.