Go Down

Topic: Problema bitshift uint32_t (Read 819 times) previous topic - next topic

niki77

Buongiorno a tutti.
Sto lavorando ad un pezzo di codice che mi dovrebbe permettere di valorizzare una variabile di tipo uint32_t (a mo di registro PINx)con lo stato di alcuni ingressi di un micro.
Alcuni di questi ingressi sono fisicamente sulle porte del micro, altri risiedono in un port expander i2c .

Ho deciso di andare ad assemblare il valore di quel registro effettuando operazioni di 'bitshift' e 'and' per formarne il valore :

Code: [Select]


uint8_t  port_a;
uint8_t  port_b;
uint8_t internal_inputs =((PINB & 0x06)>>1) + (((PIND & 0xf0)>>4)<< 2) + (((PINC & 0x0c)>>2)<< 6);
_mux.GetMuxStatus(&port_a,&port_b);
Serial.println(port_a);
Serial.println(port_b);
Serial.println(internal_inputs);
uint32_t current_bus = (port_a + (port_b <<8) + (internal_inputs << 12)& 0xfffff;
Serial.println( current_bus);



Con tutti i pin degli ingressi alti (pull'up esterni) ottengo correttamente i valori di port_a,port_b e internal_inputs.
Quando vado a variare lo stato di un ingresso di port_a o port_b , varia il suo valore relativo(port_a o port_b ovviamente) e varia il valore anche di current_bus.
Se invece vado a variare lo stato di un  pin collegato direttamente al micro, varia correttamente internal_inputs , ma sorpresa delle sorprese current_bus non cambia.
E' un limite di architettura del micro o mi è sfuggito qualcosa?(l'operazione di shift su internal_inputs penso coinvolga 3 byte)

Grazie in anticipo.
Vi è una spiegazione scientifica a tutto.
La fede è solo quell'anello che si porta al dito dopo il matrimonio.

astrobeed

Dato che le variabili associate ai port sono unsigned char devi usare il casting per promuoverle come unsigned int, o long,  prima di effettuare lo shift altrimenti il loro valore diventa 0 perché i bit shiftati vanno persi.

Code: [Select]

uint32_t current_bus = (port_a +  ((unsigned int) port_b <<8) + (unsigned int)((unsigned long) internal_inputs << 12)& 0xfffff;

niki77

Ok, grazie, lo provo subito.
Supponevo che mi ero perso qualche pezzo.

il punto che

Code: [Select]


uint8_t internal_inputs =((PINB & 0x06)>>1) + (((PIND & 0xf0)>>4)<< 2) + (((PINC & 0x0c)>>2)<< 6);



non crei problemi è dato dal fatto che nonostante lo shift di bit il valore non sfora mai il byte di lunghezza?
Vi è una spiegazione scientifica a tutto.
La fede è solo quell'anello che si porta al dito dopo il matrimonio.

astrobeed


non crei problemi è dato dal fatto che nonostante lo shift di bit il valore non sfora mai il byte di lunghezza?


Il problema lo hai solo se shifti verso sinistra perché presuppone un aumento del valore numerico, a meno che non lo fai apposta per perdere bit o traslare un indirizzo come nel caso della I2C, mentre se shifti verso destra il valore numerico diminuisce e non serve il casting.

niki77

#4
Jan 04, 2013, 10:06 am Last Edit: Jan 04, 2013, 10:09 am by niki77 Reason: 1
Ho utilizzato quella tecnica per mascherare e portare in posizione dei bit di alcuni registri in maniera tale da avere omogeneamente una variabile contenente i valori ordinati come fanno comodo a me, penso e spero sia codice efficiente , del resto dovrebbero essere tutte istruzioni native.

Ho capito perfettamente quindi se faccio:

byte a = 0xff;

a= (a <<4) >>4 ; mi perdo i 4 bit più significativi perchè prima li sposta verso sx di 4 posizioni , quindi fuori dalla portata del tipo byte, poi li riporta a dx ma a quel punto se li è già persi pertanto non li può recuperare.

se invece di byte utilizzo uint16_t, questo non accade.

Ho erroneamente pensato (e poi pensandoci bene non so neanche su che basi) che l'importante fosse che il valore dell'operazione finita stesse nei limiti del tipo di dato utilizzato.

Grazie Astro, contributo prezioso come sempre.
Vi è una spiegazione scientifica a tutto.
La fede è solo quell'anello che si porta al dito dopo il matrimonio.

PaoloP

E se usassi una union?

Code: [Select]

union UnionOfPins {
port_a:8;
port_b:8;
internal_inputs:16;
uint32_t myPort;
} myUnionOfPins;


Code: [Select]

myUnionOfPins.myPort = 0xff;



niki77

Se usassi una union come quella che hai scritto tu penso che dovrei portarmi dietro 8 byte invece di 4.

Potrei aver detto una castroneria, non uso molto le union.
Comunque non hai notato bene come ho assemblato i valori, in realtà io vado a formare una variabile a 20bit utili, di cui ogni bit corrisponde esattamente al suo numero di ingresso.
Con la union che proponi, myPort conterrebbe comunque 4 bit inutili di port_b.

Poi non trovo corretto questo :

Code: [Select]

myUnionOfPins.myPort = 0xff;


Eventualmente dovrebbe essere 0xfffff (20 bit)

Vi è una spiegazione scientifica a tutto.
La fede è solo quell'anello che si porta al dito dopo il matrimonio.

Go Up