A byte of 8 binary bits can represent 28 = 256 numbers: 0 - 255.
The serial connection does indeed send data byte by byte, so if you want to send a number larger than 255, you'll have to send multiple bytes.
For example, an int consists of 2 bytes on most Arduino AVR boards, so you'll have to split it into two separate bytes. To get the lower byte, you just use a bitmask, by performing a binary AND operation. Let's say that 0bhhhh hhhh llll llll is the binary representation of an int (where 0bhhhh hhhh is the high byte (MSB) and 0bllll llll the low byte (LSB), each 'h' and 'l' can either be a 1 or a 0). If you perform a bitwise AND with the number 0b1111 1111, you're left with the lower 8 bits of the original int:
0bhhhh hhhh llll llll
0b0000 0000 1111 1111
---------------------- &
0b0000 0000 llll llll
This particular bitwise AND operation is mathematically equivalent to "int modulo 28".
0bhhhh hhhh llll llll % 256 == 0b0000 0000 llll llll
Note that this operation doesn't have to be explicit: if you just cast an int to an 8-bit type (uint8_t or byte, for example), you try to fit a 16-bit number into an 8-bit variable, so the 8 highest bits are thrown out. (Cfr. overflow.)
int x = 0b1001 1001 1110 1110; // spaces are for readability only
uint8_t LSB = x; // a uint8_t can only store 8 bits, so the MSB is just ignored (implicit type conversion)
Serial.print(x, BIN); // prints "1001 1001 1110 1110"
Serial.print(x & 0b11111111, BIN); // prints "1110 1110"
Serial.print(x % 256, BIN); // prints "1110 1110"
Serial.print(LSB, BIN); // prints "1110 1110"
Serial.print( (uint8_t) x, BIN); // prints "1110 0110" (explicit type-casting)
To get the most significant byte (the highest 8 bits), we can use a bit shift to the right:
0bhhhh hhhh llll llll
---------------------- >> 8
0b0000 0000 hhhh hhhh
As you can see, everything is just shifted 8 bits to the right, so llll llll just falls off, and hhhh hhhh is now the LSB of the result.
We can now use the same trick as above to extract these 8 bits (hhhh hhhh).
This bitshift operator is mathematically equivalent to a floor division by 28.
0bhhhh hhhh llll llll / 256 == 0b0000 0000 hhhh hhhh
int x = 0b1001 1001 1110 1110; // spaces are for readability only
uint8_t MSB = x >> 8;
Serial.print(x, BIN); // prints "1001 1001 1110 1110"
Serial.print(MSB, BIN); // prints "1001 1001"
Serial.print( (uint8_t) x / 256, BIN); // prints "1001 1001"
Now that you know how to extract single bytes from a multi-byte variable, you can send them over Serial:
void sendIntSerial(int x) {
uint8_t LSB = x;
uint8_t MSB = x >> 8;
Serial.write(MSB);
Serial.write(LSB);
}
On the receiver side, just do the inverse operation: shift the MSB 8 bits to the right, and combine it with the LSB, using a bitwise OR:
if(Serial.available() > 1) { // if two bytes have arrived
uint8_t MSB = Serial.read();
uint8_t LSB = Serial.read();
int x = (MSB << 8) | LSB;
// do something with x ...
}
Note that this is not a good approach, because it is prone to framing errors.
If the sender and the receiver get out of sync (because of a missed byte, for example), the receiver will interpret the LSB as a MSB and vice versa.
To get around this, you could send only 7 data bits per byte, and use the 8th bit to indicate whether it's an MSB or an LSB:
void send14bitSerial(int x) {
uint8_t low = x & 0b01111111; // seven least significant bits (bits 0-6)
uint8_t high = (x >> 7) & 0b01111111; // bits 7-13
Serial.write(0b10000000 | high); // set bit 7 to 1, to indicate that this is these are the seven high bits.
Serial.write(low);
}
On the receiver side:
void loop() {
if (Serial.available() > 1) { // if two bytes have arrived
uint8_t first = Serial.read();
if (!(first & 0b10000000)) // if the first byte is not an MSB
return; // out of sync, throw byte away and restart loop
uint8_t second = Serial.read(); // bits 0-6
int x = ((first & 0b1111111) << 7) | second;
// do something with x ...
}
}
Note that you lose two bits of accuracy by doing this (7*2 = 14 instead of 16 bits)
This is not a problem if all numbers you want to send are smaller than 16384.
Alternatively, you could use Serial.print, like Robin2 suggested, the link he posted contains everything you need to know.
Pieter