Serial data to LCD

Hello, I need help with displaying certain data from serial. Here is the case:

From one arduino I am sending data temperature, humidity, voltage and current over the BT module. Exact format of serial received message is:

Temp.:*T19.00C Vlaga:*V53.00% Ub=*U2.30V Ib=*I8.00mA

Temperature and current may have negative values.

I would like to display it on LCD 2x16. The idea was to extract values after *T, *V, *U and *I. Is there any simple way to take just certain strings regarding index of data and amount of wanted strings? For example, if I want to take value of humidity (vlaga) the index is 25, 3 or 4 characters lenght. It would be fine to transform every of 4 values in variables then would be easy to display them. Instead of indexing maybe better to take few characters after *T for example, since index can change in case of negative values.

Please, the simplest code, since I am total beginner in programming. Thank you very much.

Welcome,

Here is an example that should help.. :slight_smile:

ncs9r0 - Online C++ Compiler & Debugging Tool - Ideone.com or WT9Orm - Online C++ Compiler & Debugging Tool - Ideone.com

Thank you so much for quick answer on my case.
But unfortunately I didn't find library "iostream" for Arduino so there is an error when trying to compile program for arduino. Besides I should have a program already to read serial and then attach yours and add LCD command at the end?
Is there any way to do it with substring or string replace or some other simple way? I couldn't understand the code since I am beginner. Thanks again,

Marsell

Marsell:
Please, the simplest code, since I am total beginner in programming. Thank you very much.

What about the data type of the variable where you have stored the message?

Is it a char array or nullterminated string like:

char message[]="Temp.:*T19.00C  Vlaga:*V53.00%  Ub=*U2.30V  Ib=*I8.00mA";

Or did you collect the message into a "String object" (uppercase 'S' in String), maybe like:

String message="Temp.:*T19.00C  Vlaga:*V53.00%  Ub=*U2.30V  Ib=*I8.00mA";

nullterminated strings and String objects are different.
Both are able to carry a "message" with them, but string handling is different.
So you must know whether you are dealing with nullterminated strings or with String objects, then you can use proper functions to parse the contents of the message.

My examples assumed that you knew how to buffer incoming Serial characters into a char array, and were just a demonstration of the powerful sscanf function, (for which you don't need iostream library, only used for the printf function in my examples, which is not useable in Arduino). I didn't read you were absolute beginner, sorry.

Probably the easiest, beginner-friendly way to parse floats from Serial would be to use Serial.parseFloat.

This topic might be of interest: http://forum.arduino.cc/index.php?topic=396450

Thank you Guix and Jurs for your help. And I am sorry for a delay with my answer. I do this for a hobby when I have time.

Yes, I got through few examples and I figured it out how to change the code that works for me. There is a lot of things that are just too complicated for me so I don't understand everything yet. But I have a feeling that there are probably simpler methods to achieve the same thing - parsing the data.

Jurs, the example I took uses chars, not strings. As I understand with strings you can do even more operations?

So my program looks now like this:

// Example 5 - Receive with start- and end-markers combined with parsing. To je prva uporabna verzija programa za prikaz podatkov s senzorjem DHT11.
#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

const byte numChars = 52;
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;
int integerFromPC1 = 0;
float floatFromPC = 0.0;
float floatFromPC1= 0.0;
boolean newData = false;

//============

void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
lcd.clear();
lcd.print(" Meteo display ");
lcd.setCursor(2,1);
lcd.print("WX by S52ID V1.0");
delay(4000);
lcd.clear();

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] = ' '; // 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, ","); // this continues where the previous call left off
integerFromPC1 = atoi(strtokIndx);// convert this part to an integer

strtokIndx = strtok(NULL, ",");
floatFromPC = atof(strtokIndx);// convert this part to a float

strtokIndx = strtok(NULL, ",");
floatFromPC1 = atof(strtokIndx);// convert this part to a float
}

//============

void showParsedData() {
Serial.print("Message ");
Serial.println(messageFromPC);
//delay(50);
Serial.print("Temperatura zunaj: ");
Serial.print(integerFromPC);Serial.println("C ");
Serial.print("Vlaga zunaj: ");
Serial.print(integerFromPC1);Serial.println("% ");
Serial.print("Napetost baterije: ");
Serial.print(floatFromPC);Serial.println("V ");
Serial.print("Tok baterije: ");
Serial.print(floatFromPC1);Serial.println("mA ");
Serial.println();
delay(70);
lcd.setCursor(0,0);
lcd.print("Tout:");lcd.print(integerFromPC);lcd.print("C ");
lcd.print("Vl: ");lcd.print(integerFromPC1);lcd.print("% ");
lcd.setCursor(0,1);
lcd.print("Ub=");lcd.print(floatFromPC);lcd.print("V");
lcd.print("Ib=");lcd.print(floatFromPC1);lcd.print("mA");

}

