Arduino Mega - ESP32 Serial Communication

Hello. I have an Arduino Mega and an ESP32 and I want to send data from the Mega to the ESP32 through the serial communication.

I have uploaded the following code to the Mega:

void setup() {
  Serial2.begin(9600);
}
void loop() {
  Serial2.println("Hello");
  delay(1500);
}

and this one to the ESP32:

#define RXp2 16
#define TXp2 17
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, RXp2, TXp2);
}
void loop() {
 byte n = Serial2.available();
  if (n != 0)
  {
    Serial.print("Message Received: ");
    Serial.println(Serial2.readString());
  }
}

and everything works fine, but when I insert the ESP32 code in my bigger project I get this in the serial monitor of the ESP32:

Message Received: Hello
□

and the nothing.

This is the entire code of the ESP32:

#define REMOTEXY_MODE__ESP32CORE_WIFI_CLOUD
#include <WiFi.h>
#include <HTTPClient.h>
#include <RemoteXY.h>

// RemoteXY connection settings 
#define REMOTEXY_WIFI_SSID "xxx"
#define REMOTEXY_WIFI_PASSWORD "xxx"
#define REMOTEXY_CLOUD_SERVER "cloud.remotexy.com"
#define REMOTEXY_CLOUD_PORT 6376
#define REMOTEXY_CLOUD_TOKEN "xxx"
#define RXp2 16
#define TXp2 17

//Reflectoare
int LightS = 34; // Fotorezistor
int LightR = 5; // Releu reflectoare
int MotionSensor1 = 16;
int MotionSensor2 = 17;
int MotionSensor3 = 18;
int MotionSensor4 = 19;
int LightStat;
int LightV;
int LightM;
unsigned long onDuration = 90000;// OFF time for LED
unsigned long offDuration = 10000;// ON time for LED
unsigned long rememberTime=0;// this is used by the code
int LEDState = HIGH;
unsigned long IntervalReflectoare = 1000;
unsigned long TimpReflectoare = 0;
unsigned long IntervalReflectoareT = 1000;
unsigned long TimpReflectoareT = 0;
int ContorReflectorT = 0;


//Vant
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 1000;    // the debounce time; increase if the output flickers
int pinInterrupt = 35; //senzor vant
int Count = 0;
int Vant;
int VantMax = 0;

//Alarma
int MotionSensor = 21; // Senzor miscare
int MotionSignal = 22; // Semnal sirena

//Ploaie
#define CALC_INTERVAL 1000
#define DEBOUNCE_TIME 15*1000
const int RainSensor = 23;
float TotalVolume = 0;
long NrTips = 0;
long last_micros_rg;
long nextCalc;
long Cronometru;
int PloaieReset;

//Google Sheets
unsigned long IntervalGoogleSheetsVP = 1000;
unsigned long TimpGoogleSheetsVP = 0;
String urlVP;

unsigned long IntervalGoogleSheetsTU = 60000;
unsigned long TimpGoogleSheetsTU = 0;
String urlTU;

// RemoteXY configurate  
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =   // 363 bytes
  { 255,4,0,27,0,100,1,16,30,5,130,1,255,2,65,96,0,31,129,0,
  4,251,53,6,0,13,65,117,116,111,109,97,116,105,122,97,114,101,32,99,
  117,114,116,101,0,131,1,1,99,21,7,1,13,31,71,101,110,101,114,97,
  108,0,130,0,0,2,16,18,1,31,67,6,1,7,7,4,1,135,31,4,
  129,0,8,7,4,2,1,135,75,77,47,72,0,129,0,1,3,13,3,1,
  8,86,195,162,110,116,32,77,97,120,0,129,0,1,11,13,3,1,8,86,
  195,162,110,116,32,76,105,118,101,0,67,6,1,15,7,4,1,135,31,4,
  129,0,8,15,4,2,1,135,75,77,47,72,0,130,0,39,2,23,11,1,
  31,70,16,40,6,6,6,1,16,135,0,10,50,47,6,14,6,1,0,31,
  31,79,78,0,0,79,70,70,0,129,0,42,3,16,3,1,8,82,101,102,
  108,101,99,116,111,97,114,101,0,130,0,16,2,23,18,1,31,129,0,22,
  3,10,3,1,8,65,108,97,114,109,196,131,0,10,50,25,13,12,6,1,
  1,31,31,79,78,0,1,79,70,70,0,70,16,18,13,6,6,1,16,37,
  0,130,0,0,20,29,9,1,31,1,2,17,24,11,4,0,31,164,82,101,
  115,101,116,0,129,0,11,21,8,3,1,8,80,108,111,97,105,101,0,67,
  2,0,25,9,4,0,164,31,6,129,0,9,24,5,3,0,164,76,105,116,
  114,105,0,10,50,18,6,19,6,1,1,31,31,65,114,109,97,116,196,131,
  0,1,68,101,122,97,114,109,97,116,196,131,0,67,6,40,22,20,5,1,
  135,26,11 };
  
