[Arduino / C] Bitshift omzetten

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Knopsje
  • Registratie: November 2006
  • Laatst online: 03:51
Ik ben bezig een applicatie voor Arduino om te zetten naar een C applicatie om te draaien op een NRF51 van Nordic Semi. Over i2c lees ik een accelerometer uit en doe vervolgens wat met die data.

In Arduino is de code als volgt:
C:
1
2
3
4
5
6
7
8
9
10
byte Buffer[6];
    
short AccelRaw_x, AccelRaw_y, AccelRaw_z;
float Accel_x, Accel_y, Accel_z;

readReg(addr_A, LSM330D_OUT_X_L_A, 6, Buffer);
    
AccelRaw_x = ((Buffer[1] << 8) | Buffer[0]);
AccelRaw_x = AccelRaw_x >> 4;
Accel_x = AccelRaw_x * 0.001;


Voor de native applicatie heb ik er het volgende van gemaakt:

C:
1
2
3
4
5
6
7
8
9
10
uint8_t Buffer[6];
short AccelRaw_x, AccelRaw_y, AccelRaw_z;

float Accel_x, Accel_y, Accel_z;

readI2cData(LSM330D_A_ADDR0,LSM330D_OUT_X_L_A,Buffer,6);

AccelRaw_x = ((Buffer[1] << 8) | Buffer[0]);
AccelRaw_x = AccelRaw_x >> 4;
Accel_x = AccelRaw_x * 0.001;


Zoals te zien nagenoeg hetzelfde. De resultaten zijn dat echter niet. Op Arduino krijg ik het volgende:
C:
1
2
3
4
5
Buffer[0] = 96   
Buffer[1] = 254  
AccelRaw_x (1) = -416    
AccelRaw_x (2) = -26     
Accel_x = -0.03


In de native applicatie gebeurt echter het volgende:

C:
1
2
3
4
5
Buffer[0] = 96   
Buffer[1] = 254  
AccelRaw_x (1) = 24672 
AccelRaw_x (2) = 1542    
Accel_x = 1.542

De bitshift en bitwise OR zouden volgens mij hetzelfde moeten doen maar ik kan zelf het verschil in resultaat niet verklaren. Iemand die me een zetje in de goede richting kan geven?

