Help understanding/breaking down this code.....

HI all,

I have recently bought a ‘A02YYUW’ [Waterproof Ultrasonic Sensor](A02YYUW-DFRobot Waterproof Ultrasonic Sensor SKU: SEN0311) to use in place of the waterproof ultra sonic sensor I bought from Amazon.

The one I bought off Amazon works jsut fine using the standard/beginners HC SR04 code you can find all over the internet -Random Nerd Tutorials (for example)

However the example code provided with the A02YYUW sensor is completely different and I’m sure if I just copied and pasted it, it would work just fine. I’m just a little unsure about the way it’s all witten.

/*
  *@File  : DFRobot_Distance_A02.ino 
  *@Brief : This example use A02YYUW ultrasonic sensor to measure distance
  *         With initialization completed, We can get distance value 
  *@Copyright [DFRobot](https://www.dfrobot.com),2016         
  *           GUN Lesser General Pulic License
  *@version V1.0           
  *@data  2019-8-28
*/

#include <SoftwareSerial.h>

SoftwareSerial mySerial(11,10); // RX, TX
unsigned char data[4]={};
float distance;

void setup()
{
 Serial.begin(57600);
 mySerial.begin(9600); 
}

void loop()
{
    do{
     for(int i=0;i<4;i++)
     {
       data[i]=mySerial.read();
     }
  }while(mySerial.read()==0xff);

  mySerial.flush();

  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");
     }
     delay(100);
}

I’m not sure what the do while loop is doing or mean?
What is the 0xff bit about?
And the if statement following the flush?

Pretty much the whole loop isn’t anything like I’ve been used to since starting this Arduino journey. If anyone can help that would be apprecitated. Even just a hint that I should go away and read up on this, that or the other.

Thank you

Search tags:

A02YYUW
DYPA02YY

