ESP32- Help with Software Serial

Good day guys & gals,
Ive been working to interface an A02YYUW Ultrasonic sensor with my ESP32. The RX/TX pins are connected to Pins 12 and 14, and I cannot change this in order to use Hardware serial, so i've been trying to make SoftwareSerial work.

The issue I'm having is, that my UART readout is 255 for all of the 4 bits. As such, I am not getting a good reading from the sensor. I've verified my connections to the best of my abilities, so I suspect it's a code issue. Any help in this manner would be appreciated. Thanks!


// Import required libraries
#include <Arduino.h>
#include <SoftwareSerial.h>

#define MYPORT_TX 12
#define MYPORT_RX 14

unsigned char data[4]={};
float distance;
EspSoftwareSerial::UART myPort;

void setup()
{
  Serial.begin(115200); // Standard hardware serial port 
  
  myPort.begin(9600, EspSoftwareSerial::SWSERIAL_8N1, MYPORT_RX, MYPORT_TX, false);
  if (!myPort) { // If the object did not initialize, then its configuration is invalid
    Serial.println("Invalid EspSoftwareSerial pin configuration, check config"); 
    while (1) { // Don't continue with invalid configuration
      delay (1000);
   }
  }  
}

void loop() {
    do{
      for(int i=0;i<4;i++)
     {
       data[i]=myPort.read();
     }
  }while(myPort.read()==0xff);
  
  Serial.print("Data 0 =");
  Serial.println(data[0]);
  delay(500);
  Serial.print("Data 1 =");
  Serial.println(data[1]);
  delay(500);
  Serial.print("Data 2 =");
  Serial.println(data[2]);
  delay(500);
  Serial.print("Data 3 =");
  Serial.println(data[3]);
  delay(500);
  
  if(data[0]==0xff)
    {
      int sum;
      sum=(data[0]+data[1]+data[2])&0x00FF;
      if(sum==data[3])
      {
        distance=(data[1]<<8)+data[2];
        if(distance>30){
          Serial.print("distance=");
          Serial.print(distance/10);
          Serial.println("cm");
          }
        else 
              {
                Serial.println("Below the lower limit");        
              }
      }else Serial.println("ERROR");
     }
  myPort.flush();
  delay(500);
}

Does not work with a ESP32.

Why the need for software serial when the ESP32 has multiple hardware serial ports?

1 Like

Thanks for taking the time to respond.

As mentioned above I cannot change the wiring on the ESP32 side.

Sorry, i should have clarified, Im using the EspSoftwareSerial Library for this task.

Good luck.

but you can define any pins as a hwSerial pair. Mind you, those particular pins may cause some issues, but how about you just try to use them for UART2

Serial2.begin(BAUD, SERIAL_8N1, MYPORT_RX, MYPORT_TX);

If you get a 'core-panicked' error then those pins should not be used.

3 Likes

I did not know this. I thought HW serial was limited to pins 1&3 as seen below, however i tried to compile as you suggested and did not get any issues.

I will definitely try this on the ESP when i get home, and will report back. Thanks!

the error may show up as a runtime error related to gpio 14 as far as i can tell.


By default TX0 & RX0 are 1 & 3, but those are also the pins that the USB to TTL interface is connected to, resulting in no reception on the RX pin, so if you'd want to use UART0 without USB, you should already re-define those pins. UART2 has 17 & 16 by default, that actually works on those pins.
UART1 has pins 9 & 10, but those are also used by the flash, and not recommended (causes a run-time error)
so those should be re-defined if you want to use that UART.

Just wondering now, if i set both GPIO 1 & 3 to 'INPUT' one should be able to connect to the USB-TTL while bypassing the ESP's UART, but this is of course a completely different matter.

1 Like

Not the case thus far!

Thank you for the insight. I was under the misconception that the UART pins (all 3 sets) were rigid and could not be reassigned, however, it is very useful to see that this is not the case.

Not sure you should have semicolon there :thinking:

particularly since there is no check on available() at all.

It's a do while loop. A pretty dodgy one at that. But yes, it would need the semicolon because of the do.

This do while will lock everything up until there is something available on the serial line. I would think working the other way and checking for myport.available() would be a better option. You could even wait for myport.available() to be 4 and know that you can just read in all four values back to back.

1 Like

@Deva_Rishi I uploaded the modified code this morning.
Good news, no runtime error!
Bad news, still no usable UART reading
image

Going to try to connect the setup to an oscilloscope to ensure there is some reading output from the sensor.

Firstly, thank you @Delta_G and @cherk for chiming in.

