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.

@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

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

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.

here.

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]);

'data[x] = x (or xxx) \n'
that is between 11 & 13 bytes * 4 + 'Got some serial data'\n

so reception does take time, but for every 4 bytes you send 65 byes or so, filling up the TX buffer completely. Speed wise you will be on par input to output more or less, (given that 9600 * 12 = 115200) but the 16 byte header will cause the TX buffer to overflow if the data stream is continuous, after 4 iterations already..
Anyway it is all very unimportant.

that is so true.

Yes of course, and then all the work starts.

he (that is actually an assumption) will want his code to work using those pins, i should really just quickly check to see if it does on one of my ESp32's I have the facilities set up.

1 Like

I got all that, but, so was i,... just making sure something should come out. I use the 'if (!Serial.available()) delay(1);' method a lot when dealing with data streams with an unknown (or variable) length. (basically, 'oh something has come in, let's wait and see the complete message. Like waiting next to the fax machine the moment it starts producing the message.)

Anyway on a different point. Pins 12 & 14 should do the trick just fine, i assigned Serial2 to them and have reception and transmission. So just assuming that the hardware is connected properly, what is being sent ?

I did not actually. I just understood that the Header bit from the sensor was supposed to be 0xFF (or 255, according to my hexa-to-decimal conversion lol).

I will try this tonight when i get back home.

This is a great idea, I will also try this if all else fails.

I really appreciate you going through the effort the verify this independently. I wish i could answer your question. I will update you when i have tested further, and in the meantime, any other ideas are very much appreciated.

Regarding the efficiency of the code (as discussed above), At this point all i'm aiming for is to get it working. However, any feedback for keeping the code robust and efficient is appreciated as it gives me pointers of good practice after the communication is established.

Thanks all

Just had another look at the datasheet, so just to make sure, you are powering the sensor with 3.3v, that would mean that there is no need to modify the logic level.
Now the TX & RX lines need to be crossed over. TX ESP -> RX sensor & TX sensor -> RX ESP

I personally have resorted to using lines with a 1K resistor in them for experimentation, which will prevent burning out a GPIO pin in case of wrong connection.

It really wasn't a lot of work, i had almost all of it done already since i have been working on a triple MIDI-merger with an ESP32.