Hey All,
I've got a home automation project where I'm controlling lights, i.e. turning pins HIGH and LOW using various forms of input; IR signals, buttons and Serial. I use the serial connection to communicate to and from a Raspberry Pi running a web server.
I recently wrote some code for a thermostat to control a space heater.
I want to be able to set the desired temperature from a web application and then set that variable usr_temp over serial. I can make this work by using the following code
String a;
while(Serial1.available()) {
a = Serial1.readString();// read the incoming data as string
usr_temp = (a.toFloat());
Serial1.print("The new temperature setting is ");
Serial1.println(usr_temp);
}
I'm also listening to serial with a bunch of if statements to read ASCII characters to toggle LEDs which looks like this
if (Serial1.available() > 0) {
// read the oldest byte in the serial buffer:
incomingByte = Serial1.read();
// if it's a capital H (ASCII 72), turn on the LED:
if (incomingByte == 'H') {
digitalWrite(ledPin, HIGH);
Serial1.println("ON - PIN 44");
}
// if it's an L (ASCII 76) turn off the LED:
if (incomingByte == 'L') {
digitalWrite(ledPin, LOW);
Serial1.println("OFF - PIN 44");
}
}
These things work on their own but confilct when together. For example when I send and ASCII character to toggle the LED pins it resets usr_temp to 0.0.
So my question is how can I send ASCII and integers that don't confuse one another over the same serial connection?
Next 5 characters define comma separted data, CR terminated.
Parsing is now very easy!
SP8266 for use with Arduino IDE and ESP8266 plug-in
void GPSstuff(char c) { // GPSbuffer[] is global
static int i, j; // persistent within function scope
static char q;
static bool flag = false;
static char GPSbuffer[120]; // GPS serial line input buffer
q = c;
if ( q == 0x24 ) // '
[Full code here](https://www.hackster.io/rayburne/tardis-time-esp8266-ap-webserver-gps-6b5d2a)
Ray to GPSbuffer[0]
// Serial << "Found $" << endl;
}
if ( i < 120) GPSbuffer[i++] = q;
// Serial << "Index=" << (i -1) << "Input=" << q << endl;
//if (i = 120) i = 119; // array limit safety
if (q == 0x0d) {
flag = true; // is the character a CR for eol
i = 0;
}
if (flag) { // test for end of line and if the right GPSbuffer
flag = false; // reset for next time
UDP.beginPacketMulticast(broadcastIP, localPort, apIP);
// Serial << "We are in the flag routine..." << GPSbuffer[3] << GPSbuffer[4] << GPSbuffer[5] << endl;
// Serial << "Analyzing " << GPSbuffer[3] << GPSbuffer[4] << GPSbuffer[5] << endl;
if ( (GPSbuffer[3] == 0x52) && (GPSbuffer[4] == 0x4d) && (GPSbuffer[5] == 0x43)) // 'R' && 'M' && 'C'
{
for (j = 0; j < 120 ; j++) {
UDP.write(GPSbuffer[j]);
}
UDP.write("\r\n"); // terminate the line
UDP.endPacket(); // clear UDP buffer
}
}
}
So I read through the Serial Input Basics page which was very helpful but I don't understand it fully. So I took one of the examples from there that reads a char, int and float using <> as start and end markers. This works fine and good but when I try to toggle a pin with commands I'm getting stuck.
I wrote a little function toggleLED(); to try to do this but I can't seem to get it toggle the LED.
// 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(115200);
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();
toggleLED();
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);
}
void toggleLED(){
if(messageFromPC == "A"){
digitalWrite(13, HIGH);
Serial.println("ON");
}
if(messageFromPC == "a"){
digitalWrite(13, LOW);
Serial.println("OFF");
}
}
OK, next I want to set a variable from the float value. Here is my function
void setTemp(){
if ((floatFromPC != 0) == 0){ // test to see if the two strings are equal
float usr_temp = floatFromPC;
Serial.println(usr_temp);
}
}
Seems pretty straight forward but it doesn't seem to fire. Here's the sketch in it's entirety. How can I set the usr_temp value from floatFromPC? Thanks again!
// 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;
float usr_temp = 0.0;
boolean newData = false;
//============
void setup() {
pinMode (13, OUTPUT);
Serial.begin(115200);
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();
toggleLED();
setTemp();
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);
}
void toggleLED(){
if (strcmp(messageFromPC, "A") == 0){ // test to see if the two strings are equal
digitalWrite(13, HIGH);
Serial.println("ON");
}
if (strcmp(messageFromPC, "a") == 0){ // test to see if the two strings are equal
digitalWrite(13, LOW);
Serial.println("OFF");
}
}
void setTemp(){
if ((floatFromPC != 0) == 0){ // test to see if the two strings are equal
float usr_temp = floatFromPC;
Serial.println(usr_temp);
}
}
richiep:
OK, next I want to set a variable from the float value. Here is my function
void setTemp(){
if ((floatFromPC != 0) == 0){ // test to see if the two strings are equal
float usr_temp = floatFromPC;
Serial.println(usr_temp);
}
}
First off, floatFromPC is not a string, it is a float.
Your IF line should just be
if (floatFromPC != 0) {
but comparing float variables to a precise number is risky. There might be a difference of 0.00001 which would cause the test to fail. It would be better to use