Click here for a free subscription to "HDE" our site newsletter.

Arduino Distance Sensor Software Sketch

Get part 2 of the Arduino Distance Sensor Project

Arduino Distance Sensor Software Sketch

Click to get the full project details by subscribing free to HDE Magazine.

Copy the code sketch below, paste it into your Arduino programming software and load it into your Arduino to run the distance sensor project.

You must also download the timerOne library from

Install the library using the guide

This is where the magic happens...


The main code blocks of the sketch are:

  1. Library include files
  2. Definitions
  3. Setup
  4. Main loop
  5. Timer interrupt routine
  6. Echo interrupt routine

Library include files

Two libraries are included with the #include directive. They both pull in definitions and give your sketch information regarding the liquid crystal display and the Timer 1 driver respectively.

The liquid crystal library was installed by default when you installed the Arduino software on your computer.


As the Arduino starts up various constants and variables are defined. First the control pins for the trigger and echo signals of the HC-SR04 are designated. These must match the actual connections between your boards.

#define trigPin 12
#define echoPin 2

An id is then assigned to the interrupt generated from the echo signal.

#define echo_int 0

Timer one is set to time out every 50 uS and a tick counter allows the routine to measure a 200 mS duration after which a new trigger pulse is initiated.

#define TIMER_US 50
volatile int tick_counts = 4000;
volatile int trigger_time_count = 0;

'tick_counts' is defined as a variable rather than a constant so that it can be adjusted on the fly if we need to later.

The variables required to measure the duration of the echo pulse are defined and initialized to zero.

volatile long echo_start = 0;
volatile long echo_end = 0;
volatile long echo_duration = 0;

Next we define 16 distance ranges to characterize the echo signal distance. One range or zone for each column on the 16 character display.

#define RANGES 16
#define MAX_ZONE 18000
int zones[RANGES];
volatile int range_hits[RANGES];

A variable holds the current distance found in cm.

volatile int range_cm;

Bargraph characters

The LCD display module allows us to define up to eight special characters over and above the built in character set. These are used for the mini bargraph characters of the distance sensor graphic.

Each of the special characters 'bar0'-'bar7' consists of an array of eight bytes. One byte for each row of the character. The least significant five bits each correspond to a pixel in the character row


The setup() function is called by the Arduino start up code once during the reset sequence. Any necessary initialisation can be done here.

The I/O pins that we are going to use are set as 'INPUT' or 'OUTPUT' as appropriate. The timer is initialised and interrupt routines attached to interrupts so that the routines will be executed when the interrupts fire.

The LCD begin() routine is called to initialise the LCD display.

The USB virtual serial port is initialised so that we can use it for debugging the software when needed.

Next the distance zones array is initialised by calculating equally spaced zones from the 'MAX_ZONE' value in uS.

To complete the setup the special LCD characters are created and stored in the LCD module then a rough scale in cm is printed to the second row of the display.

Note that we are not going to use the keyboard of the LCD in this project but we may well come back to it in a later exercise.

Main loop

After setup() is complete the loop() function is called. As it's name suggests it will execute to the end then start again at the top forever or until it is powered off or reset. This is where we make the device accessible to the outside world and do things that are not time critical.

All the critical stuff in this project is done in the interrupt routines leaving only the display to be handled in the main loop.

I decided to update the display twice a second so the first thing that loop() does is test a timer to see if it has been at least 500mS since the last update.

LCD distance display

If the timer triggers then the LCD display is updated after sending some diagnostic information to the serial monitor port.

As a general rule you should always build some diagnostics of some sort into your software because it can often be invaluable when you find that your code doesn't work in the way that you intended. Printing information to the serial monitor is an easy and quick method of debugging your programs.

The display is generated by writing one of the special bargraph characters to each of the 16 positions. The actual character written is determined by the corresponding value from the 'range_hits' array.

The range_hits array contains one counter for each character. The value of the counter is an indication of how often a distance reading in the corresponding range has been detected recently.

The resulting display is a line of bargraphs that indicate various objects seen by the sensor.

Timer Interrupt Routine

The timerIsr() function is called when the timer times out every 50uS. For now it simply calls the trigger_pulse() function which deals with the timing of the pulse on the trigger output pin.

Each time the routine is called it decrements the counter by subtracting 1 until it reaches zero where it is reset and 'state' is set to '1' to start the pulse output.