the do while may be waiting for a string of 0xFF characters. or it may be the start bit (forget if it's a 0 or 1) is constantly asserted on the receive pin

i say string because it doesn't check for a character to be available and the loop within the do/while reads 4 characters regardless. so either it just happens to read at the right time or there is a persistent stream of 0xff characters being transmitted to it.

The code works but it looks like it was designed by someone who had little or no experience programming. It makes very little sense. It reads four times from the serial port WITHOUT checking to see if data was available. Then it tries to read a 5th time and if there IS a character but it ISN'T 0xFF it tries again. If the 5th read is 0xFF and there was no 1st character or the 1st character is also 0xFF, check that the sum of the first three reads is equal to the fourth read. If it is, the 2nd and 3rd characters are a 16-bit signed integer "distance" in tenths of a centimeter. If the distance is larger than 3.2767 meters, it will read as NEGATIVE.

I think the only thing that allows this to work is the checksum.

It appears that the message format is five bytes:
0xFF, distanceHigh, distanceLow, checksum, 0xFF

Thank you both for your replies.

I've uploaded the above code but got a constant error using a Micro. I thought the TX/RX were the wrong way round but that didn't solve anything once I swapped them

I used the hardware serial instead of the software serial (Bit banging?? (is that the right term)) and it works fine.

I'm just wondering if there is any way I can simplify the code to something that a C++ beginner will understand a little easier. If there isn't then I'll just have to figure out all the 0xFF stuff but hexi' is something fairly new to me.

Just for completion and in case there is anyone else having trouble or wondering where the code is, I came across this code on github. I haven't tried it yet but it's worth a shot.

/**
 * 
 * Author: Ritesh Talreja, Made in China, Warehouse: Shenzhen, Guangdong.
 * 
 * Components: Arduino UNO, DYPA02YYUM  v1.0
 * 
 * Arduino UNO +5V    --> DYPA02YYUM Pin 1 Red
 * Arduino UNO GND    --> DYPA02YYUM Pin 2 Black
 * Arduino UNO Pin 11 --> DYPA02YYUM Pin 3 or Floating
 * Arduino UNO Pin 10 --> DYPA02YYUM Pin 4
 * 
 * Since Arduino UNO does not have 2 hardware serial ports.
 * We are using 1 software serial port connected to the sensor.
 * All data from software serial port is copied onto hardware serial port to view in "Arduino IDE Serial Monitor".
 */

#include <SoftwareSerial.h>

SoftwareSerial ss (10, 11);   // RX, TX

byte hdr, data_h, data_l, chksum;
unsigned int distance;

void setup()
{
  Serial.begin(57600);
  while (!Serial);

  ss.begin(9600);
}

void loop()
{
  if (ss.available())
  {
    hdr = (byte)ss.read();
    if (hdr == 255)
    {
      data_h = (byte)ss.read();
      data_l = (byte)ss.read();
      chksum = (byte)ss.read();

      if (chksum == ((hdr + data_h + data_l)&0x00FF))
      {
        Serial.print(hdr);
        Serial.print(",");
        Serial.print(data_h);
        Serial.print(",");
        Serial.print(data_l);
        Serial.print(",");
        Serial.print(chksum);
        
        Serial.print("=");
      
        Serial.print(hdr, HEX);
        Serial.print(",");
        Serial.print(data_h, HEX);
        Serial.print(",");
        Serial.print(data_l, HEX);
        Serial.print(",");
        Serial.print(chksum, HEX);
        Serial.print(" => ");
  
        distance = data_h * 256 + data_l;
        Serial.print(distance, HEX);
        Serial.print("=");
        Serial.print(distance, DEC);
        Serial.println(" mm");
      }
    }
  }
  delay(100);
}

EDIT.
I have just tried it using the new code above, using software serial and it seem to be working ok. The output appears to be showing what it's been asked to, though I'll be honest, the only thing I understand right now is the distance!!

You can also try this: Compiles, untested:

/*
 * 
 */

#include <SoftwareSerial.h>

SoftwareSerial mySerial(11,10); // RX, TX

enum statesRX
{
    ST_RX_HEADER=0,
    ST_RX_DATA,
    ST_RX_PROCESSMSG    
};

unsigned char data[4]={};

void setup()
{
    Serial.begin(57600);
    mySerial.begin(9600);
}

void loop()
{
    static uint8_t
        stateRX = ST_RX_HEADER,
        rxIdx;
        
    if( mySerial.available() > 0 )
    {
        do
        {
            uint8_t ch = mySerial.read(); 
            switch( stateRX )
            {
                case    ST_RX_HEADER:
                    if( ch == 0xff )
                    {
                        rxIdx = 0;
                        data[rxIdx++] = ch;
                        stateRX = ST_RX_DATA;
                        
                    }//if
                    
                break; 

                case    ST_RX_DATA:
                    data[rxIdx++] = ch;
                    if( rxIdx == 4 )
                        stateRX = ST_RX_PROCESSMSG;
                break;

                case    ST_RX_PROCESSMSG:
                    uint8_t sum = 0;
                    for( uint8_t i=0; i<3; i++ )
                        sum = sum + data[i];

                    if( sum == data[3] )
                    {
                        uint16_t distance = ((uint16_t)data[1] << 8) + data[2];
                        if( distance > 30 )
                        {
                            Serial.print("Distance = ");
                            Serial.print(distance/10);
                            Serial.println("cm");
                            
                        }//if
                        else
                            Serial.println("Distance below lower limit.");     
                        
                    }//if
                    else
                        Serial.println("Msg checksum error.");

                    stateRX = ST_RX_HEADER;
                    
                break;
                
            }//switch
            
        }while( mySerial.available() > 0 );
        
    }//if
    
}//loop

This is how I would read the input from the distance sensor, assuming I have the message format correct.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(11, 10); // RX, TX
byte Buffer[5];
unsigned BytesRead = 0;
unsigned DistanceInMM = 0;

void setup()
{
  Serial.begin(57600);
  mySerial.begin(9600);
}

void loop()
{
  if (mySerial.available())
  {
    // Put the character in the buffer
    Buffer[BytesRead++] = mySerial.read();

    // Validate the input so far:
    switch (BytesRead)
    {
      case 1:  // Start character
        if (Buffer[0] != 0xFF)
        {
          Serial.print("Invalid start character: ");
          Serial.println(Buffer[0], HEX);
          BytesRead = 0; // Start over
        }
        break;

      case 4:  // Checksum
        byte sum;  // DO NOT INITIALIZE LOCAL VARIABLES IN A 'case' CLAUSE.
        sum = Buffer[0] + Buffer[1] + Buffer[2];
        if (sum != Buffer[3])
        {
          Serial.print("Invalid checksum: 0xFF + 0x");
          Serial.print(Buffer[1], HEX);
          Serial.print(" + 0x");
          Serial.print(Buffer[2], HEX);
          Serial.print(" != 0x");
          Serial.println(Buffer[3], HEX);
          BytesRead = 0; // Start over
        }
        break;

      case 5: // End character
        if (Buffer[4] != 0xFF)
        {
          Serial.print("Invalid end character: ");
          Serial.println(Buffer[4], HEX);
          BytesRead = 0; // Start over
        }
        break;
    }
  }

  if (BytesRead == 5)
  {
    DistanceInMM = Buffer[1] * 256 + Buffer[2];
    BytesRead = 0; // Look for a new start next time

    if (DistanceInMM > 30)
    {
      Serial.print("distance=");
      Serial.print(DistanceInMM / 10.0, 1); // Convert to cm and show with 1 decimal place
      Serial.println("cm");
    }
    else
    {
      Serial.println("Below the lower limit");
    }
  }
}

Thank you both for your time writing your codes, much appreciated!!

They both work just fine! Much better than the first code I posted which throws up errors every 5-6 readings.

Blackfins, yours seems to print just fine and with no errors.

Johnwasser, your also prints just fine but also displays debug errors (shown below), that to be honest can just be ignored I think??

Invalid start character: 5
Invalid start character: 39
Invalid start character: 3D
distance=133.7cm
Invalid start character: 5
Invalid start character: 34
Invalid start character: 38
distance=133.6cm
Invalid start character: 5
Invalid start character: 34
Invalid start character: 38
distance=133.2cm
Invalid start character: 5
Invalid start character: 38
Invalid start character: 3C
distance=133.2cm

What I am realising is I need to start looking at HEX and serial communication beacause it still makes little or no sense.

Thank again to both for your time :slight_smile:

GaryRH:
Johnwasser, your also prints just fine but also displays debug errors (shown below), that to be honest can just be ignored I think??

They're not really errors, just informing you that the logic is expecting 0xff and didn't see it. You can comment out those prints.

Brilliant. Thanks both

Looks like you are getting three additional message bytes. I don’t know what they might mean and the documentation I can find doesn’t mention them at all. It makes no sense that they would not be included in the checksum. You can comment out:

          Serial.print("Invalid start character: ");
          Serial.println(Buffer[0], HEX);

Hi again!

The code @johnwasser and Blackfin work perfectly and display the distance in the serial monitor without any issues. I have ran into bit of a problem when trying to use the distance to switch LEDs on and off. I have tested this with the standard 5v HC SR04 ultrasonic sensor and the code works without issue. When I replace the HV SR04 code with the code used for the new Ultrasonic sensor, nothing happens LED wise and I think I’m starting to go blind looking at the code over and over. I can’t see why it’s not working and I’m hoping another set of eyes might be able to help.

It prints to the serial fine so I know the sensor is working, it just won’t light up the LEDs :frowning:

I know the code is super basic but that’s all I need at this stage to make sure the LED idea works

(I’m using pin 9 for the Ultrasonic sensors VCC so I can powersave)

#include <Wire.h>
#include <SoftwareSerial.h>

const int redPin = 6; //Red LED pin
const int greenPin = 7; //Green LED pin
const int bluePin = 8; //Blue LED pin
const int usPinVcc =  9; //Ultrasonic Sensor Vcc Pin

//A02YYUW Ultrasonic Sensor

SoftwareSerial mySerial(11, 12); // RX, TX

enum statesRX
{
  ST_RX_HEADER = 0,
  ST_RX_DATA,
  ST_RX_PROCESSMSG
};

int distanceInMM; //distance from US sensor in mm

unsigned char data[4] = {};

void setup() {

  Serial.begin(9600);
  mySerial.begin(9600);

  //LEDs
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

  //US sensor
  pinMode (usPinVcc, OUTPUT); //Vcc control
  digitalWrite (usPinVcc, HIGH);
}

void loop() {

  sendPing();

  if (distanceInMM >= 10 && distanceInMM <= 30) {
    digitalWrite(redPin, HIGH);
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, LOW);
  }
  else if (distanceInMM >= 31 && distanceInMM < 50) {
    digitalWrite(redPin, LOW);
    digitalWrite(bluePin, HIGH);
    digitalWrite(greenPin, LOW);
  }
  else if (distanceInMM >= 51 && distanceInMM <= 200) {
    digitalWrite(redPin, LOW);
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, HIGH);
  }
  else if (distanceInMM >= 201 && distanceInMM <= 9) {
    digitalWrite(redPin, LOW);
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, LOW);
  }

}


