Hello,
I am trying to establish a simple UART Communication protocol between my Arduino UNO and NodeMCU ESP8266. Right now I have two LEDS connected to two digital pins of the Uno, and the two boards are connected with jumper wires to set up the TX and RX sides. The goal is to be able to make requests to a web server on the ESP 8266 so that it can send a message to the Uno to toggle one of the LEDs, and then receive a response back indicating success. However, while the LED lighting itself is fairly consistent, there is a lot more inconsistency in the Serial messages.
Uno:
#include <SoftwareSerial.h>
#define LEDR 8
#define LEDB 7
SoftwareSerial s(2, 3);
const byte numChars = 32;
char receivedChars[numChars];
bool newData = false;
void setup()
{
pinMode(LEDR, OUTPUT);
pinMode(LEDB, OUTPUT);
digitalWrite(LEDR, LOW);
digitalWrite(LEDB, LOW);
Serial.begin(9600);
s.begin(9600);
}
void loop()
{
readString();
if (newData) handleLED();
newData = false;
delay(100);
}
void handleLED() {
Serial.println(receivedChars);
char c[10];
strcpy(c, receivedChars);
Serial.println(c);
int len = strlen(c);
int pin = (*c == 'r') ? LEDR : LEDB;
bool LED_state = !digitalRead(pin);
digitalWrite(pin, LED_state);
char c2[20];
memcpy(c2, c + 2, len - 2); // put id first
char res[13];
if (LED_state)
strcpy(res, "LED is on\n");
else
strcpy(res, "LED is off\n");
Serial.println(res);
sprintf(c2, "%s %s", c2, res); // append space and state of LED
s.write(c2);
}
void readString()
{
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (s.available() > 0 && newData == false)
{
rc = s.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;
}
}
}
ESP:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <SoftwareSerial.h>
#define WIFI_SSID ****
#define WIFI_PASSWORD ****
ESP8266WebServer server(80);
SoftwareSerial s(D6, D7);
const byte numChars = 32;
char receivedChars[numChars];
bool newData = false;
void setup()
{
Serial.begin(9600);
s.begin(9600);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
server.on("/", HTTP_GET, handleRoot); // Call the 'handleRoot' function when a client requests URI "/"
server.on("/LEDR", HTTP_POST, []() -> void
{ signalLED("r"); }); // Call the 'handleLED' function when a POST request is made to URI "/LED"
server.on("/LEDB", HTTP_POST, []() -> void
{ signalLED("b"); }); // Call the 'handleLED' function when a POST request is made to URI "/LED"
server.onNotFound(handleNotFound); // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
server.begin(); // start the server
Serial.println("HTTP server started");
}
void loop()
{
server.handleClient(); // Listen for HTTP requests from clients
// handleLED();
delay(100);
}
void handleRoot()
{
// When URI / is requested, send a web page with a button to toggle the LED
server.send(200, "text/plain", "Welcome!");
}
int id = 0; // unique id to mark request id
// run whenever request from app is made
void signalLED(char *c)
{
char c2[10];
strcpy(c2, c);
sprintf(c2, "%s %d\n", c2, id);
Serial.println(c2);
s.write(c2);
while (!s.available()) delay(10);
readString();
if (newData)
{
char *endId;
int id2 = strtol(receivedChars, &endId, 10); // collects first part of string and stores location of end in endId
char res[12];
strcpy(res, endId + 1);
if (id2 == id) server.send(200, "text/plain", res); // Send it back to the browser with an HTTP status 303 (See Other) to redirect
newData = false;
id++;
}
}
// run constantly in loop to check if there is a response
void handleLED()
{
readString();
if (newData)
{
char *endId;
int id2 = strtol(receivedChars, &endId, 10); // collects first part of string and stores location of end in endId
char res[12];
strcpy(res, endId + 1);
server.send(200, "text/plain", res); // Send it back to the browser with an HTTP status 303 (See Other) to redirect
newData = false;
id++;
}
}
void handleNotFound()
{
server.send(404, "text/plain", "404: Not found");
}
void readString()
{
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (s.available() > 0 && newData == false)
{
rc = s.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;
}
}
}
On the Uno side, I get output in the serial monitor like the following:
r 78
r 78
LED is on
r 79
r 79
LED is off
r 80�r 81
r 81
LED is on
The first two chunks print fine, indicating the LED desired, the toggle id, and the status (I am not sure why each r 78 and r 79 line prints twice, but that is not the main issue right now). However, the third is messed up with that question mark symbol and inconsistencies in the id.
Even wilder examples:
Regardless of how fast I was firing requests, messed up output like this kept coming up.
On the ESP side, nothing is getting printed to the monitor even though it should be getting printed once the arduino finishes handling the request and sends the response.
Is there any way I can improve this communication / printing? Should I use an alternative to SoftwareSerial? Is my code written in the most appropriate way for such a task? Am I doing anything concerning performance-wise?
Thanks