Can't get UART connection between two ESP32s (solved)

I'm trying to send a simple test string from one ESP32 to the other via UART, and not having any success.

I have one ESP32 set to receive messages:

#include <HardwareSerial.h>

HardwareSerial MySerial(1);

void setup() {
  Serial.begin(115200); 
  Serial.println("Starting the receiver (black board)....");  
  MySerial.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {
    while (MySerial.available() > 0) {
        uint8_t byteFromSerial = MySerial.read();
        Serial.println("got something!");
    }
}

And one set to send messages:

#include <HardwareSerial.h>

HardwareSerial MySerial(1);

void setup() {
  Serial.begin(115200); 
  Serial.println("Starting the sender (white board)....");  
  MySerial.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {

    // Send a random number
    MySerial.write(random(0, 255));
    delay(1000);
}

I have pin 16 of the Receiver connected to pin 17 of the Sender, and pin 17 of the Receiver connected to pin 16 of the Sender. And they're sharing ground and 3.3v pins.

Does anyone happen to have any ideas?

Edit: and I know there are better ways to communicate between two ESP32s, but my eventual goal is to send messages to an ESP32 (so it can upload the data) from an Arduino. Basically trying to slave an ESP32 for wifi.

What do you mean? only join the GND pins

Thanks for that, I thought I could just power the 2nd ESP32 off the first. But alas, still not working even with the 3.3v+ pins no longer connected.

Why use a library in order to do serial comms with an ESP32 ?

I tried without as well. Here's the version without a library.

Receiver board:

#define RXD2 16
#define TXD2 17

void setup() {
  Serial.begin(115200);
  Serial.println("Started the receiver (black board");
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
}

void loop() { 
  while (Serial2.available()) {
    Serial.println("We have data!");
    Serial.print(char(Serial2.read()));
  }
}

Sender board:


#define RXD2 16
#define TXD2 17

void setup() {
  Serial.begin(115200);
  Serial.println("Started the sender (white board");
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
}

void loop() { 
  Serial2.write(random(0, 255));
  delay(200);
}

Still not a peep on Serial Monitor.

Here's a pic of the setup, in case I'm still doing something dumb.

How are both ESP32 powered? Are you trying to supply the second ESP32 through the 3.3V pin of the first one? This will not work. The ESP32 produces current-spikes 300 mA high.

me personal I always add a piece of code that makes the onboard-led blink as a "heartbeat" to visually indicate code is running.

I powered both ESP32s with their own USB-cable. And in this configration this code works
You can use the code on both ESP32 they send back and forth a byte.

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);


#include <HardwareSerial.h>

HardwareSerial MySerial(1);


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod ) {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  MySerial.begin(9600, SERIAL_8N1, 16, 17);
}

uint8_t myByte = 48;

void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);
  while (MySerial.available() > 0) {
    uint8_t byteFromSerial = MySerial.read();
    dbg("received", byteFromSerial);
  }


  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    MySerial.write(myByte);
    myByte++;
    if (myByte > 59) {
      myByte = 48;
    }
  }
}

best regards Stefan

If you want to use the second hardware-serial port
this requires hardwareserial.h

best regards Stefan

Very nice, lots of interesting things happening in your script, lots for me to learn there.

But alas, I installed it on both boards, still nothing in the Serial Monitor.

(And I'm powering both boards from the same laptop, but to be safe one board is powered with a USB micro that doesn't have data lines. Only connecting ground and the tx/rx pins as in the pic above).

Fixed! Was a bad ESP32, or maybe a bad pin. That board (the black one in the pic, a Rover) works great for everything else, odd.

Argh, I was wrong, it's not fixed. It still prints data to the console even with the 2nd ESP32 turned off. I should probably take a break, ha.

Edit: it's some grounding issue, the output changes with where I touch the ESP32.

I observe this too. If there is no connection the numbers are randomly.
If the Tx/Rx are connected the numbers count up 48,49 etc.
Rx/Tx connected