// this structure defines all the variables and events of your control interface 
struct {

    // input variables
  uint8_t Reflectoare_B; // =1 if state is ON, else =0 
  uint8_t Alarma; // =1 if state is ON, else =0 
  uint8_t PloaieReset; // =1 if button pressed, else =0 
  uint8_t Alarma_A; // =1 if state is ON, else =0 

    // output variables
  char Vant_Max[4];  // string UTF8 end zero 
  char Vant_Live[4];  // string UTF8 end zero 
  uint8_t Reflectoare_L; // led state 0 .. 1 
  uint8_t Alarma_L; // led state 0 .. 1 
  char Litri[6];  // string UTF8 end zero 
  char text_1[11];  // string UTF8 end zero 

    // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 

} RemoteXY;
#pragma pack(pop)
/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, RXp2, TXp2);

  delay(1000);
  RemoteXY_Init ();
  delay(1000);

  pinMode(5,OUTPUT);
  pinMode(16,INPUT);
  pinMode(17,INPUT);
  pinMode(18,INPUT);
  pinMode(19,INPUT);
  pinMode(21,INPUT);
  pinMode(22,OUTPUT);
  pinMode(23,INPUT);
  pinMode(34,INPUT);
  pinMode(35,INPUT);
  
  digitalWrite(LightR,HIGH);

  //interrupt vant
  pinMode( pinInterrupt, INPUT_PULLUP);// set the interrupt pin
  attachInterrupt( digitalPinToInterrupt(pinInterrupt), CounterVant, FALLING);

  //interrupt ploaie
  attachInterrupt(digitalPinToInterrupt(RainSensor), Ploaie, RISING);

  //Google Sheets

}