Im not exactly sure what you mean by this, but will look into the .available() command to see if i can improve. That section of the code was shamelessly copied from the DF robot example as a (theoretically) "working" starting point.

EDIT: @Delta_G, Would this be an appropriate implementation of the myPort.(available) as you sugested?

  // reply only when you receive data:
  if (myPort.available() == 4) {
    // read the incoming bytes:
    data[] = Serial.read();  

well really that is to be expected with this loop really.

You don't check available(), and only if the result of read() == 255 do you continue anyway.
try

uint8_t i = 0;
while ((myPort.available()) && (i < 4)) {
  data[i]=myPort.read();
  i++;
  if (!myPort.available())) delay(2);
}

of course actually myPort should be replaced with the UART you are using.
easiest way to do that is by defining a macro

#define myPort Serial1

Please show us the updated code in your next reply

I really thank you for taking time to help me here.

I've implemented your suggested changes, please see below.


// Import required libraries
#include <HardwareSerial.h>

#define MYPORT_TX 12
#define MYPORT_RX 14

float distance;
#define myPort Serial2

void setup()
{
  Serial.begin(115200); // Standard hardware serial port 
  Serial2.begin(9600, SERIAL_8N1, MYPORT_RX, MYPORT_TX);  
}

void loop() {
  uint8_t i = 0;
  while ((myPort.available()) && (i < 4)){
    data[i]=myPort.read();
    i++;
    if (!myPort.available()) delay(2);
  }
  
  Serial.print("Data 0 =");
  Serial.println(data[0]);
  delay(500);
  Serial.print("Data 1 =");
  Serial.println(data[1]);
  delay(500);
  Serial.print("Data 2 =");
  Serial.println(data[2]);
  delay(500);
  Serial.print("Data 3 =");
  Serial.println(data[3]);
  delay(500);
  
  if(data[0]==0xff)
    {
      int sum;
      sum=(data[0]+data[1]+data[2])&0x00FF;
      if(sum==data[3])
      {
        distance=(data[1]<<8)+data[2];
        if(distance>30){
          Serial.print("distance=");
          Serial.print(distance/10);
          Serial.println("cm");
          }
        else 
              {
                Serial.println("Below the lower limit");        
              }
      }else Serial.println("ERROR");
     }
  Serial2.flush();
  delay(500);
}

And upon making those changes, heres the printout
image

The delay isn't necessary. This just creates blocking code. Do it like you did in reply 13 and just wait until 4 bytes are available but allow for the possibility that there may be more than four byte.

if (myPort.available() >= 4) {
    // read the incoming bytes:
    for(int i = 0; i<4; i++){
        data[i] = myPort.read();
    }
}

I tried this, and still no reading. Interesting to see that now all bits are 0 instead of 255. Ive verified the HW wiring (TX, RX, GND all good, sensor receiving 3.4V) And trying to probe with the oscilloscope now.

Again, want to thank you @Delta_G for your time and effort in this manner

You understand that 255 is what you get when you read the port when there's nothing there to be read right. That's the source of 255.

Try this and see if it is ever getting four bytes to read and going into the if statement. This is how we debug, stick a print in there to see if things are happening.

if (myPort.available() >= 4) {
   Serial.println("Got some serial data!");
    // read the incoming bytes:
    for(int i = 0; i<4; i++){
        data[i] = myPort.read();
        Serial.print("data[");
        Serial.print(i);
        Serial.print("] = ");
        Serial.println(data[i]);
    }
}

those 2 ms we can spare, reception of a byte at 9600 takes just over 1 ms.
What i did forget (and you missed as well)

if (i == 4) { // only then was the transmission complete, otherwise you may still be looking at old data.

That can be done in your method as well (just to be clear, yes my code is blocking in a sense, but this is not the issue the OP is having, it can be optimized later once reception has been confirmed)
Keep in mind that you are transmitting more bytes than you are receiving and although you are transmitting at a higher speed, you transmit up to 10 bytes for every byte received + the notification) Once the TX buffer is full, Serial.print() becomes blocking automatically (basically the program will wait until there is space in the TX-buffer) So you debug code is just as blocking as mine.

btw. Thanx for the help though.

@zach3d How about first you verify that those pins are actually working as a tx/rx pair by sending Serial data from the TX pin (and receive them with a different device i guess you will have an arduino lying around somewhere) and receive from the RX-pin and send that output to the USB-serial.

You're speaking for the OP there. He may want his code to be more responsive.

No, mine waits until available() returns 4 or more. It won't start reading until all four bytes are there.