Communicating between ESP32 (from Sparkfun type c) and Arduino Mega2560

I'm trying to send data from esp32 to Arduino mega and get it displayed on the serial monitor. Does anyone know what mistake am i doing from the code below:

Arduino Mega2560 code:

//ARDUINO MEGA2560 SIDE CODE
void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  if (Serial1.available() > 0) {
    Serial.println("Message Received: ");
    Serial.println(Serial1.readString());
  }
}

here's the ESP32 side code:

//ESP32 SIDE CODE

void setup() {

Serial.begin(9600);

}

void loop() {

Serial.println("Hello");

delay(500);

}

I'm connecting pin 17/TX of esp32 to pin 19/RX1 of Arduino mega and pin16/RX of esp32 to pin 18/TX1 of arduino mega.
The problem is that only "Message Received: " gets printed and randomly blank square characters gets printed after it. I've checked the baud rate on serial monitor it's set to 9600, so I believe the issue is something else, tried other TX and RX pins of mega but the issue is still the same.

Thanks.

Hello @back57313,

I don't think you have Nano ESP32, so I moved your topic to programming questions.

Thank you.

1 Like

Do you have the ground connected between the Mega and the ESP32?
Also, be careful, the Tx output of the Mega will produce a 5V signal, the ESP32 operates at 3.3V.

yes they share common ground. I'm able to transfer data from Mega to esp32 (but at 1500s delay@9600 baudrate and minimum 1000s delay@115200 baudrate), so I think data transfer and wiring is fine, but my objective is to send data from ESP32 to Mega, so the problem is something with my programming I guess.

To send signals between a 5v controller and 3v3 controller logic level shifters are incorporated.


Always show us a good schematic of your proposed circuit.
Show us good images of your ‘actual’ wiring.
Give links to components.

Use Serial2 instead --

Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);

rxd2 is 16 and txd2 is 17 (use magic numbers or const or defines, whichever way works for you)

to point you to an important point:

your ESP32 might be DESTROYED from directly connecting 5V to it

that is the reason why user @david_2018 wrote

and user @LarryD explains:

If you use serial.readString without adjusting the timeout you need this delay(1000) because the default timeout of function readString() is 1000 milliseconds.

This means using readString() seems to be easy but has it's own difficulties that are hidden under the hood.

I recommend that you learn the things explained in the serial input basics

to be able to do fast and reliable serial receiving

and put a logic level-shifter between ESP32 and Mega 2560

Mega250 5V---------logic-level-shifter---------ESP32 3.3V

Finally you have to modify your code to use that serial interface on Mega 2560 / EPS32 that is connected to particular IO-pins

best regards Stefan

An actual level shifter is not required. A simple 1K series resistor on the Mega TX/ESP RX line will do.

I used this modified code on esp32...now nothing shows in the serial monitor

//ESP32 SIDE CODE
void setup() {
  Serial.begin(9600);
  Serial2.begin(9600, SERIAL_8N1, 16, 17);
}
void loop() {
  Serial2.println("Hello");
  delay(2000);
}

okay so I managed to transfer data from ESP32 to Mega, here's the correct code:

//ESP32 SIDE CODE
#define RXp2 16
#define TXp2 17
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial2.begin(115200, SERIAL_8N1, RXp2, TXp2);
}
void loop() {
  Serial2.println("from esp32 ");
  delay(1500);
}
//ARDUINO MEGA2560 SIDE CODE
void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  
}
void loop() {
  if (Serial1.available()) {
    Serial.println("message received: ");
    Serial.println(Serial1.readString());
  } 
 
}

But as said by @StefanL38

So now I just have to read data in different format to remove the delay. Actually the data which I'll receive from transmitter esp will be joystick inputs i.e x and y axis which I have reduced to 0-255 bits and a switch, which just gives 0 or 1 digital signal, so basically the final data i need in mega is in integer format for further processing.

Any further advice on this will be appreciated.

thanks

If it is a single byte you could use Serial.read() which does exactly that reading a single byte.

If it is more than a single byte I recommend that you use sending your data with a startmarker-byte and an endmarker-byte
For example "<" as startmarker and ">" as endmarker
and then use the serial receive with start/endmarker-function like shown in the serial input basiscs tutorial linked above

So data-telegram examples would look like this

<230,1>
<007,0>
<083,1>
<083,0>

best regards Stefan

