Engine
Engine

Reputation: 5422

Reading 2 bytes in the correct way

I've a sensor that delivers its 16bits in this way : 1. MSB 2. LSB :

The values are in this range :

0xffff ===> -32767   MIN 
0x8000 ====> -1 LSB say -1 
0x0000 ====> +1 LSB say 1 
0x7FFF ====> 32767 MAX 

I'm trying to display these values in a readable way. For that I've written this small program:

#include <stdio.h>
#include <math.h>
#include <stdint.h>
int main(){
  char msbyte =0x7f;
  char lsbyte = 0xff;
  int16_t temp=0;
  temp = (msbyte<<8) | lsbyte;
  printf(" %4x temp %d ", temp,temp);

  return 0 ;

}

the result that I get is strange:

ffffffff temp -1

I expected the output to be:

7fff temp 32767

What am I doing wrong?

Upvotes: 3

Views: 659

Answers (3)

Mohit Jain
Mohit Jain

Reputation: 30489

Use the following:

uint8_t msbyte =0x7f;
uint8_t lsbyte = 0xff;

If char behaves as signed char on your implementation, lsbyte while oring would extend the sign bit and result may be unexpected. To solve the problem you should use unsigned char or uint8_t

Live demo

Although this way, the output range would be:

0xffff ===> -1 
0x8000 ====> -32768
0x0000 ====> +1 LSB say 1 
0x7FFF ====> 32767 MAX 

If you really want the range as you specified, do the following: (Keeping the msbyte and lsbyte unsigned)

int16_t num16=0;
temp = (msbyte<<8) | lsbyte;
num16 = (int16_t)(temp & 0x7FFF);  /* Get the number */
if(temp & 0x8000) { /* Get sign bit */
  num16 = num16 * -1 - 1;
}

Live demo

Upvotes: 3

shaunakde
shaunakde

Reputation: 3108

As mentioned your problem is that the high bit is being used as a sign bit.

You can avoid this using:

uint8_t msbyte =0x7f;
uint8_t lsbyte = 0xff;
uint16_t temp=0;

Additionally, I find using the AVR type defs, Short tutorial useful while handling embedded/device data.

For instance define:

typedef unsigned char BYTE
typedef unsigned int WORD

and use BYTE and WORD in your code.

Upvotes: 0

ouah
ouah

Reputation: 145829

Change:

char msbyte =0x7f;
char lsbyte = 0xff;

to

unsigned char msbyte =0x7f;
unsigned char lsbyte = 0xff;

char is a signed type on your implementation and undergoes sign extension when promoted to int.

Also change:

printf(" %4x temp %d ", temp,temp);

to

printf(" %4x temp %d ", (uint16_t) temp,temp);

to avoid signed extension if temp is negative.

Upvotes: 0

Related Questions