I'm trying to communicate between 2 boards (NodeMCU, arduino mega) over an RS485 hardware setup. This is just for learning to later only the NodeMCU as IoT solution and the mega is simulating any rs485 device. issue: the data communication is not working at all!! These are the converters used.
*Arduino mega is connected to the laptop via USB cable.
*breadboard's power line is receiving 5 volts & ground from a power supply unit.
this is how the system should work: the NodeMCU reads the input voltage from the Potentiometer, maps that (0 to 255) and changes the led brightness (via pwm) and also sends one of five characters (a,b,c,d,e) based on the led brightness calculated.
code excerpt from the NodeMCU Code:
#include <ESP8266WiFi.h>; //to recognize nodemcu board and use wifi later
#include <WiFiClient.h>; //to recognize nodemcu board and use wifi later
int potval = 0; //to store voltage input from potentiometer
int ledrate = 0; //to calculate led pwm rate
void setup() {
pinMode(16, OUTPUT); //labeled D0 on board,the led controlled by Potentiometer
pinMode(12, OUTPUT); //labeled D6 on board, controlling converter's enable
Serial.begin(9600);
}
void loop() {
potval = analogRead(A0); //labeled A0 on board
ledrate = abs(map(potval, 10, 1024, 0, 255));
if (ledrate > 255) {
ledrate = 254;
} //the above 4 lines calculated pwm rate for led light
analogWrite(16, ledrate); //16 is actually labeled D0 on the board
if (ledrate >= 0 && ledrate < 50) { //compare led rate
digitalWrite(12, HIGH); //turn converter into send mode
Serial.println("a"); //print "a"
delayMicroseconds(500); //wait
digitalWrite(12, LOW);//turn converter into receive mode
delayMicroseconds(1500);
}
//lines that print "b" or "c" etc based on ledval NOTincluded here for //simplicity
delay(3000);
}
the Arduino Mega is expected to read the characters delivered to (( Serial3 )) and print them via (( Serial )) to the arduino IDE's Serial monitor on the laptop. code excerpt from the Arduino mega:
#include <string.h> // for strcmp()
// max length of a the data or command
#define MAX_DATA_LEN (15)
#define TERMINATOR_CHAR ('\r')
// the buffer for the received chars
// 1 extra char for the terminating character "\0"
char g_buffer[MAX_DATA_LEN + 1];
// function prototype
void processSerialData(void);
String Serialinput;
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT);
Serial.begin(9600);
Serial.println("Mega reading a,b,c,d,e from NodeMCU. setup done");
Serial3.begin(9600);
pinMode(8, OUTPUT); //control RS 485 comm adapter
}
void loop() {
// Here we read the sensors, calculate the output etc.
delay(100);
// Here we process data from serial line
processSerialData();
}
void processSerialData(void) {
digitalWrite(8, LOW); //activate the rs485 adapter into receive mode
int data;
bool dataReady;
while ( Serial3.available() > 0 ) {
data = Serial3.read();
dataReady = addData((char)data);
if ( dataReady )
//if dataready==true then the func addData has reutrned true meaning it has read all that was received,
//nothing more coming, then the code goes to decide what to do with it
processData();
}
}
bool addData(char nextChar)
{
// This is position in the buffer where we put next char.
// Static var will remember its value across function calls.
static uint8_t currentIndex = 0;
// Ignore some characters - new line, space and tabs
if ((nextChar == '\n') || (nextChar == ' ') || (nextChar == '\t'))
return false;
// If we receive Enter character...
if (nextChar == TERMINATOR_CHAR) {
// ...terminate the string by NULL character "\0" and return true
g_buffer[currentIndex] = '\0';
currentIndex = 0;
return true;
}
// For normal character just store it in the buffer and move
// position to next
g_buffer[currentIndex] = nextChar;
currentIndex++;
// Check for too many chars
if (currentIndex >= MAX_DATA_LEN) {
// The data too long so reset our position and return true
// so that the data received so far can be processed - the caller should
// see if it is valid command or not...
g_buffer[MAX_DATA_LEN] = '\0';
currentIndex = 0;
return true;
}
return false;
}
// process the data - command
// strcmp compares two strings and returns 0 if they are the same.
void processData(void) { //this void compares the strings read and decides what to do
//it's NOT the one that reads what's arriving at the port, it's rather what gets them and
//decides what to do based on them
if (strcmp(g_buffer, "a") == 0 ) { //strcmp == string compare. compares two strngs
//g_buffer is a var where in input was stored, so strcmp sees if it equals "1"
digitalWrite(31, HIGH);
Serial.println("received a");
Serial.println("LED1 is on");
}
else if (strcmp(g_buffer, "b") == 0 ) {
digitalWrite(31, LOW);
Serial.println("LED1 is off");
Serial.println("received b");
}
else if (strcmp(g_buffer, "c") == 0 ) {
Serial.println("received c");
Serial.println("Version 1.0");
}
else if (strcmp(g_buffer, "e") == 0 ) {
Serial.println("received e");
Serial.println("just an e");
}
else if ( strcmp(g_buffer, "d") == 0 ) {
Serial.println("received letter d ... will blink");
for (int cntr = 0; cntr < 11; cntr++) {
digitalWrite(31, HIGH);
delay(200);
digitalWrite(31, LOW);
delay(75);
}
}
else {
Serial.print("Unknown command ");
Serial.println(g_buffer);
}
} //ends the void
here is where a problem happened:when i ran the system , BUT only the sentence from the setup was printed on the serial monitor, but nothing else at all appeared on the serial monitor afterwards.
Troubleshooting:
- i checked all the physical connections, an everything is connected well.
- i connected the NodeMcU to the laptop separately, and opened the serial monitor, it printed characters , such as a or b , etc, as expected. so the NodeMCU is working correctly.
- i connected the Arduino mega separately to the laptop, and changed the code to make it receive from (Serial) instead of (Serial3), and typed a into the serial monitor input in Arduino IDE, and the board received it and worked as expected.
- i bypassed the (TTL to RS485) converters, and directly took the the Tx and Rx from the NodeMCU and connected them to the Arduino Mega's Rx and Tx. the system actually worked and the Arduino mega received the characters from Serial3 and printed them to the serial monitor of the laptop.
- in an attempt to try figuring out what's happening to the board, i re-connected the circuit as in the schematic above using the converters, and modified the code to see what the port is receiving:
#include <string.h> // for strcmp()
// max length of a the data or command
#define MAX_DATA_LEN (15)
#define TERMINATOR_CHAR ('\r')
// the buffer for the received chars
// 1 extra char for the terminating character "\0"
char g_buffer[MAX_DATA_LEN + 1];
// function prototype
void processSerialData(void);
String Serialinput;
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT);
Serial.begin(9600);
Serial.println("Mega reading a,b,c,d,e from NodeMCU. setup done");
Serial3.begin(9600);
pinMode(8, OUTPUT); //control RS 485 comm adapter
}
void loop() {
// Here we read the sensors, calculate the output etc.
delay(100);
// Here we process data from serial line
processSerialData();
}
void processSerialData(void) {
digitalWrite(8, LOW); //activate the rs485 adapter into receive mode
int data;
bool dataReady;
while ( Serial3.available() > 0 ) {
data = Serial3.read();
//following are the new lines added for troubleshooting:
String serial3input;
Serial.println("----------------------------");
Serial.println("serial 3 received"); //this worked so serial 3 is hardware active and receiving sth
serial3input = Serial3.readString();
Serial.print("Serial.readString into variable gives: ");
Serial.println(serial3input);
Serial.print("Serial.readString directly gives: ");
Serial.println(Serial3.readString());
Serial.print("Serial.read directly gives: ");
Serial.println(Serial3.read());
Serial.print("Serial.read into a variable gives: ");
Serial.println(data);
Serial.print("char(serial.read) gives: ");
Serial.println(char(Serial3.read()));
//end of lines added for troubleshooting
dataReady = addData((char)data);
if ( dataReady )
//if dataready==true then the func addData has reutrned true meaning it has read all that was received,
//nothing more coming, then the code goes to decide what to do with it
processData();
}
}
bool addData(char nextChar)
{
// This is position in the buffer where we put next char.
// Static var will remember its value across function calls.
static uint8_t currentIndex = 0;
// Ignore some characters - new line, space and tabs
if ((nextChar == '\n') || (nextChar == ' ') || (nextChar == '\t'))
return false;
// If we receive Enter character...
if (nextChar == TERMINATOR_CHAR) {
// ...terminate the string by NULL character "\0" and return true
g_buffer[currentIndex] = '\0';
currentIndex = 0;
return true;
}
// For normal character just store it in the buffer and move
// position to next
g_buffer[currentIndex] = nextChar;
currentIndex++;
// Check for too many chars
if (currentIndex >= MAX_DATA_LEN) {
// The data too long so reset our position and return true
// so that the data received so far can be processed - the caller should
// see if it is valid command or not...
g_buffer[MAX_DATA_LEN] = '\0';
currentIndex = 0;
return true;
}
return false;
}
// process the data - command
// strcmp compares two strings and returns 0 if they are the same.
void processData(void) { //this void compares the strings read and decides what to do
//it's NOT the one that reads what's arriving at the port, it's rather what gets them and
//decides what to do based on them
if (strcmp(g_buffer, "a") == 0 ) { //strcmp == string compare. compares two strngs
//g_buffer is a var where in input was stored, so strcmp sees if it equals "1"
digitalWrite(31, HIGH);
Serial.println("received a");
Serial.println("LED1 is on");
}
else if (strcmp(g_buffer, "b") == 0 ) {
digitalWrite(31, LOW);
Serial.println("LED1 is off");
Serial.println("received b");
}
else if (strcmp(g_buffer, "c") == 0 ) {
Serial.println("received c");
Serial.println("Version 1.0");
}
else if (strcmp(g_buffer, "e") == 0 ) {
Serial.println("received e");
Serial.println("just an e");
}
else if ( strcmp(g_buffer, "d") == 0 ) {
Serial.println("received letter d ... will blink");
for (int cntr = 0; cntr < 11; cntr++) {
digitalWrite(31, HIGH);
delay(200);
digitalWrite(31, LOW);
delay(75);
}
}
else {
Serial.print("Unknown command ");
Serial.println(g_buffer);
}
} //ends the void
when running the new code, the Arduino IDE serial monitor, receiving from the Arduino Mega, would show something like: >
Mega reading a,b,c,d,e from NodeMCU. setup done
serial 3 received
Serial.readString into variable gives:
Serial.readString directly gives:
Serial.read directly gives: -1
Serial.read into a variable gives: 244
char(serial.read) gives: ⸮
<
I thought I've misunderstood the converters, so I took one to a separate breadboard and manually added logic high/low to its inputs and tried combinations for hours.
here's the results:
Observation: the converter is outputting logic high (5V) ALL THE TIME at DI & RO , regardless of send/receive mode, signal input or none, and this is going to the Arduino mega tx/rx.
- So, why is the communication not working when done over the RS485 converters??!!