The pulse output is generated every 200mS by the simple finite state machine in the trigger_pulse function.

The state machine is normally in state '0' but is set to state '1' when the timer times out. While in state '1' the trigger output pin is set 'HIGH' which produces a +5v level on the trigger pin. The state is then immediately set to '2' and the function exits.

The next time the interrupt routine calls trigger_pulse() 50uS later, the code in state '2' of the state machine sets the trigger pin 'LOW' which sends the output level to 0v. The state is then set to '0', the normal or idle state.

That is how this function generates a trigger pulse of 50uS duration which is comfortably in excess of the minimum 10uS required by the HC-SR04 module.

Echo Interrupt Routine

The second interrupt routine deals with the echo pulse coming back from the HC-SR04 module. It's called 'echo_interrupt()' and it measures the duration of the echo in micro seconds.

The echo interrupt is set to trigger whenever the level on the echo input pin changes state either from low to high or from high to low.

The first job is to determine which end of the pulse has just triggered the routine and this is done by testing the level on the pin. If it is high then this must be the start of the pulse and if it is low then it must be the end of the pulse.

Depending on which end of the pulse we are at the 'echo_start' and 'echo_end' variables are set to the start and end times of the pulse in micro seconds. When the end of the pulse is detected the 'echo duration' is calculated from the difference between end and start times and the distance in centimeters is then calculated by dividing by 58.

When the echo duration has been calculated it is sorted into the appropriate range or zone.

The corresponding element of the 'range_hits' array is increased by 3 and all other elements decreased by 1. The effect of this is to provide persistence to the display. The relative height of each bargraph is an indication of how strong the echo is from objects at different distances.


When you have connected it up, installed the TimerOne library and downloaded the sketch from the website to the Arduino you should have a working ultrasonic distance sensor.

Point the sensor at the objects of interest and watch the echos pop up on the display.

Now subscribe to our newsletter and don't miss a thing

Comments (5)

Topic: Arduino Distance Sensor
Full StarFull StarFull StarFull StarFull Star 5/5 (4)
Full StarFull StarFull StarFull StarFull Star
Tony (US) says...
One quick question. How does the LCD know what to do? How do you make that connection from the Arduino to the LCD? That's the part I'm having trouble with, I can't figure out what pins from the Arduino that I need to connect to the LCD then the LCD to the Ultrasonic sensor
16th April 2018 4:47am
Full StarFull StarFull StarFull StarFull Star
Pavan kumar (India) says...
I was wondering if the same code can be used with a normal 16X2 lcd which comes without the keypad shield. What are the changes I need to do in order to make the same project run on a normal 16X2 display?
19th August 2017 9:00am
Full StarFull StarFull StarFull StarFull Star
MrMaint (US) says...
Very nice presentation. I think there are a couple of areas where you could simplify your code without changing it's function. Your 50us pulse is going to be high then low, then high, then low every 50us. Your call to your routine is nice, but the routine could be simplified... void trigger_pulse() { static volatile bool state=0; state=1-state;digitalWrite(trigPin,state); } And your routine for weighting the hits... for(i=0,i<RANGES,i++) { if(i!=found_hit) { ... Read More
23rd November 2016 7:29pm
Full StarFull StarFull StarFull StarFull Star
Bob Jones (US) says...
This code was just what I was looking for and then some. I am building some robot classes and needed logic like this to handle my obstacle sensor.

The inclusion of the LCD code got me over another hump as well.

I will be "cleaning up" this example to encapsulate its functionality a bit better and then incorporating it into my robot code. I will post what I have once it's working.
27th January 2016 1:41am
Steve (UK) says...
Hi Bob,

I'm pleased the article has helped. I would be very interested to see how your project turns out.

31st January 2016 1:36pm

Add Comment

* Required information
(will not be published)
Bold Italic Underline Strike Superscript Subscript Code PHP Code Quote Insert line Bullet list Numeric list Link Email Image Video
Smile Sad Huh Laugh Mad Tongue Crying Grin Wink Scared Cool Sleep Blush Unsure Shocked
Enter code:
Notify me of new comments via email.
Remember my form details on this computer.
I have read and understand the privacy policy. *
I have read and agree to the terms and conditions. *
Click here for a free subscription to "HDE" our site newsletter.