3

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?

psmears
  • 26,070
  • 4
  • 40
  • 48
Engine
  • 5,360
  • 18
  • 84
  • 162
  • Your data type `char` (which is signed) and format code `%d` (which is signed) define whether your values are interpreted as signed or unsigned integers. There is more detail on that in [this](http://stackoverflow.com/questions/22497382/how-to-find-out-if-a-variable-is-signed-or-unsingned/22498104#22498104) answer. – Jens Apr 23 '15 at 12:30
  • Prefer `"%" PRId16` to print `int16_t` – Mohit Jain Apr 23 '15 at 12:32
  • `LSB` and `MSB` mean `least significant BIT` and `most significant BIT`, please dont invent your own language ... – specializt Apr 23 '15 at 12:35
  • Are you sure you even want a signed result? – Weather Vane Apr 23 '15 at 12:36
  • 2
    @specializt - Although less common, `LSB` and `MSB` have certainly been used for byte rather than bit. Wikipedia agrees: http://en.wikipedia.org/wiki/Most_significant_bit – Steve Fallows Apr 23 '15 at 12:40
  • [citation needed]. I have _never_ seen or even heard of such a use of this term - and im in the business for quite some time now. Im guessing its what the internet superheros nowadays _want_ it to be - but thats it. – specializt Apr 23 '15 at 13:01

3 Answers3

3

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

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • the MIN should be -32768 = 0xffff – Engine Apr 23 '15 at 12:47
  • I am glad if it helps you. I hope you understood why did you need unsigned. – Mohit Jain Apr 23 '15 at 12:56
  • I've understood the unsigned but the I'm still trying with the rest – Engine Apr 23 '15 at 12:57
  • no need for cast before shifting? also he prints using wrong format specifier – Giorgi Moniava Apr 23 '15 at 12:58
  • @Giorgi You can see integral type promotion while shifting to understand why no cast is required. Correct way to print would be: `printf(" %4x temp %" PRId16 "\n", (unsigned int)temp, temp);` – Mohit Jain Apr 23 '15 at 13:01
  • @MohitJain: I thought shifting more than size of the object being shifted was not ok, e.g., 8 in this case – Giorgi Moniava Apr 23 '15 at 13:03
  • @Giorgi In C99 specs check section 6.5.7 Bitwise shift operators > Semantics (Same in C11 also): "The integer promotions are performed on each of the operands.The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the **promoted** left operand, the behavior is undefined." – Mohit Jain Apr 23 '15 at 13:06
0

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.

ouah
  • 142,963
  • 15
  • 272
  • 331
0

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.

shaunakde
  • 3,009
  • 3
  • 24
  • 39
  • I use the C99 standard header `` for portable size-annotated primitive types, e.g. `uint8_t` and corresponding `UINT8_MAX` etc. – Morten Jensen Apr 23 '15 at 13:00