One more thing about LCD. I noticed I can't reset the display just pressing the reset button while RX/TX is connected to bluetooth module. If I press the reset button while communication is established, the LCD just got stuck and I have to pull out the wire of RX and press the reset button in order to initialize display correctly.
What can I do about it?

Thank you,

Marsell

What can I do about it?

Get the bluetooth module off the hardware serial pins.

Marsell:
So my program looks now like this:

Please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum Your code is too long for me to study quickly without copying to a text editor.

Then please tell us what your program actually does and what you want it to do that is different.

And, as @PaulS implies, use SoftwareSerial to create a separate serial port for your bluetooth module.

...R

jurs:
What about the data type of the variable where you have stored the message?

Is it a char array or nullterminated string like:

char message[]="Temp.:*T19.00C  Vlaga:*V53.00%  Ub=*U2.30V  Ib=*I8.00mA";

Or did you collect the message into a "String object" (uppercase 'S' in String), maybe like:

String message="Temp.:*T19.00C  Vlaga:*V53.00%  Ub=*U2.30V  Ib=*I8.00mA";

Jurs, thank you for the suggestion. I changed a bit a data stream and simplified the problem in order to send two data strings: one for "Bluetooth electronics" on Android, which requires *T or *V etc. and one with start and end markers for another arduino BT module with LCD. The problem is solved, maybe could be done also with less code.

Robin2, I am sorry for the wrong code copy here on forum.
If I remember well you wrote the template that I used in my case. Thank you very much for that. Maybe would suffice even less code to LCD 4 variables transmitted over serial BT on the second arduino device, but now everything basicly works. I will maybe need some help further to improve the functionality of my simple weather station. When I'll have time to dedicate of course :slight_smile:

Best regards,

Marsell

Marsell:
If I remember well you wrote the template that I used in my case.

I have not looked at the long code in Reply #5 - I am waiting for you to put it in code tags.

...R

Robin2:
I am waiting for you to put it in code tags.

Needless pissing contest.

Here:

// Example 5 - Receive with start- and end-markers combined with parsing.   To je prva uporabna verzija programa za prikaz podatkov s senzorjem DHT11. 
#include <LiquidCrystal.h>


LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

const byte numChars = 52;
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;
int integerFromPC1 = 0;
float floatFromPC = 0.0;
float floatFromPC1= 0.0;
boolean newData = false;

//============

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // initialize the serial communications:
  lcd.clear();
  lcd.print(" Meteo display  ");
  lcd.setCursor(2,1);
  lcd.print("WX by S52ID V1.0");
  delay(4000);
  lcd.clear();

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] = ' '; // 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, ","); // this continues where the previous call left off
integerFromPC1 = atoi(strtokIndx);// convert this part to an integer

strtokIndx = strtok(NULL, ",");
floatFromPC = atof(strtokIndx);// convert this part to a float

strtokIndx = strtok(NULL, ",");
floatFromPC1 = atof(strtokIndx);// convert this part to a float
}

//============

void showParsedData() {
Serial.print("Message ");
Serial.println(messageFromPC);
//delay(50);
Serial.print("Temperatura zunaj: ");
Serial.print(integerFromPC);Serial.println("C ");
Serial.print("Vlaga zunaj: ");
Serial.print(integerFromPC1);Serial.println("% ");
Serial.print("Napetost baterije: ");
Serial.print(floatFromPC);Serial.println("V ");
Serial.print("Tok baterije: ");
Serial.print(floatFromPC1);Serial.println("mA ");
Serial.println();
delay(70);
lcd.setCursor(0,0);
lcd.print("Tout:");lcd.print(integerFromPC);lcd.print("C ");
lcd.print("Vl: ");lcd.print(integerFromPC1);lcd.print("% ");
lcd.setCursor(0,1);
lcd.print("Ub=");lcd.print(floatFromPC);lcd.print("V");
lcd.print("Ib=");lcd.print(floatFromPC1);lcd.print("mA");

}

nyphot:
Needless pissing contest.

Here:

Thank you. You obviously have not yet got tired of doing stuff for people who are perfectly capable of doing it themselves.

@Marsell, now that I can see your code I also need an answer to the other question in Reply #8 "Then please tell us what your program actually does and what you want it to do that is different."

From a quick look at the code I don't see any problem.

...R

Robin2, thank you for checking the code. Yes, as you found out, there is everything working now as I wanted. Thanks again for your template that I used in this case. Later I would like to add few features, like air pressure measuring, the charging current average and similar things. So in case of any problem I'll post it again.