void sendPing() {
  {
    static uint8_t
    stateRX = ST_RX_HEADER,
    rxIdx;

    if ( mySerial.available() > 0 )
    {
      do
      {
        uint8_t ch = mySerial.read();
        switch ( stateRX )
        {
          case    ST_RX_HEADER:
            if ( ch == 0xff )
            {
              rxIdx = 0;
              data[rxIdx++] = ch;
              stateRX = ST_RX_DATA;

            }//if

            break;

          case    ST_RX_DATA:
            data[rxIdx++] = ch;
            if ( rxIdx == 4 )
              stateRX = ST_RX_PROCESSMSG;
            break;

          case    ST_RX_PROCESSMSG:
            uint8_t sum = 0;
            for ( uint8_t i = 0; i < 3; i++ )
              sum = sum + data[i];

            if ( sum == data[3] )
            {
              uint16_t distanceInMM = ((uint16_t)data[1] << 8) + data[2];
              if ( distanceInMM > 9 )
              {
                Serial.print("Distance = ");
                Serial.print(distanceInMM);
                Serial.println("mm");

              }//if
              else
                Serial.println("Distance below lower limit.");

            }//if
            else
              Serial.println("Msg checksum error.");

            stateRX = ST_RX_HEADER;

            break;

        }//switch

      } while ( mySerial.available() > 0 );

    }//if

  }//loop
}
 if (distanceInMM >= 201 && distanceInMM <= 9) {

I can’t think of any numbers that are simultaneously greater than 200 AND less than 10. I suspect you wanted:

 if (distanceInMM >= 201 || distanceInMM <= 9) {

(Numbers that are either greater than 200 OR less than 10.)

GaryRH:
It prints to the serial fine so I know the sensor is working, it just won't light up the LEDs :frowning:

All of the output you have shown so far has indicated distances of about 500mm or more. Your code says to turn off the leads for anything over 200mm. You should check the range limits of your sensor and adjust your ranges to fit the data available. Perhaps you meant 9, 30, 50, and 200 cm? That would be 90, 300, 500, and 2000 mm.

johnwasser:

 if (distanceInMM >= 201 && distanceInMM <= 9) {

I can’t think of any numbers that are simultaneously greater than 200 AND less than 10. I suspect you wanted:

 if (distanceInMM >= 201 || distanceInMM <= 9) {

(Numbers that are either greater than 200 OR less than 10.)

Haha! yes, good catch thank you, changed to OR (copy and pasting error ::slight_smile: )

I have kept the distances small in this case so I can just put a sheet of paper or card in fornt of the sensor to test it. I have change the distances just in case, but unfortunately it has made no difference. Nothing lights up. It doesn’t make sense that the other sesor works but this one won’t.

I’ve just tested the following code to see if I get the correct LEDs light up but for some reasonI only get the Blue LED that comes on (Checksum error), even though the distance is printed (pins are correct). The other 2 just kind flash but not anywhere near full brightness.

I’d expect Green to be lit for the majority of the time and a red or blue flash now and again?

I have commented out the LED if else statements (deleted in example below) in the main loop and amended the sendPing.

function.

#include <Wire.h>
#include <SoftwareSerial.h>

const int redPin = 6; //Red LED pin
const int greenPin = 7; //Green LED pin
const int bluePin = 8; //Blue LED pin
const int usPinVcc =  9; //Ultrasonic Sensor Vcc Pin

//A02YYUW Ultrasonic Sensor

SoftwareSerial mySerial(11, 12); // RX, TX

enum statesRX
{
  ST_RX_HEADER = 0,
  ST_RX_DATA,
  ST_RX_PROCESSMSG
};

int distanceInMM; //distance from US sensor

unsigned char data[4] = {};

void setup() {

  Serial.begin(9600);
  mySerial.begin(9600);

  //LEDs
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

  //US sensor
  pinMode (usPinVcc, OUTPUT); //Vcc control
  digitalWrite (usPinVcc, HIGH);
}

void loop() {

  sendPing();

}


void sendPing() {
  {
    static uint8_t
    stateRX = ST_RX_HEADER,
    rxIdx;

    if ( mySerial.available() > 0 )
    {
      do
      {
        uint8_t ch = mySerial.read();
        switch ( stateRX )
        {
          case    ST_RX_HEADER:
            if ( ch == 0xff )
            {
              rxIdx = 0;
              data[rxIdx++] = ch;
              stateRX = ST_RX_DATA;

            }//if

            break;

          case    ST_RX_DATA:
            data[rxIdx++] = ch;
            if ( rxIdx == 4 )
              stateRX = ST_RX_PROCESSMSG;
            break;

          case    ST_RX_PROCESSMSG:
            uint8_t sum = 0;
            for ( uint8_t i = 0; i < 3; i++ )
              sum = sum + data[i];

            if ( sum == data[3] )
            {
              uint16_t distanceInMM = ((uint16_t)data[1] << 8) + data[2];
              if ( distanceInMM > 90 )
              {
                Serial.print("Distance = ");
                Serial.print(distanceInMM);
                Serial.println("mm");
                digitalWrite(redPin, LOW);
                digitalWrite(bluePin, LOW);
                digitalWrite(greenPin, HIGH);

              }//if
              else
                Serial.println("Distance below lower limit.");
              digitalWrite(redPin, HIGH);
              digitalWrite(bluePin, LOW);
              digitalWrite(greenPin, LOW);

            }//if
            else
              Serial.println("Msg checksum error.");
            digitalWrite(redPin, LOW);
            digitalWrite(bluePin, HIGH);
            digitalWrite(greenPin, LOW);

            stateRX = ST_RX_HEADER;

            break;

        }//switch

      } while ( mySerial.available() > 0 );

    }//if

  }//loop
}

Johnwasser!

So I swapped out the sendPing code for yours and it works a treat! No idea what the difference is between yours and Blackfins are but they both show fine on the serial but Blackfins won’t light up the LEDs? Very odd!

Thanks again

#include <Wire.h>
#include <SoftwareSerial.h>

const int redPin = 6; //Red LED pin
const int greenPin = 7; //Green LED pin
const int bluePin = 8; //Blue LED pin
const int usPinVcc =  9; //Ultrasonic Sensor Vcc Pin

//A02YYUW Ultrasonic Sensor

SoftwareSerial mySerial(11, 10); // RX, TX
byte Buffer[5];
unsigned BytesRead = 0;
unsigned distanceInMM = 0;

unsigned char data[4] = {};

void setup() {

  Serial.begin(9600);
  mySerial.begin(9600);

  //LEDs
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

  //US sensor
  pinMode (usPinVcc, OUTPUT); //Vcc control
  digitalWrite (usPinVcc, HIGH);
}

void loop() {

  sendPing();

  if (distanceInMM >= 90 && distanceInMM <= 300) {
    digitalWrite(redPin, HIGH);
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, LOW);
  }
  else if (distanceInMM >= 301 && distanceInMM < 500) {
    digitalWrite(redPin, LOW);
    digitalWrite(bluePin, HIGH);
    digitalWrite(greenPin, LOW);
  }
  else if (distanceInMM >= 501 && distanceInMM <= 2000) {
    digitalWrite(redPin, LOW);
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, HIGH);
  }
  else if (distanceInMM >= 2001 || distanceInMM <= 89) {
    digitalWrite(redPin, LOW);
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, LOW);
  }

}


void sendPing()
{
  if (mySerial.available())
  {
    // Put the character in the buffer
    Buffer[BytesRead++] = mySerial.read();

    // Validate the input so far:
    switch (BytesRead)
    {
      case 1:  // Start character
        if (Buffer[0] != 0xFF)
        {
          //Serial.print("Invalid start character: ");
          //Serial.println(Buffer[0], HEX);
          BytesRead = 0; // Start over
        }
        break;

      case 4:  // Checksum
        byte sum;  // DO NOT INITIALIZE LOCAL VARIABLES IN A 'case' CLAUSE.
        sum = Buffer[0] + Buffer[1] + Buffer[2];
        if (sum != Buffer[3])
        {
          Serial.print("Invalid checksum: 0xFF + 0x");
          Serial.print(Buffer[1], HEX);
          Serial.print(" + 0x");
          Serial.print(Buffer[2], HEX);
          Serial.print(" != 0x");
          Serial.println(Buffer[3], HEX);
          BytesRead = 0; // Start over
        }
        break;

      case 5: // End character
        if (Buffer[4] != 0xFF)
        {
          Serial.print("Invalid end character: ");
          Serial.println(Buffer[4], HEX);
          BytesRead = 0; // Start over
        }
        break;
    }
  }

  if (BytesRead == 5)
  {
    distanceInMM = Buffer[1] * 256 + Buffer[2];
    BytesRead = 0; // Look for a new start next time

    if (distanceInMM > 30)
    {
      Serial.print("distance=");
      Serial.print(distanceInMM);
      Serial.println("mm");
    }
    else
    {
      Serial.println("Below the lower limit");
    }
  }
}