It worked then after you defined rx & tx (as I'd mentioned) -- the Solution (yes?).

Thanks for the update. So I followed the link above and tried to implement it the same way but I'm not gertting any output on Mega side. Here's the code for both sides:

//ARDUINO MEGA2560 SIDE CODE
const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  //Serial2.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {
  /*
  if (Serial1.available()) {
    Serial.println("message recived: ");
    int c = Serial1.read();
    Serial.println(c);
  } */
  recvWithStartEndMarkers();
  showNewData();
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial1.available() > 0 && newData == false) {
    rc = Serial1.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 showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
  }
}

ESP32 side code:

//ESP32 SIDE CODE
#define RXp2 16
#define TXp2 17

int xAxis = 120;
int yAxis = 160;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial2.begin(115200, SERIAL_8N1, RXp2, TXp2);
}
void loop() {
  String message = "<" + String(xAxis) + "," + String(yAxis) + ">";
  Serial2.println(message);
  Serial.println(message);

  //Serial2.println("123");
  delay(1500);
}


On ESP32 side, the output is "<120,160>" (without quotes). Which is as expected, so now I think there's something wrong with the Mega side code. Could you please check and see if you find anything? Another possibility could be that I'm sending the data incorrectly.

Main objective: I want to receive joystick <x-axis, y-axis> data in Mega and use it to control an RC car.

Yes I included

and wrote data to serial2 instead of serial.

The stategy to analyse the problem is to print out the single bytes that were received

This is your code from post # 16 with additional debug-output

//ARDUINO MEGA2560 SIDE CODE
const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  //Serial2.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {
  /*
  if (Serial1.available()) {
    Serial.println("message recived: ");
    int c = Serial1.read();
    Serial.println(c);
  } */
  recvWithStartEndMarkers();
  showNewData();
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial1.available() > 0 && newData == false) {
    rc = Serial1.read();
    Serial.print("rc=#");
    Serial.print(rc);
    Serial.println("#");
    Serial.println();
    
    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 showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
  }
}
    Serial.print("rc=#");
    Serial.print(rc);
    Serial.println("#");
    Serial.println();

to make visible what you really receive.

The hash-characters "#" are there for making visible if there are some carriage return linefeeds inbetween

best regards Stefan

my serial monitor is set to No line ending is that fine for all these testing part?

Hey thanks it's working fine now

Now I have to break the two values apart and convert it to integer to control the motors

if you fill 1digit-numbers with two leading zeros 001,002,003..009
and
2digit-numbers with one zero 010..011.012....099
The position of the comma is always the same.
example-data
123,987
So receivedChars[0]..receivedChars[2] contains "123"
and
So receivedChars[4]..receivedChars[6] contains "987"

you store these characters in a new variable and then use function atoi()
to convert them to integers

myXChars[0] = receivedChars[0];
myXChars[1] = receivedChars[1];
myXChars[2] = receivedChars[2];
myXChars[3] = 0; // VERY IMPORTANT zero-terminating of the c_string

myYChars[0] = receivedChars[4];
myYChars[1] = receivedChars[5];
myYChars[2] = receivedChars[6];
myYChars[3] = 0; // VERY IMPORTANT zero-terminating of the c_string

myXInt = atoi(myXChars);
myYint = atoi(myYChars);

on three bytes a for-loop has the same amount of typing

for (byte i = 0; i < 3; i++ 
  myYChars[i] = receivedChars[i + 4];

  myYChars[3] = 0; 

another way would be to use the function strcpy()

best regards Stefan

got it working. I used pointers instead, but it does the same job. I have one more question. I have already written and tested the pid control part of the code( speed control of dc motor), and it is working fine. So I used to declare a fixed setpoint (rpm) in the setup function and used to give starting pwm of 50% but now I want to set the setpoint = xValue of joystick which is received. I tried to do this inside loop function but it doesnt work...motor starts at 127pwm(50%) and quickly comes to a stop then I directly substitued "xValue" inplace of "setpoint" directly inside the PIDcalculation function, but it didn't work.

This is my current problem so should I post this querry as a new topic or is it okay to continue in this thread? If it's okay then does anyone have any idea of what I should do, I'm pretty sure it's a programming mistake.

could be both. Continuiing as your thread-title is very unspecific.
or
starting a new thread with a really precise and specific title.
In the new thread post a link to this thread.

In any case post your complete sketch instead of some words.

best regards Stefan

1 Like