void loop() {
  byte n = Serial2.available();
  if (n != 0)
  {
    Serial.print("Message Received: ");
    Serial.println(Serial2.readString());
  }

  RemoteXY_Handler ();

//START Vant  
  if ((millis() - lastDebounceTime) > debounceDelay)
  {
    lastDebounceTime = millis();
    Vant=((Count * 8.75)/100)*3.6;
    Count = 0;
    itoa (Vant, RemoteXY.Vant_Live, 10);
    if (Vant > VantMax) {
        VantMax = Vant;
        itoa (VantMax, RemoteXY.Vant_Max, 10);
    }    
  }
//STOP Vant

//START Reflectoare
if( (millis() - TimpReflectoare) >= IntervalReflectoare){
TimpReflectoare = millis();

  LightV = analogRead(LightS);

  if (RemoteXY.Reflectoare_B == 1) {
    digitalWrite(LightR, LOW);
  } else {
    if (LightV > 900) {
    RemoteXY.Reflectoare_L = 1;
        if( LEDState == HIGH ){
          if( (millis()- rememberTime) >= onDuration){   
            LEDState = LOW;// change the state of LED
            rememberTime=millis();// remember Current millis() time
          }
       } else {   
         if( (millis()- rememberTime) >= offDuration){     
         LEDState = HIGH;// change the state of LED
         rememberTime=millis();// remember Current millis() time
         }
       }

   digitalWrite(LightR, LEDState);// turn the LED ON or OFF

    /*
    if (digitalRead(MotionSensor1) == HIGH){
      digitalWrite(LightR,LOW);
      RemoteXY.Reflectoare_L = 1;
      } else {
          if (digitalRead(MotionSensor2) == HIGH){
            digitalWrite(LightR,LOW);
            RemoteXY.Reflectoare_L = 1;
          } else {
              if (digitalRead(MotionSensor3) == HIGH){
                digitalWrite(LightR,LOW);
                RemoteXY.Reflectoare_L = 1;
              } else {
                  if (digitalRead(MotionSensor4) == HIGH){
                    digitalWrite(LightR,LOW);
                    RemoteXY.Reflectoare_L = 1;
                  } else {
                      digitalWrite(LightR,HIGH);
                      RemoteXY.Reflectoare_L = 0;
                        }
                     }
                  }
              }
    */
    
    } else {
      digitalWrite(LightR,HIGH);
      RemoteXY.Reflectoare_L = 0;
    }
  }
}

if (LightV > 900) {
  if( (millis() - TimpReflectoareT) >= IntervalReflectoareT){
    TimpReflectoareT = millis();
    if (digitalRead(MotionSensor1) == HIGH){
      ContorReflectorT = ContorReflectorT + 1;
      itoa (ContorReflectorT, RemoteXY.text_1, 10);
      Serial.println(ContorReflectorT);
    }
  }
}  


//STOP Reflectoare

//START Alarma
  if (RemoteXY.Alarma_A == 1) {
    if (RemoteXY.Alarma == 1) {
      digitalWrite(MotionSignal,HIGH);
      RemoteXY.Alarma_L = 1;
      } else {
        if (digitalRead(MotionSensor) == 1) {
        digitalWrite(MotionSignal,HIGH);
        RemoteXY.Alarma_L = 1; 
        } else {
        digitalWrite(MotionSignal,LOW);
        RemoteXY.Alarma_L = 0;
        } 
      }
  } else {
    RemoteXY.Alarma = 0;
    digitalWrite(MotionSignal,LOW);
    RemoteXY.Alarma_L = 0;
  }
//STOP Alarma

//START Ploaie
  Cronometru = millis();
  if(Cronometru > nextCalc) {
    nextCalc = Cronometru + CALC_INTERVAL;
    itoa (TotalVolume, RemoteXY.Litri, 10);
  }
  if (RemoteXY.PloaieReset == 1){
    NrTips = 0;
    TotalVolume = 0;
  }
//STOP Ploaie

//START Google Sheets
  //Vant si Ploaie
  if( (millis() - TimpGoogleSheetsVP) >= IntervalGoogleSheetsVP){
  TimpGoogleSheetsVP = millis();

  urlVP += "https://script.google.com/macros/s/";
  urlVP += "xxx";
  urlVP += "/exec?";
  urlVP += "Vant=";
  urlVP += String(Vant);
  urlVP += "&Ploaie=";
  urlVP += String(TotalVolume);

  HTTPClient httpPV;
  httpPV.begin(urlVP);
  int httpResponseCode = httpPV.GET();
  }
  urlVP = "";

//Temperaturi si Umiditati


  if( (millis() - TimpGoogleSheetsTU) >= IntervalGoogleSheetsTU){
  TimpGoogleSheetsTU = millis();

  urlTU += "https://script.google.com/macros/s/";
  urlTU += "xxx";
  urlTU += "/exec?";
  urlTU += "Magazie_IN_T=12.2&Magazie_IN_U=50&Magazie_OUT_T=13.3&Magazie_OUT_U=52&Beci_IN_T=14.4&Beci_IN_U=54&Beci_OUT_T=15.5&Beci_OUT_U=56&Solar_T=16.6&Solar_U=58";

  HTTPClient httpTU;
  httpTU.begin(urlTU);
  int httpResponseCode = httpTU.GET();
  }
  urlTU = "";


//STOP Google Sheets

} // END LOOP



void CounterVant()
{
  if ( digitalRead(pinInterrupt) == LOW )
    Count++;
}

void Ploaie() {
  if((long)(micros() - last_micros_rg) >= DEBOUNCE_TIME) { 
    NrTips += 1;
    TotalVolume = NrTips*(0.00165/0.0055);
    last_micros_rg = micros();
  }  
}

Can anyone help me to figure out what is going on?

think you could do with some more Serial.println() statements to display key variables and program flow

anu particular reason to use a Mega and a ESP32 ? could you loose the Mega and just use the ESP32?

the Mega uses 5V logic the ESP32 3.3V - have you a potential divider on the Mega Tx to ESP32 Rx line

having to program two microcontrollers and the resultant communications makes the overall task complexity an order of magnitude greater

I'm using the Mega because I need more I/O pins. I don't think it is a voltage divider problem because it works with the basic sketch.

think you could do with some more Serial.println() statements to display key variables and program flow

What do you mean?

Yes but to ensure that the ESP32 won't break, you should add a voltage divider on the ESP32's RX-line
Mega-TX -> 1K -> ESP32-RX -> 1K -> 1K -> GND

also, once you define

  pinMode(16,INPUT);
  pinMode(17,INPUT);

