There are 2 ways to transmit data over serial: As byte data or in ASCII codes
Byte data: Everything, that is digitally stored or processed, is a series of 0s and 1s (bits) (electrically HIGH and LOW level), which are grouped into bytes (8 bits). So all data is just numbers at low level. The different datatypes (like numbers, Strings, executable code) are only reached by different interpretation of the byte data. You can take the number value of a byte directly. A byte like 0b00000101
for example is equivalent to the decimal value 5
. So every byte can hold numbers between 0 and 255. (Google the binary system for more information). To hold bigger numbers, more bytes are put together. For example an integer consists of 2 bytes (16 bits) and can hold numbers between 0 and 65535. Note: These are the unsigned types. There are also signed types, that also can hold negative values. To understand this, google binary two's complement. To transmit such a bigger type over serial (which is byte based), you need to seperate the bytes of the type, send them consecutively and put them back together at the receiving side. You can do this with the following code:
unsigned int number = 54321;
Serial.write(number & 0xFF); //getting the lower byte of the number by using bitwise AND
Serial.write(number >> 8); // getting the high byte of the number by shifting the bits of the value 8 bits to the right
There are macros defined for Arduino, that can do this for you:
Serial.write(lowByte(number));
Serial.write(highByte(number));
In long term, you should learn, how the bitwise operators work. They are often needed. To put the data back together, you can look at CrossRoads answer.
Note: Serial.write()
will send the byte data unchanged, while Serial.print()
will convert the data to ASCII before sending. They are not equal.
ASCII Data: One interpretation of byte data is the ASCII standard (which is really old). Every byte value between 0 and 127 get's a corresponding ASCII value, meaning characters of the alphabet, digits, some special characters and some control characters. Numbers, that are transmitted as ASCII data, consist of multiple bytes, one for each digit. Thats, what you tried. Since the receiver has to seperate the different numbers to process them correctly, you have to mark the end of each number. This is commonly done with the newline character \n
(optionally preceeded by the carriage return character \r
, windows style). You add this at the end of every number. Serial
has an extra function for that: Serial.println()
will print the parameter as ASCII and will add a carriage return and newline character. On the receiving side you read the bytes into a buffer, until you see this delimiter sequence. After that, you process the whole buffer. If you want to know, how this Serial communication is done in code, look at the SerialEvent
example, that comes with the Arduino IDE.
What way you use for transmitting data, is up to you and depends on your needs. If you only want to transmit number data, nothing else, you can use byte data. For complex or diverse data types, you can use the ASCII representation.
EDIT: I have described above, that - when using ASCII data - you can use one or more special characters to delimit one message/number. The receiver can then distinguish between the numbers in that row of digits. This is just some kind of protocol, that you impose on the data. You state, that every message is ended with this special character, much like very sentence in the english language is ended with a dot.
An important requirement is, that the special character does not occure inside of a message/number. So cannot use the character '1'
as delimiter, since it will also occur inside of your numbers and you would chop the numbers in the wrong way.
The same principle can be imposed as protocol onto a byte stream. For example: You define, that every message/number will be ended with a special byte sequence, so that the receiver always can say: "This is the whole data of a number and not just a part of it." As above, the special byte sequence must not occur inside of the valid data. You wrote, that your numbers are always in the range of 0 to 62000. This means, that the value 65535 will never occur as valid data, thus you can use it as delimiter. In hex 65535 is written als 0xFFFF
, which means, that you send two bytes with every bit set to 1 (each byte having a decimal value of 255). In your code everytime, that you are receiving something, you can check, if you have got 2 consecutive bytes with the value 255 (or written as 0xFF
). If not, write the data into a buffer. If yes, that means, that you can process the data inside the buffer to a number.
For sending that would look like this:
Serial.write(lowByte(number));
Serial.write(highByte(number));
Serial.write(0xFF);
Serial.write(0xFF);
Note: This protocol will make sure, that sender and receiver cannot get out of sync. But still the first reading after a transmission problem (for example that a byte got send before the receiver was ready) will be garbage. That will happen very very rarely, so for most people it's not a problem. There are more principles, that you can use in your protocol to mitigate those problems, if you want to. For example you can define another special byte sequence as the start of a message/number. Or you can calculate a checksum of the number and only use messages/numbers, that fit to that checksum.
\n
for this. Then you can read the digits one by one, adding them together to the big number. For further help, we need to see your code.