09:09:57.519 -> "received" byteFromSerial=48
09:09:58.502 -> "received" byteFromSerial=49
09:09:59.521 -> "received" byteFromSerial=50
09:10:00.506 -> "received" byteFromSerial=51
09:10:01.499 -> "received" byteFromSerial=52
09:10:02.513 -> "received" byteFromSerial=53
09:10:03.499 -> "received" byteFromSerial=54
09:10:04.509 -> "received" byteFromSerial=55
09:10:05.525 -> "received" byteFromSerial=56
09:10:06.508 -> "received" byteFromSerial=57
09:10:07.527 -> "received" byteFromSerial=58
09:10:08.508 -> "received" byteFromSerial=59
09:10:09.529 -> "received" byteFromSerial=48
09:10:10.509 -> "received" byteFromSerial=49

DIS-connected

09:10:39.990 -> "received" byteFromSerial=224
09:10:39.990 -> "received" byteFromSerial=0
09:10:39.990 -> "received" byteFromSerial=0
09:10:40.024 -> "received" byteFromSerial=0
09:10:40.024 -> "received" byteFromSerial=0

For connecting a 5V-Arduino to a 3.3V ESP32 you should use voltage-level-converters.
For Arduino sends to ESP32 a simple voltage-divider would be sufficient.
For sending from the ESP32 to an 5V arduino voltage-level-shifting is nescessary.
best regards Stefan
For sending data from an arduino to an ESP32 over serial I recommend reading

best regards Stefan

But @wrybread could have simply define the Serial port like this without using a library

void setup()
{
  Serial2.begin(115200, SERIAL_8N1, 14, 15);
}

void loop()
{
  Serial2.println("bong");
  delay(1000);
}

Ok, all working now, phew. That was confusing.

Here's what I learned:

  • @UkHeliBob is right, it works without an external library. See my updated scripts below.

  • don't power both ESP32's from the same computer. The tests didn't work until I plugged the sender into a wall USB charger.

  • keep a lot of ESP32s on hand, ideally from different vendors, because for some reason that Rover ESP32 still doesn't work with these tests, but every one of my cheaper Wrooms do. With the bad ESP32 and the issue of powering both chips from the same computer, this was a tough riddle.

Updated stripped down code.

Sender:

#define RXD2 16
#define TXD2 17

void setup() {
  Serial.begin(115200);
  Serial.println("Started the sender (white board");
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
}

void loop() { 
  Serial2.write("my head hurts\n");
  delay(200);
}

Receiver:

#define RXD2 16
#define TXD2 17

String incoming;

void setup() {
  Serial.begin(115200);
  Serial.println("Started the receiver (black board");
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
}

void loop() { 
  while (Serial2.available() >= 1) {
    //Serial.print(char(Serial2.read()));
    incoming = Serial2.readStringUntil('\n');
    Serial.println(incoming);
  }
}

For wiring, connect pin 16 of the Sender ESP32 to pin 17 of the Receiver ESP32, connect pin 17 of the Sender to pin 16 of the Receiver, and connect a ground pin of Sender to a ground pin of Receiver. And if it doesn't work at first, try powering the Sender ESP32 from a different source, not just another port on the same computer.

And thanks for the tip @stefanL38 about a voltage divider, I'll give that a try. I only need to send data from the Arduino to the ESP32, so that should work.

Whoo hoo! This works as a Sender when running on an Arduino Uno, both with and without a voltage divider... I'm guessing I'd be wise to use a voltage divider though?

And interestingly the Arduino doesn't seem to mind being powered by the same laptop as the ESP32.

Sender (version for Arduino Uno, connect Arduino tx pin (1) to ESP pin 16 and connect Arduino ground to ESP32 ground):

void setup() {
  Serial.begin(9600);
  Serial.println("Started the Arduino");
}

void loop() { 
  Serial.write("teste\n");
  delay(200);
}

And all the above scripts seem to work just fine with a serial baud rate of 115200.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.