convert signed int to bytes and back

Hey

So I am ables to convert an unsigned int to two bytes and rebuild it no problem.

int myInt = 900;
byte myBytes[2];
myBytes[0] = 900/256;
myBytes[1] = 900%256;
int newInt = myBytes[0]*256+myBytes[1];

also managed to do it this way

int myInt = 900;
byte myBytes[2];
myBytes[0] = (myInt >> 8);
myBytes[1] = myInt;
int newInt = (myBytes[0] << 8) | (myBytes[1]);

but as soon as i change 900 to -900 i get the result as 64636. I’m sure there must be a simple solution for this but my search of the forum and google only led me to the second method i showed above and it doesn’t work either.

try to change

byte myBytes[2];

to

signed char myBytes[2];

As an alternative:

union unionForm {
  byte myBytes[2];
  int myInt;
} myUnion;

void setup() {
  // put your setup code here, to run once:
  int testInt = 900;
  int newInt;
  
  Serial.begin(9600);
  myUnion.myInt = 900;
  Serial.print("900 in HEX = ");
  for (int i = 0; i < sizeof(int); i++) {
    Serial.print(myUnion.myBytes[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
  newInt = myUnion.myInt;
  Serial.print("newInt = ");
  Serial.println(newInt);
}

void loop() {

}

Since the program prints out 900 as 84 3, it gives you a clue as to the order in which the Arduino stores int data.

awesome thankyou robtillart!

Any chance you could explain why that works and bytes don't?

Hey me again…

I recently asked about converting a signed int to bytes and the answer i got here worked a charm! I am now considering doing the same with signed longs but expanding the method doesn’t appear to be working for me!

  int myInt = -900;
  signed char myBytes[2];
  myBytes[0] = (myInt >> 8);
  myBytes[1] = myInt;
  int newInt = (myBytes[0] << 8) | (myBytes[1]);
  Serial.println(newInt);
  delay(1000);
  
  long myLong = 123456;
  signed char myBytes2[4];
  myBytes2[0] = (myLong >> 24);
  myBytes2[1] = (myLong >> 16);
  myBytes2[2] = (myLong >> 8);
  myBytes2[3] = myLong;
  long newLong = (myBytes2[0] << 24) | (myBytes2[1] << 16) | (myBytes2[2] << 8) | (myBytes2[3]);
  Serial.println(newLong);
  delay(1000);

I get -7616 instead of 123456 :frowning: can’t even work this one out in positive numbers hah!

(if anyone is feeling like a prophet then you might have anticipated that floats are coming next - trying to exapnd the SpiRam library to make it allot less hassel to store ints, longs floats etc. GitHub - dmason1992/SpiRam_Extended: An extended version of the SpiRam library (includes functions for reading and writing variety of variable types) if interested)

google only led me to the second method i showed above and it doesn’t work either.

Are you sure? The “second method” you posted prints out -900 for me.

void setup() {
Serial.begin (9600);
int myInt = -900;
byte myBytes[2];
myBytes[0] = (myInt >> 8);
myBytes[1] = myInt;
int newInt = (myBytes[0] << 8) | (myBytes[1]);
Serial.print(newInt);
}

void loop() {}

I think this is basically the same topic so I am going to merge these threads.

  Serial.println (myBytes2[0] << 24);

That gives zero. You have shifted one byte left 24 bits. Ditto for:

  Serial.println (myBytes2[1] << 16);

Now the interesting bit:

  Serial.println (myBytes2[2] << 8);

That prints -7680.

The char was promoted to an int and shifted left 8 bits. Hence -7680.

Add 64 and you get -7616. Which is what you got for your result.

You have to consider intermediate data types in expressions.

http://www.gammon.com.au/forum/?id=12146

slzer:
(if anyone is feeling like a prophet then you might have anticipated that floats are coming next - trying to exapnd the SpiRam library to make it allot less hassel to store ints, longs floats etc. GitHub - dmason1992/SpiRam_Extended: An extended version of the SpiRam library (includes functions for reading and writing variety of variable types) if interested)

If that is your intention, then you are causing yourself a ton of hassle that could all be saved with the use of a union and two template functions, one to write and one to read.

Have a look at these two functions that I use for writing or reading any value from EEPROM. It works with floats, longs, bytes, chars, and even custom types like structs and class instances. Returning the number of bytes written or read would be optional in your case, you could have them return void. I thought it was nice to allow for stepping through EEPROM by address. Basically, you should be able to take these and change the EEPROM.write and read functions for whatever you need to send the individual bytes over to the SpiRam.

template<class T>
int writeToEEPROM(int address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  } 
  temp;

  temp.type = value;
  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    EEPROM.write(address + i, temp.b[i]);
  }
  return sizeof(T);
}


template<class T>
int readFromEEPROM(int address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  } 
  temp;

  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    temp.b[i] = EEPROM.read(address + i);
  }
  value = temp.type;
  return sizeof(T);
}

Have a look at these two functions that I use for writing or reading any value from EEPROM. It works with floats, longs, bytes, chars, and even custom types like structs and class instances.

Delta_G this looks like it could save me allot of time! I will have a look into it now

Nick I had a look at the article and from what i could tell i needed to try this (it didn’t work)

long myLong = 123456;
  signed char myBytes2[4];
  myBytes2[0] = char (myLong >> 24);
  myBytes2[1] = char (myLong >> 16);
  myBytes2[2] = char (myLong >> 8);
  myBytes2[3] = char (myLong);
  long newLong = (myBytes2[0] << 24) | (myBytes2[1] << 16) | (myBytes2[2] << 8) | (myBytes2[3]);
  Serial.println(newLong);
  delay(1000);