at the very least the TX line won't work, but as far as i know the ESP32 has separate pin-modes (sort of i think it's done through MUX somehow) for Serial pins. Comment out these 2 lines and Serial2 should keep working.

how much IO have you got? have a look at ESP32 pin usage

Thanks Deva_Rishi for the advice. I was using those pins has been put from other sensors.

Now I have another problem once in a while I get a double word:

Message Received: Hello
Message Received: Hello
Hello
Message Received: Hello
Message Received: Hello
Message Received: Hello
Hello
Message Received: Hello

I've tried increasing the delay but the problem still persists.

That's because your code was busy doing other things and was not able to read the serial buffer before another "Hello" was sent. Is that a problem?

It is because the data that I want to send it is part of an URL used to sent data to a Google Sheets.

So what is the problem?
The ESP32 is receiving everything the Mega is sending.

Yes, but the problem that if I get two strings in one transfer that messes up the formatting of the URL

If you add start and end characters to the message that you send then you can check that you receive the message in the correct format

See Serial input basics - updated

Your present Mega code uses println, so there will be a \r\n after each URL.
You can use readStringUntil('\n') or just look for \n in the string you receive

I have played with the delays and I managed to make it to work. I have put on the Mega a 2s delay between sends and on the ESP32 a 1s delay between sends of the URL.

Now I have a different problem. It seems that the data is not reach to the Google Sheets. If I copy the URL from the serial monitor and paste it in a browser this way it works.

Here is the code that I'm running now:

  Pachet = String(Serial2.readString());
  
  if( (millis() - TimpGoogleSheetsTU) >= IntervalGoogleSheetsTU){
  TimpGoogleSheetsTU = millis();

  urlTU += "https://script.google.com/macros/s/";
  urlTU += "xxx";
  urlTU += "/exec?";
  //urlTU += "Magazie_IN_T=NAN";
  urlTU += Pachet;
  Serial.println(urlTU);
  HTTPClient httpTU;
  httpTU.begin(urlTU);
  int httpResponseCode2 = httpTU.GET();
  urlTU = "";
  }

But if I comment the "urlTU += Pachet;" part and uncomment the "urlTU += "Magazie_IN_T=NAN";" then it sends the "NAN" to the google sheets.

Also I have noticed that when I add the "urlTU += Pachet;" in the serial monitor I get the string plus a blank line:

17:02:01.055 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=23.80
17:02:01.055 -> 
17:02:03.072 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=23.80
17:02:03.072 -> 
17:02:05.091 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=23.80
17:02:05.091 -> 
17:02:07.114 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=23.80
17:02:07.114 -> 

blank line that is not present if I add the "urlTU += "Magazie_IN_T=NAN";"

17:06:20.839 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=NAN
17:06:24.856 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=NAN
17:06:28.872 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=NAN
17:06:32.913 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=NAN
17:06:36.946 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=NAN
17:06:40.979 -> https://script.google.com/macros/s/xxx/exec?Magazie_IN_T=NAN

if you run out of pins on an ESP32, add a I2C port expander.
It is far easier to program the ESP32 and add more ports via port expanders.

Rule of thumb:
One Microcontroller = One Problem (the program you write)
Two Microcontroller = Three Problems (a Program on each Microcontroller and the communication between these Microcontrollers)

Ca you recomend a port expander?

pcf8574
pcf8575
mcp23017
mcp23008
if you want to read buttons: SX1509
If you want to drive LEDs: SX1509, HT16K33
if you need PWM outputs or servos: PCA9685
If you need analog inputs: ADS1115

and these are just ICs where you find maker friendly boards and lot of libraries.
The list could continue if you want to to use SPI.

What do you need and how many of them?

For now I have several DHT22 temperature sensors and several relay.

several = 2, 3, 10, 20, 42, 100?

if you need advises, please give EXACT figures (how many DHTs, how many relays, what else needs to be connected).

And which ESP32 are you using - post a link or a datasheet.

Have you checked already all proposed ICs in the internet of your own? Some have 4 ports, some have 8 ports, some have 16 ports. I would not recommend to use two 8 port ICs if you need 16 outputs for relays. I hope you understand why you need to give precise numbers.

For now I have 5 DHT22 and probably 10 relays but I will like to have room for more expansion.

may be worth looking at a 16 Channel Relay Module - as well as 16 channel TTL control there are modules with TTL serial, I2C, ethernet and WiFi (ESP8266) interfaces