PC Services


PC Services (Electronics)

Better Echo Example for Ultrasonic Distance Sensor HC-SR04

Tel: 0118 946 3634

linked-in profile facebook profile

   The Company 
   Resources / Examples 
       Better Echo Example 

Better Example Sketch for Ultrasonic Range Sensing

Other Pages cover


This examples use a better replacement for the function 'pulseIn', and sits in a loop getting results and putting them to the serial port. However unlike other examples, does the following -

  • Replaces 'pulseIn' or other libraries. Use of pulseIn with or without optional TIMEOUT parameter. Other libraries like Ping or NewPing, can make life easy but it does NOT catch and report easily many error conditions and can often appear to 'lock up' in blocking calls, they all exhibit. Some have delays of up to one second. So the default TIMEOUT value for pulseIn is one second meaning your programme could sit wasting time for a second before returning from that function.
  • Add error indication and reporting, instead of one error code for any error, firstly by TWO LEDs to give visual feedback also error message after a test distance check at startup error of faulty unit and code reported. The function 'GetEchoTime( )' reports back separate codes
    • Timeout
    • Echo did not start
    • Echo pin was high already before trying to do a trigger
  • By default example is set to poll the sensor 30 ms after the last reading has been converted
  • Initial setting of TRIG to LOW is done ONCE in 'setup( )'
  • Only VALID values are output to the serial port
  • Maths is kept at integer maths

This example exercises the sensor rapidly if you do not get steady readings for a stationary object, then if you have not altered the code at all, the most likely scenario is that your sensor has died or has bad components on it. See the Circuitry section for more information and possible remedies.

Back to top

Error Code Reporting

Errors are reported as software error codes, no reading, and in the example by LED combinations. The LED pins are defined as constants in the code and can be changed if required.

On startup both are lit as a diagnostic check, then each time through the loop they are first cleared, then set if required. Other combinations for the LEDs are -

LED Error codes
Red LED Yellow LED Reason
OFF OFF Valid Reading
ON OFF Out of Range (main loop check)
or Timeout from getting echo
ON ON ECHO HIGH before setting Trigger
ECHO not gone high within 1 ms

The GetEchoTime function returns a range of values, usually between 0 and the maximum value (MAX_ECHO). However usuable range for most Ultrasonic Distance Sensors is a minimum of 3 cm, with the fact that the sound wave takes at least 50 µs per cm, this means counts below 150 are NOT VALID as timings. Therefore values below 150 are used as error codes, currently these are

GetEchoTime Error codes
Value Error Condition
0 Echo length exceeded timeout
1 ECHO not gone high within 1 ms
2 ECHO HIGH before setting Trigger

More codes may get added later

The only error reported at startup is sent to the serial port for faulty unit and error code as above.

Back to top

Better Echo Example Code

This example can be viewed below or download a zip file of example betterecho.zip

Back to top