A byte is only 8 bits wide. So you can’t shift it 24 times left. You’ll shift the whole thing off into never never land.

Try it this way:

long newLong = ((long)myBytes2[0] << 24) | ((long)myBytes2[1] << 16) | ((int)myBytes2[2] << 8) | (myBytes2[3]);

But really, those unions will save you all the shifting headache.

Ok so trying the Unions ( something i am going to have to read up on! - only learnt programming through using arudino so i’m getting their slowly) I get this error

error: ‘T’ has not been declared

Also this still doesn’t seem to work - sorry for being so thick sculled here! prints out -7616

long myLong = 123456;
  signed char myBytes2[4];
  myBytes2[0] = (myLong >> 24);
  myBytes2[1] = (myLong >> 16);
  myBytes2[2] = (myLong >> 8);
  myBytes2[3] = myLong;
  long newLong = ((long)myBytes2[0] << 24) | ((long)myBytes2[1] << 16) | ((int)myBytes2[2] << 8) | (myBytes2[3]);
  Serial.println(newLong);
  delay(1000);

error: ‘T’ has not been declared

Ok so fixed this (forgot to include the template in the header file as well. Now i get this problem XD

D:\Users\Dropbox\Arduino\libraries\SpiRam_Extended\SpiRam_Extended.cpp: In function ‘int writeTest(long int, T&)’:
D:\Users\Dropbox\Arduino\libraries\SpiRam_Extended\SpiRam_Extended.cpp:195:37: error: there are no arguments to ‘_prepare’ that depend on a template parameter, so a declaration of ‘_prepare’ must be available [-fpermissive]
D:\Users\Dropbox\Arduino\libraries\SpiRam_Extended\SpiRam_Extended.cpp:195:37: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
D:\Users\Dropbox\Arduino\libraries\SpiRam_Extended\SpiRam_Extended.cpp: In function ‘int readTest(long int, T&)’:
D:\Users\Dropbox\Arduino\libraries\SpiRam_Extended\SpiRam_Extended.cpp:213:36: error: there are no arguments to ‘_prepare’ that depend on a template parameter, so a declaration of ‘_prepare’ must be available [-fpermissive]

I don't see a union in your posted code.

slzer: Ok so trying the Unions ( something i am going to have to read up on! - only learnt programming through using arudino so i'm getting their slowly) I get this error

The fact that the union was declared inside a template function was important. The template function gets defined for whatever type value is and T gets replaced with that type. If you want to try it with just the union and without the template, then you'll have to use long or int or whatever type you're trying to work with in place of the T.

I should also mention that Arduino will puke on template functions in an ino file. Those functions have to be defined in a .h file.

Ah sorry the stuff i quoted above was trying to fix the shifting method

cpp file

template<class T>
int writeTest(long address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  }
  temp;

  temp.type = value;
  _prepare(STREAM_MODE,WRITE,address);
  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    SPI.transfer(address + i, temp.b[i]);
  }
  return sizeof(T);
}


template<class T>
int readTest(long address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  }
  temp;

  _prepare(STREAM_MODE,READ,address);
  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    temp.b[i] = SPI.transfer(0xFF);
  }
  value = temp.type;
  return sizeof(T);
}

header file

template<class T>
    int writeTest(long address, T& value);
    template<class T>
    int readTest(long address, T& value);

Furthermore, the full definition of a template function has to be in the .h. Typically you declare functions in the .h and implement them in a .cpp, but for templates the whole shebang has to be in the .h or you'll get errors.

EDIT: I see what you posted while I was typing. It appears that is what happened to you.

Try this:

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  typedef union {
    long num;
    byte b [sizeof(long)];
  } myUnion;
  
  myUnion foo;
  foo.num = 123456;
  for (int i = 0; i < sizeof (long); i++)
    Serial.println ((int) foo.b [i]);
 
  // make another one
  myUnion bar;
  // copy each byte in
  for (int i = 0; i < sizeof (long); i++)
    bar.b [i] = foo.b [i];
  // print the resulting long
  Serial.println (bar.num);
  }  // end of setup
void loop () { }

Output:

64
226
1
0
123456

I tried this and it works on my Teensy 3.1 :slight_smile: - I’m gonna head to bed now but I will look into it more tomorrow and try to apply what you have shown me in this demo script to the library!

I’m sorry if this post is beside the point, as I quickly glanced over the posts rather than reading them.

The problem is sending multiple-byte-values over a serial interface that works on a per-byte basis. Obviously, longer types are stored as bytes, so all you need to do is take its address and convert this to a byte*. The union approach does the trick but seems a little verbose. Why not use reinterpret_cast?

long val = 0x89abcdef; // 4 bytes!
Serial.write(reinterpret_cast<byte*>(&val), sizeof(val));

Just keep in mind you might have to compensate for endianness when putting it back together at the other end of the line. Probably that’s not even necessary.

PS. Code not tested so could contain errors. I hope the idea is clear though.

Edit: By the way, this works for any type (floats, doubles, user-defined types, whatever). If you want, you can make it a (very simple, not scary at all) template:

template <typename T>
void serialWrite(T *buf)
{
    Serial.write(reinterpret_cast<byte*>(buf), sizeof(T));
}

And simply call it like so:

serialWrite(&val); // same 'val' as above