Continued from previous Post
Receiving numbers rather than text
So far the examples have assumed you want to receive text. But perhaps you want to send a number or maybe a mix of text and numbers.
Example 4 - Receiving a single number from the Serial Monitor
The simplest case is where you want to type a number into the Serial Monitor (I am assuming you have line-ending set to newline). Let's assume you want to send the number 234. This is a variation on Example 2 and it will work with any integer value. Note that if you don't enter a valid number it will show as 0 (zero).
// Example 4 - Receive a number as text and convert it to an int
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
int dataNumber = 0; // new for this version
void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithEndMarker();
showNewNumber();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
if (Serial.available() > 0) {
rc = Serial.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
}
}
}
void showNewNumber() {
if (newData == true) {
dataNumber = 0; // new for this version
dataNumber = atoi(receivedChars); // new for this version
Serial.print("This just in ... ");
Serial.println(receivedChars);
Serial.print("Data as Number ... "); // new for this version
Serial.println(dataNumber); // new for this version
newData = false;
}
}
Example 5 - Receiving and parsing several pieces of data
It is also straightforward to receive several pieces of data in a single message and parse the data to assign them to individual variables. This example assumes you send something like <HelloWorld, 12, 24.7>
. This is an extension of Example 3.
A function called parseData() has been added and the function showParsedData() takes the place of showNewData() in the earlier example.
// Example 5 - Receive with start- and end-markers combined with parsing
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;
boolean newData = false;
//============
void setup() {
Serial.begin(9600);
Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
Serial.println("Enter data in this style <HelloWorld, 12, 24.7> ");
Serial.println();
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars,","); // get the first part - the string
strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
integerFromPC = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
floatFromPC = atof(strtokIndx); // convert this part to a float
}
//============
void showParsedData() {
Serial.print("Message ");
Serial.println(messageFromPC);
Serial.print("Integer ");
Serial.println(integerFromPC);
Serial.print("Float ");
Serial.println(floatFromPC);
}
Binary data
So far we have been receiving character data - for example the number 121 is represented by the characters '1', '2' and '1'. It is also possible to send that value as binary data in a single byte - it happens to be the Ascii value for the character 'y'. Note that 121 in decimal is the same as 0x79 in HEX.
Note that if you are sending binary data it is quite likely that you will need to send as data the same values that are used for the start- and end-markers. That goes beyond the scope of this Tutorial and one way of doing it is illustrated in the demo here.
The examples that follow assume that the binary data will NEVER include the byte values used for the start- and end-markers. For simplicity I will continue to use <
and >
as the markers. The byte values for those characters are 0x3C and 0x3E. This will allow you to test the program from the Serial Monitor by sending, for example, <24y>
which will be interpreted by the receiving program as the binary values 0x32, 0x34 and 0x79. These are the Ascii codes for 2, 4 and y.
Of course it would be more usual for binary data to be sent by another computer program - on another Arduino or on a PC.
Example 6 - Program to receive binary data
This is adapted from Example 3
// Example 6 - Receiving binary data
const byte numBytes = 32;
byte receivedBytes[numBytes];
byte numReceived = 0;
boolean newData = false;
void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready>");
}
void loop() {
recvBytesWithStartEndMarkers();
showNewData();
}
void recvBytesWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
byte startMarker = 0x3C;
byte endMarker = 0x3E;
byte rb;
while (Serial.available() > 0 && newData == false) {
rb = Serial.read();
if (recvInProgress == true) {
if (rb != endMarker) {
receivedBytes[ndx] = rb;
ndx++;
if (ndx >= numBytes) {
ndx = numBytes - 1;
}
}
else {
receivedBytes[ndx] = '\0'; // terminate the string
recvInProgress = false;
numReceived = ndx; // save the number for use when printing
ndx = 0;
newData = true;
}
}
else if (rb == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in (HEX values)... ");
for (byte n = 0; n < numReceived; n++) {
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
}
Serial.println();
newData = false;
}
}
END
As usual, comments and suggested improvements are welcome but please do not ask questions about your own project in this Thread.
...R