Read the comments at top of the code and the first section of constants (#define) for pin configuration and settings.

/* Ultrasonic distance sensor example - Better Version Paul Carpenter, PC Services 26-Jan-2017 Update 4-Feb-2017 PC make variables more obvious Uses HC-SR04 four pin ultrasonic sensor to continuously output distances found when in range (every second). Results WHEN valid output onto serial port at 115,200 baud Both LEDs ON when program starts and any other time for no start of echo received (probably bad wiring or faulty unit) on start up also serial port error string Lights RED Led when No Reading received or out of range Lights Yellow LED when too close (less than 5 cm) LEDs are connected via 330R or similar resistor other end of LED to GND Works on principle sound travels at 343.2 m/s in dry STILL air at 20 deg C So time per cm is 29.137529 micro seconds /cm For round trip (there and back) 58.275058 micro seconds /cm In order to reduce code size and execution time values are kept as integers and factor of 58 to calculate distances */ /* Pin definitions */ #define echopin 4 #define trigpin 5 #define redled 6 #define yellowled 7 /* time between readings in ms On Arduino Mega readings belown 20ms interval could have residual echo issues */ #define INTERVAL 30 /* Scale factor round trip micro seconds per cm */ #define SCALE_CM 58 #define SCALE_CM_ROUND (SCALE_CM/2) /* Timeout for distance sensing rather than 1 second in us */ #define MAX_ECHO 300000 #define MIN_ECHO (3 * SCALE_CM) /* Timeout for start of ECHO pulse being received in us */ #define MAX_START_ECHO 1000 /* Limits for application ranges in cm */ #define MIN_RANGE 4 #define MAX_RANGE 500 #define MAX_ERROR 10 /* calculated distance in centimetres */ unsigned long distance; unsigned int echotime; unsigned long next_time, new_time; /* Distance sensor function to get echo time Note most ultrasonic distance sensors are only usable beyond 3 cm So usable range is 3 * SCALE_CM to MAX_ECHO, therefore anything below 3 * SCALE_CM should be treated as error Returns echo time in microseconds Maximum MAX_ECHO Minimum 3 * SCALE_CM (minimum usable) error codes Error 2 Echo HIGH before start Error 1 Echo did not start Error 0 NO ECHO (Timeout) Timeout for measurements set by MAX_ECHO */ unsigned long GetEchoTime( ) { unsigned long start_time; unsigned long end_time; /* check Echo if high return error */ if( digitalRead( echopin ) ) return( 2 ); /* note start time */ start_time = micros( ); /* send the trigger pulse */ digitalWrite( trigpin, HIGH ); delayMicroseconds( 10 ); digitalWrite( trigpin, LOW ); /* Set timeout for start of echo pulse */ end_time = start_time + MAX_START_ECHO; /* check ECHO pin goes high within MAX_START_ECHO if not return error of 1 */ while( !digitalRead( echopin ) ) if( micros( ) > end_time ) return( 1 ); /* Check for Length of echo occurred or timeout */ start_time = micros( ); end_time = start_time + MAX_ECHO; while( digitalRead( echopin ) ) if( micros( ) > end_time ) break; end_time = micros( ); /* Return time or timeout */ return( ( start_time < end_time ) ? end_time - start_time: 0 ); } void setup( ) { /* set time from reset */ next_time = INTERVAL; Serial.begin( 115200 ); /* Configure pins and ensure trigger is OFF */ pinMode( trigpin, OUTPUT ); digitalWrite( trigpin, LOW ); pinMode( echopin, INPUT ); /* Configure LED drive and both LEDs On at start up */ pinMode( redled, OUTPUT ); pinMode( yellowled, OUTPUT ); digitalWrite( redled, HIGH ); digitalWrite( yellowled, HIGH ); /* Send signon message */ Serial.println( F( "PC Services - Better Range test" ) ); /* Do test reading to check if unit connected */ distance = GetEchoTime( ); if( distance > 0 && distance <= 10 ) { Serial.println( F( "No unit found - Error = " ) ); Serial.println( distance ); } } void loop( ) { new_time = millis( ); /* check if to run this time */ if( new_time >= next_time ) { /* Turn LEDs Off */ digitalWrite( redled, LOW ); digitalWrite( yellowled, LOW ); /* Calculate distance */ echotime = GetEchoTime( ); /* only scale valid readings 0 is timeout or 1 is no echo realistically minimum accurate or physical range is 3cm */ if( echotime > MAX_ERROR ) distance = echotime /SCALE_CM; /* catch errors first */ if( echotime <= MAX_ERROR || distance > MAX_RANGE ) { digitalWrite( redled, HIGH ); // Range error too large if( echotime > 0 && echotime <= MAX_ERROR ) digitalWrite( yellowled, HIGH ); // Light 2nd LED error } else if( distance < MIN_RANGE ) digitalWrite( yellowled, HIGH ); // Range too close else Serial.println( int( distance ) ); // In range output distance next_time = new_time + INTERVAL; // save next time to run } }

Back to top

Other Pages cover

Interested in something similar contact sales.

© 2017 onwards by PC Services, Reading UK Last Updated: 8th February 2017
If you encounter problems with this page please email your comments to webmaster