[ Voor 32% gewijzigd door Knopsje op 15-06-2015 15:29 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 12-09 10:54

Janoz

Moderator Devschuur®

!litemod

Sowieso is het makkelijk om de getallen hexadecimaal neer te zetten. Op die manier is het duidelijker te zien wat er nu eigenlijk bij het shiften gebeurt (en wat er eventueel mis gaat)

maar als ik zo kijk lijkt het erop alsof bij de arduino de short signed is, terwijl het in de native app unsigned is.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
Je shift is undefined omdat je shift groter is dan wat in je uint8_t past.

[edit]
Hmmm, dit gaat over het promoted argument dus mijn statement is alleen waar als een int op jouw platform 8 bits zou zijn, wat volgens mij niet mag. Ff verder zoeken ....

[edit2]
Je uitkomst van 24672 is 0x6060, weet je zeker dat je niet 2x buffer[ 0 ] gebruikt?

[ Voor 70% gewijzigd door farlane op 15-06-2015 16:33 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Omisys
  • Registratie: Oktober 2010
  • Laatst online: 12-09 15:24
De short is default signed bij Arduino. Waarschijnlijk op jou chip is deze unsigned en krijg je deze rare output.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12-09 15:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, short == signed short != unsigned short. Alleen bij char is ongespecificeerd of dat signed of unsigned is.

Wat farlane zegt, het lijkt me gewoon een foutje in je code.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
24672 = 0x6060, 96 = 0x60.

Ik heb zo'n vermoede dat je de verkeerde waardes aan elkaar aan het shiften/or-en bent :)

Acties:
  • 0 Henk 'm!

  • Knopsje
  • Registratie: November 2006
  • Laatst online: 03:51
Door de getallen als hexadecimaal te printen zie ik inderdaad al wat beter wat er gebeurd:

Output Arduino
C:
1
2
3
4
5
6
Buffer[0] = 60
Buffer[1] = FE
(Buffer[1] << 8) = FFFFFE00
(Buffer[1] << 8 | Buffer[0]) = FFFFFE60
(FFFFFE60 >> 4) = FFFFFFE6
(FFFFFFE6 * 0,001) = -0.0259999990


Wat ik echter niet snap is waarom de Arduino dit doet: als ik een online bitshift calculator gebruik (klik) en FE << 8 doe dan komt er FE00 uit in plaats van FFFFFE00.
Daarnaast lijkt me regel 6 ook niet logisch: volgens elke online HEX converter zou FFFFFFE6 als decimaal 4294967270 zijn. Hoe kan het dan dat de output uiteindelijk -0,02 is? Dat is namelijk wel logisch want dat is 0G op de x-as, wat precies klopt. Ik zal vast iets over het hoofd zien maar snap niet wat er nou gebeurd 8)7

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12-09 15:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ah ja, blijkbaar is een "byte" op Arduino geen unsigned char maar een signed char ofwel een char (de signedness van die laatste is implementatie-afhankelijk, maar vaak gewoon signed). Hij wordt gepromote naar int, dus met sign extension krijg je 0xfffffffe. Het is voor je code overigens niet zo relevant. Je slaat het resultaat van de berekening namelijk op in een (signed) short die 16 bits is, dus de bovenste 16 bits worden toch genegeerd.

Dat neemt niet weg dat wat farlane en PrisonerOfPain al eerder zeiden gewoon klopt: 24672 = 0x6060, dus daar zit 2x een 0x60 in, oftewel beide buffer[0]. Dit komt niet overeen met je code, dus ik denk dat je ofwel de code ofwel de waardes niet exact hebt overgenomen.

[ Voor 15% gewijzigd door .oisyn op 16-06-2015 10:23 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
.oisyn schreef op dinsdag 16 juni 2015 @ 10:21:
Ah ja, blijkbaar is een "byte" op Arduino geen unsigned char maar een signed char ofwel een char (de signedness van die laatste is implementatie-afhankelijk, maar vaak gewoon signed).
Deze link suggereert dat een byte op Arduino unsigned is. dus ik snap even niet waarom het ding naar iets negatiefs wordt gepromote?

Of het is een debugger ding : TS waar (en hoe) haal je die geprinte waarden vandaan?

[ Voor 8% gewijzigd door farlane op 16-06-2015 11:43 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 03:22
.oisyn schreef op dinsdag 16 juni 2015 @ 10:21:
Ah ja, blijkbaar is een "byte" op Arduino geen unsigned char maar een signed char
Ik heb geen ervaring met Arduino, maar volgens deze documentatie is een byte unsigned.

Dat moet ook wel als we aannemen dat de Arduino-code in de TS correct is, want anders zou bij de conversie naar 16-bits (signed) short de sign-bit van de LSB over de hele MSB geschreven worden. De code zou dan zo iets moeten worden:
C++:
8
AccelRaw_x = ((Buffer[1] << 8) | (Buffer[0] & 0xff));

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12-09 15:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, want de lsb is 0x60 en dus niet negatief :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • deadinspace
  • Registratie: Juni 2001
  • Laatst online: 05-09 17:21

deadinspace

The what goes where now?

Er zit sowieso implementation-defined gedag in die code:
C:
1
2
3
4
5
short AccelRaw_x;

...
    
AccelRaw_x = AccelRaw_x >> 4;

Bij het right-shiften van negatieve signed integers is de waarden van de nieuwe bits implementation-defined.

Dat zal hier niet de issue zijn, maar het is wel iets dat problemen kan opleveren.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 03:22
.oisyn schreef op dinsdag 16 juni 2015 @ 14:58:
Nee, want de lsb is 0x60 en dus niet negatief :)
In dit specifieke voorbeeld ja, maar als je een 16-bits integer wil inlezen waarvan bit 7 toevallig 1 is (en om even heel pedantisch te zijn: een van de bits 8 t/m 15 0 zijn), dan werkt dat met de in de TS gegeven code niet als bytes signed zijn. Als we aannemen dat die code correct is, dan moet een byte in Arduino dus unsigend zijn.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12-09 15:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dacht dat ik mijn post nog geëdit had 8)7. Ik wilde er dus bijzeggen "in dit specifieke geval". Als byte inderdaad signed zou zijn zou de code idd niet kloppen nee.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1