In this tutorial you will learn how to read data from serial char by char, sentence by sentence or in more complex chunks.
Table of contents:
- Serial, bauds and bytes
- Reading one character
- Reading sequence of characters
- Reading integers enclosed with markers
- Reading complex data
Todo (id=no todo id): What serial is
Todo (id=no todo id): Serial vs parallel
Todo (id=no todo id): Why serial over parallel
Bod (Baud), named after Émile Baudot [bo:do] -- the creator of the Baudot telegraph code and abbreviated as Bd, is a measure that specifies the speed of transmission of changes in the transmission medium. Every change is called a character. The carrier signal is characterized by the number of signal intervals, or pulses, that are transmitted per second. Each pulse is called a baud. For example, a transmission speed of 250 Bd means that the signal can change 250 times in every second. If you ask: How many bits is it equal to?, the answer is: Nobody knows. Really. It is strictly dependent on the medium and coding you use. Technically, the baud rate specifies the number of symbols per second; rather than bits. Each symbol can represent (transport) one or more bits of data.
Although the terms baud and bps (bits per second) are often used interchangably, the two are not the same at all. Bps is a measure of how many bits can be transmitted during one pulse (one baud). So,
1 |
bps = baud * number_of_bits_per_baud |
The Bd should not be confused with the data rate (measured in bits per second) because each change in the signal may carry information about one or more bits (e.g. for 16-QAM it is 4 bits). When each change in signal carries only one bit information, then the number of bauds is equal to the data rate. Probably the misunderstanding of the concept of bod comes from the times when each change in the signal carried information about only 1 bit.
A good example illustrating the difference between the speed expressed in bauds and in bits per second is a man using a single flag. He can change his hand position once every second, so his rate of change of signal (baud) is 1 per second. Assume, that the flag can be held in one of eight positions "arround": up, left-up, left, left-down, down, right-down, right, down-right. This means that each signal carries information about three bits (8 different flag positions can be written on three bits), so the data transmission speed in this case is 3 bits per second.
In case ot typical 8-N-1 (8 data bits, no parity, and 1 stop bit + 1 start bit which is always present) serial communication at 9600 baud about 960 characters per second arrive to Arduino, which means there is a gap of just over 1 millisecond between characters. Is that fast? Is that a lot? Not too much, not too fast. The Arduino can do a lot in 1 millisecond. Even at 115200 baud there is still 86 microseconds between characters. Please keep in mind that during 86 microseconds Arduino executes 1376 instructions.
In Arduino supported baud rates are 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600, and 115200.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
char receivedChar; bool newData; int counter; void setup() { counter = 0; Serial.begin(9600); Serial.println("I'm ready..."); } void loop() { getOneCharacter(); showNewData(); } void getOneCharacter() { if (Serial.available() > 0) { receivedChar = Serial.read(); newData = true; } } void showNewData() { if (newData) { Serial.print(counter); Serial.print(": >"); Serial.print(receivedChar); Serial.println("<"); newData = false; counter++; } } |
1 2 3 4 5 6 7 8 |
RESULT: I'm ready... INPUT: abcENTER RESULT: 0: >a< 1: >b< 2: >c< |
Keep in mind that the Arduino buffer size is 64 bytes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#define MAX_CHARS 32 #define END_MARKER '@' char receivedChar; bool newData; int counter; char buffer[MAX_CHARS]; byte index; void setup() { counter = 0; index = 0; Serial.begin(9600); Serial.println("I'm ready..."); } void loop() { getCharactersWithEndMarker(); showNewData(); } void getCharactersWithEndMarker() { while (Serial.available() > 0 && newData == false) { receivedChar = Serial.read(); if (receivedChar != END_MARKER) { buffer[index] = receivedChar; index++; if (index >= MAX_CHARS) { index--; } } else { buffer[index] = '\0'; newData = true; index = 0; } } } void showNewData() { if (newData) { Serial.print(counter); Serial.print(": >"); Serial.print(buffer); Serial.println("<"); newData = false; counter++; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
RESULT: I'm ready... INPUT: abc@defENTER RESULT: 0: >abc< INPUT: ghi@jklENTER RESULT: 1: >defghi< INPUT: @ENTER RESULT: 2: >jkl< |
But if you try read this abc@def
you will only see the first part abc
. Then if you send ghi@
you will see defghi
because the Arduino has no idea that should ignore def
part.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#define MAX_CHARS 32 #define BEGIN_MARKER '>' #define END_MARKER '<' char receivedChar; bool newData; int counter; char buffer[MAX_CHARS]; byte index; bool collectingCharacters; void setup() { counter = 0; index = 0; collectingCharacters = false; Serial.begin(9600); Serial.println("I'm ready..."); } void loop() { getCharactersWithEnclosingMarkers(); showNewData(); } void getCharactersWithEnclosingMarkers() { while (Serial.available() > 0 && newData == false) { receivedChar = Serial.read(); if (collectingCharacters) { if (receivedChar != END_MARKER) { buffer[index] = receivedChar; index++; if (index >= MAX_CHARS) { index--; } } else { buffer[index] = '\0'; newData = true; index = 0; collectingCharacters = false; } } else if (receivedChar == BEGIN_MARKER) { collectingCharacters = true; } } } void showNewData() { if (newData) { Serial.print(counter); Serial.print(": >"); Serial.print(buffer); Serial.println("<"); newData = false; counter++; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
RESULT: I'm ready... INPUT: abc>def<ghiENTER RESULT: 0: >def< INPUT: abc>defENTER ghi<jklENTER RESULT: 1: >defghi< mno>par<stuENTER 2: >par< |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#define MAX_CHARS 32 #define BEGIN_MARKER '>' #define END_MARKER '<' char receivedChar; bool newData; int counter; char buffer[MAX_CHARS]; byte index; bool collectingCharacters; int sum; int number; void setup() { counter = 0; index = 0; collectingCharacters = false; sum = 0; Serial.begin(9600); Serial.println("I'm ready..."); } void loop() { getCharactersWithEnclosingMarkers(); showNewData(); } void getCharactersWithEnclosingMarkers() { while (Serial.available() > 0 && newData == false) { receivedChar = Serial.read(); if (collectingCharacters) { if (receivedChar != END_MARKER) { buffer[index] = receivedChar; index++; if (index >= MAX_CHARS) { index--; } } else { buffer[index] = '\0'; newData = true; index = 0; collectingCharacters = false; } } else if (receivedChar == BEGIN_MARKER) { collectingCharacters = true; } } } void showNewData() { if (newData) { Serial.print(counter); Serial.print(": >"); Serial.print(buffer); Serial.println("<"); number = atoi(buffer); // ASCII to integer sum += number; Serial.print("number: "); Serial.println(number); Serial.print("sum: "); Serial.println(sum); newData = false; counter++; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
RESULT: I'm ready... INPUT: 1>234<56ENTER RESULT: 0: >234< number: 234 sum: 234 INPUT: 6>78<9ENTER RESULT: 1: >78< number: 78 sum: 312 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#define MAX_CHARS 32 #define BEGIN_MARKER '>' #define END_MARKER '<' #define DELIMITER ";" char receivedChar; bool newData; int counter; char buffer[MAX_CHARS]; byte index; bool collectingCharacters; char bufferCopy[MAX_CHARS]; // BEGIN data model char dataText[MAX_CHARS]; int dataInteger = 0; float dataFloat = 0.0; // END data model void setup() { counter = 0; index = 0; collectingCharacters = false; Serial.begin(9600); Serial.println("I'm ready..."); } void loop() { getCharactersWithEnclosingMarkers(); showNewData(); } void getCharactersWithEnclosingMarkers() { while (Serial.available() > 0 && newData == false) { receivedChar = Serial.read(); if (collectingCharacters) { if (receivedChar != END_MARKER) { buffer[index] = receivedChar; index++; if (index >= MAX_CHARS) { index--; } } else { buffer[index] = '\0'; newData = true; index = 0; collectingCharacters = false; } } else if (receivedChar == BEGIN_MARKER) { collectingCharacters = true; } } } void showNewData() { if (newData) { strcpy(bufferCopy, buffer); parseData(); showParsedData(); newData = false; } } void parseData() { char * tokenIndex; tokenIndex = strtok(bufferCopy, DELIMITER); strcpy(dataText, tokenIndex); tokenIndex = strtok(NULL, DELIMITER); dataInteger = atoi(tokenIndex); tokenIndex = strtok(NULL, DELIMITER); dataFloat = atof(tokenIndex); } void showParsedData() { Serial.print(counter); Serial.print(": >"); Serial.print(buffer); Serial.println("<"); Serial.print("text >"); Serial.print(dataText); Serial.println("<"); Serial.print("integer >"); Serial.print(dataInteger); Serial.println("<"); Serial.print("float >"); Serial.print(dataFloat); Serial.println("<"); } |
1 2 3 4 5 6 7 8 9 |
RESULT: I'm ready... INPUT: xyz>text to test string;-123;-5.76<zyxENTER RESULT: 0: >text to test string;-123;-5.76< text >text to test string< integer >-123< float >-5.76< |
Sending binary data
1 |