{"id":2195,"date":"2018-08-08T17:38:29","date_gmt":"2018-08-08T17:38:29","guid":{"rendered":"https:\/\/deepbluembedded.com\/?p=2195"},"modified":"2023-08-17T23:53:12","modified_gmt":"2023-08-17T20:53:12","slug":"ultrasonic-sensor-hc-sr04-pic-microcontrollers-tutorial","status":"publish","type":"post","link":"https:\/\/deepbluembedded.com\/ultrasonic-sensor-hc-sr04-pic-microcontrollers-tutorial\/","title":{"rendered":"Ultrasonic Sensor HC-SR04 With PIC Microcontrollers Tutorial"},"content":{"rendered":"\n\n\n\n\n
\"Previous<\/a><\/td>\nPrevious Tutorial<\/strong><\/a><\/td>\nTutorial 12<\/span><\/strong><\/span><\/td>\nNext Tutorial<\/strong><\/a><\/td>\n\"Next<\/a><\/td>\n<\/tr>\n
<\/td>\nUltrasonic Sensor HC-SR04 With PIC Microcontrollers<\/strong><\/span><\/td>\n<\/td>\n<\/tr>\n
<\/td>\nIntroductory Level\u00a0\u2605\u2606\u2606\u2606\u2606<\/strong><\/span><\/td>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n

 <\/p>\n

in this tutorial, you’ll learn how HC-SR04 ultrasonic sensors work and how to interface them with pic microcontrollers in MPLAB IDE XC8 compiler. we’ll also discuss what are their applications and how to use this sort of sensor with microchip pic microcontrollers. We’ll be developing the necessary firmware to interface the ultrasonic sensor and display the readings on a breadboard. It’s going to be an interesting tutorial, so let’s get started!<\/span><\/p>\n

[toc]<\/p>\n


\n

\u00a0 \u00a0Components Needed For This Tutorial\u00a0 \u00a0<\/span><\/strong><\/span><\/h3>\n

 <\/p>\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Quantity<\/span><\/strong><\/span><\/td>\nComponent Name<\/span><\/strong><\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\nPIC16F877A<\/span><\/td>\n<\/tr>\n
2<\/span><\/td>\nBreadboard<\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\nJumper Wires Pack<\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\nHC-SR04 Ultrasonic Sensor<\/span><\/td>\n<\/tr>\n
4<\/span><\/td>\nLEDs<\/span><\/td>\n<\/tr>\n
4<\/span><\/td>\n330\u03a9 Resistors<\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\n4MHz Crystal OSCillator<\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\nLM7805 Voltage Regulator<\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\n9v Battery or any Power Supply Source<\/span><\/td>\n<\/tr>\n
1<\/span><\/td>\nPICkit3 (PIC Programmer)<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n

 <\/p>\n


\n

\u00a0 \u00a0What Is An Ultrasonic Sensor?\u00a0 \u00a0<\/span><\/strong><\/span><\/h3>\n

 <\/p>\n

An ultrasonic sensor is an electronic device that is typically used for distance measurement and\/or object detection. This sort of sensors is very common in the makers’ community as well as industrial applications. Ultrasonic sensors are usually used for embedded systems projects\/applications. That’s why we’ll learn how to interface this sensor in our series of tutorials. They are pretty cheap and easy to get sensors and could be interfaced with minimal electronic circuitry setup & as little of coding as operating a timer module.<\/span><\/p>\n

\"Ultrasonic-Sensor\"<\/p>\n

\u00a0 Features of The HC-SR04 Sensor\u00a0\u00a0<\/span><\/h4>\n\n\n\n\n\n\n\n\n\n\n\n\n
Operating Voltage<\/span><\/td>\n+5v DC<\/span><\/td>\n<\/tr>\n
Operating Current<\/span><\/td>\n15mA<\/span><\/td>\n<\/tr>\n
Operating Sound Frequency<\/span><\/td>\n40kHz<\/span><\/td>\n<\/tr>\n
Measuring Angle Range (Sight Of Vision)<\/span><\/td>\n< 15\u00b0<\/span><\/td>\n<\/tr>\n
Effective Measuring Field (Angle)<\/span><\/td>\n30\u00b0<\/span><\/td>\n<\/tr>\n
Measurement Resolution (Accuracy)<\/span><\/td>\nUp To 3mm<\/span><\/td>\n<\/tr>\n
Measurements Range (Theoretically)<\/span><\/td>\n2cm To 400cm<\/span><\/td>\n<\/tr>\n
Measurements Range (Practically)<\/span><\/td>\n2cm To 120cm<\/span><\/td>\n<\/tr>\n
Trigger Input Pulse-Width<\/span><\/td>\n10\u00b5s<\/span><\/td>\n<\/tr>\n
Dimensions Of The Module<\/span><\/td>\n45mm x 20mm x 15mm<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n

\u00a0 Ultrasonic Sensor HC-SR04 Pinout\u00a0\u00a0<\/span><\/h4>\n\n\n\n\n\n\n\n
Pin<\/strong><\/td>\nPin Name<\/strong><\/td>\nFunctionality<\/strong><\/td>\n<\/tr>\n
1<\/span><\/td>\nVcc<\/span><\/td>\n+5v DC Power Supply Input Pin<\/span><\/td>\n<\/tr>\n
2<\/span><\/td>\nTrigger<\/span><\/td>\nInput Trigger Pulse That Starts The Sensor’s Operation<\/span><\/td>\n<\/tr>\n
3<\/span><\/td>\nEcho<\/span><\/td>\nOutput Pin which is connected to an input pin on the MCU to read the sensor’s measurements output.<\/span><\/td>\n<\/tr>\n
4<\/span><\/td>\nGround<\/span><\/td>\n0v (Ground) Power Supply Input Pin<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n

The module board of the sensor itself has some sort of digital control circuitry that’s why there are 2 power pins (Vcc<\/sub> & Vss<\/sub>) in order to power it up. There are also a couple of pins (Trigger & Echo) which are used for operating the sensor.<\/span><\/p>\n

Knowing how this sensor actually works not only will help you use it for the right applications. It’ll also help you to identify when it fails or when it’s a better idea to search for another sensor that would be a better fit for the target application. So let’s see how it works?<\/span><\/p>\n

 <\/p>\n


\n

\u00a0 \u00a0How Does An Ultrasonic Sensor Work?\u00a0 \u00a0<\/span><\/strong><\/span><\/h3>\n

 <\/p>\n

As the name suggests, the ultrasonic sensor’s operation is mainly dependent on ultra-sound waves. This is typically the way that Bats<\/strong> are using for vision and navigating around. They send some sound waves in the air, which will reflect back to them to tell how close an object is to the source of the sound wave. You should also know that the ultrasound waves are not detected by the human ears which hear low-frequency tones up to 20kHz.<\/span><\/p>\n

\"Ultrasonic-Sensor\"<\/p>\n

Our sensor works in a similar fashion. It sends out ultrasonic sound waves then receives it back,\u00a0 then calculates the time it took the sound to travel from the source to the target. Which will obviously tell how far the target is from the sensor. That’s easily calculated due to the fact that sound travels in air at a constant speed.<\/span><\/p>\n

Let’s formulate the whole process more technically!<\/span><\/p>\n

First, we activate the trigger pin of the ultrasonic sensor by giving it a short pulse (10\u00b5S). Consequently, the sensor will send out an ultra-sound wave that will travel along in the air until it hits something. If the sound wave has hit something it’ll reflect back to the sensor. Which will identify how long it took the sound wave to travel back and forth. Actually, this is the information that we’re willing to read from the sensor! We need to know how long it took the sound wave to go back and forth (between the sensor & the target).<\/span><\/p>\n

The sensor sends out a pulse on the echo pin. In fact, this pulse captures the information that we’re looking for. As the width of the echo pulse is identical to the time of sound trip!\u00a0<\/span><\/p>\n

\"ultrasonic-sensor-operation\"<\/p>\n

Yes, as you might be thinking. The ultrasonic sensor sends an ultrasound wave and calculates how long it takes that wave to hit a target and get back to the source. Then the sensor will output an echo pules that has a similar time duration for us to read. After calculating this pulse’s width, we can easily find out what is the distance between the sensor and the target using the following formula.<\/span><\/p>\n

\"ultrasonic-sensor-eq1\"<\/p>\n

Note that, the EchoTime<\/sub> is the time it took the sound wave to travel back and forth between the sensor and the object that’s why we’re dividing it by 2 to get only the straightforward trip time. Sound waves travel in the air at a constant speed of 340m\/s, so it’s an easy process to find out the distance measurement.<\/span><\/p>\n

 <\/p>\n


\n

\u00a0How To Interface An Ultrasonic Sensor With A \u00b5C?\u00a0<\/span><\/strong><\/span><\/h3>\n

 <\/p>\n

Technically speaking, all we need is a couple of IO pins and a hardware Timer module<\/span><\/p>\n

\"ultrasonic-sensor-interfacing\"<\/p>\n

The first io pin should be configured as an output pin which will hook to the trigger pin of the ultrasonic sensor. A typical trigger signal is achieved by driving the trigger pin to high for a period of 2\u00b5S, Then drive it back to low.<\/span><\/p>\n

The second io pin should be configured as an input pin which will be hooked to the echo output pin of the ultrasonic sensor. Now, it’s the time to measure the width of the echo pules coming from the sensor. We’ll wait for the echo pin until it’s driven high by the sensor, then we’ll start the Timer module (e.g. Timer1) by setting the TMR1ON bit. Then, we’ll wait until the echo pin is driven back to low. When it returns to the low state, this indicates the termination of the pulse. And we should stop the timer module by clearing the TMR1ON bit.<\/span><\/p>\n

\"Ultrasonic<\/p>\n

Now, the time period which we’re interested in is simply existing in the TMR1 register. The value stored in the 16-Bit TMR1 register can now tell us exactly how long did it take the sound wave to travel back and forth between the sensor and the target object. You can find out the Time (T<\/strong>) using the equation (T<\/strong> = number_of_ticks x time of each tick), formulated as shown below<\/span><\/p>\n

\"Ultrasonic-Sensor-eq2\"You should have noticed that we’re not interested in the full-time period of the sound trip back and forth. We’re actually interested in only half of it in order to find the distance between the sensor and the target. That’s why we should divide T<\/strong> by 2 afterward.<\/span><\/p>\n

Now, we’ve got the time of the sound trip (more accurately, the forward half-time) & the speed of sound propagation in the air which is a constant of (340m\/s). So it’s very easy to find out the distance using the following formula<\/span><\/p>\n

\"Ultrasonic-Sensor-Eq1\"<\/p>\n

After simple manipulations, conversion, and by relating the timer output T to the time in the last formula. We can finally get an equation that maps TMR1 value to distance (in cm). It’ll turn out to be as follows<\/span><\/p>\n

\"Ultrasonic-Sensor-eq4\"<\/p>\n

And that is the equation we’ll be using in writing the firmware code for the ultrasonic sensor. You can also double check and verify this equation on your own to make sure everything is OK.<\/span><\/p>\n

 <\/p>\n


\n

\u00a0Implementing An Ultrasonic Driver Procedure\u00a0<\/span><\/strong><\/span><\/h3>\n

 <\/p>\n

Here we’ll start implementing the firmware drive (C-Code) for the ultrasonic sensor step-by-step. So let’s get started!<\/span><\/p>\n

\u00a0 Step1 – Configure The IO Pins\u00a0\u00a0<\/span><\/h4>\n

As we’ve stated earlier in the previous section, we should configure a couple of io pins for both triggering the sensor (output pin) and reading the output pulse (input pin). let’s use RC2 and RC3 pins.<\/span><\/p>\n

#define trigger RC2\r\n#define echo    RC3\r\n<\/pre>\n

And in the main function, we’ll set them to be output and input respectively<\/span><\/p>\n

void main()\r\n{\r\n  \/\/\u00a0 Configure The IO Pins\r\n  TRISB1 = 0;\r\n  TRISB2 = 1;\r\n  ...\r\n  while(1)\r\n  {\r\n    ...\r\n  }\r\n}<\/pre>\n

\u00a0 Step2 – Configure The Timer Module\u00a0\u00a0<\/span><\/h4>\n

The Next step is obviously to configure the Timer1 module in order to operate in timer mode. We’ve done this many times in the previous tutorials, so let’s copy&paste that code snippet as is.<\/span><\/p>\n

\n
\/\/ -- [[ Configure Timer1 To Operate In Timer Mode\u00a0 ]] --\r\n\r\n\/\/ Clear The Timer1 Register. To start counting from 0\r\nTMR1 = 0;\r\n\/\/ Choose the local clock source (timer mode)\r\nTMR1CS = 0;\r\n\/\/ Choose the desired prescaler ratio (1:1)\r\nT1CKPS0 = 0;\r\nT1CKPS1 = 0;<\/pre>\n

Note that we shouldn’t start the timer module operation right now, so it should be OFF.<\/span><\/p>\n<\/div>\n

\u00a0 Step3 – Write the Distance Calculation Procedure\u00a0\u00a0<\/span><\/h4>\n

The best way to go about implementing the distance calculation procedure is to create a dedicated function that handles everything and returns back the measured distance value! The declaration for this function should precede the main function. It’ll be something like this<\/span><\/p>\n

int calc_distance(void);<\/pre>\n

A function called calc_distance<\/strong> that takes no inputs but it handles the ultrasonic sensor interfacing procedure and returns back an integer value which represents the measured distance. You should notice that the distance value will always have a fraction part. But for sake of simplicity, we’ll discard that part of the output value by writing it to an integer.<\/span><\/p>\n

The definition for this function could be placed either before or after the main function. From my experience, it’s a better practice to keep drivers in a completely separate header. But for this tutorial, we’ll place it right after the main function. The definition for this procedure should be as follows<\/span><\/p>\n

\/\/ Definition Of The calc_dist() Function\r\nint calc_dist(void)\r\n{\r\n  int distance=0;\r\n  TMR1=0;\r\n  \/\/ Send Trigger Pulse To The Sensor\r\n  trigger=1;\r\n  __delay_us(10);\r\n  trigger=0;\r\n  \/\/ Wait For The Echo Pulse From The Sensor\r\n  while(!echo);\r\n  \/\/ Turn ON Timer Module\r\n  TMR1ON=1;\r\n  \/\/ Wait Until The Pulse Ends\r\n  while(echo);\r\n  \/\/ Turn OFF The Timer\r\n  TMR1ON=0;\r\n  \/\/ Calculate The Distance Using The Equation\r\n  distance=TMR1\/58.82;\r\n  return distance;\r\n}<\/pre>\n

\u00a0Summary For Interfacing The HC-SR04 Sensor\u00a0<\/span><\/h4>\n

As you might have noticed, the procedure is typically some consecutive easy steps as listed down below<\/span><\/p>\n

    \n
  1. Send a trigger signal<\/span><\/li>\n
  2. Wait for the echo to come from the sensor<\/span><\/li>\n
  3. When the echo signal arrives, start the timer module<\/span><\/li>\n
  4. When the echo signal is driven back to low, then stop the timer<\/span><\/li>\n
  5. Convert the time reading to real-time period then to a distance in cm<\/span><\/li>\n
  6. Check the validity of the calculated distance and return it back to the caller<\/span><\/li>\n<\/ol>\n

    And that’s all about it!<\/span><\/p>\n\n\n\n\n\n
    Checkout this Ultrasonic + LCD project For Distance Measurement<\/span><\/strong><\/a>
    \n<\/span><\/strong><\/td>\n

    \n<\/span><\/strong>\"Ultrasonic<\/a><\/td>\n<\/tr>\n
    This is an updated ultrasonic sensor tutorial with a more advanced and reliable library with a handful of examples on STM32 microcontrollers.<\/span><\/strong><\/a>
    \n
    \n<\/span><\/strong>
    \n<\/span><\/strong><\/td>\n
    \"STM32<\/span><\/strong><\/a><\/td>\n<\/tr>\n
    <\/td>\n<\/td>\n<\/td>\n<\/td>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n
    \n

    \u00a0Ultrasonic Sensor HC-SR04 Interfacing – LAB\u00a0<\/span><\/strong><\/span><\/h3>\n

     <\/p>\n\n\n\n\n\n\n
    Lab Name<\/span><\/strong><\/span><\/td>\nUltrasonic Sensor HC-SR04 Interfacing<\/span><\/td>\n<\/tr>\n
    Lab Number<\/span><\/strong><\/span><\/td>\n9<\/span><\/td>\n<\/tr>\n
    Lab Level<\/span><\/strong><\/span><\/td>\nBeginner<\/span><\/td>\n<\/tr>\n
    Lab Objectives<\/span><\/strong><\/span><\/td>\nLearn how to use ultrasonic sensors with microcontrollers. How to read distance measurements with an ultrasonic HC-SR04 sensor module.<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n

    \u00a0 Disclaimer\u00a0\u00a0<\/strong><\/span><\/h4>\n

    In this LAB we’ll be using the same procedure which we’ve discussed earlier. Meaning that we’ll be discarding fraction parts. We’ll be getting discrete distance measurements (e.g. 5cm, 6cm, 7cm, and so on). The reason behind this is that we haven’t yet discussed serial communication protocols. So we can’t send floating-points values (e.g 5.32, 6.76 or 9.54 cm) to a computer to display on the screen. On the other hand, we haven’t yet developed LCD screen drivers. The display method we’ll be using in this LAB is just an LED bar! That’s why fractions can and will be neglected. An updated version of the firmware will be provided after some serial communication tutorials, So stay tuned!<\/span><\/p>\n

     <\/p>\n

    \u00a0 \u00a0 \u00a0 \u00a01. Coding\u00a0 \u00a0 \u00a0 \u00a0<\/strong><\/span><\/h4>\n

     <\/p>\n

    Open<\/strong> the MPLAB IDE and create a new project name it “Ultrasonic Sensor”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.<\/span><\/p>\n

    \"timer-preloading\"<\/a><\/p>\n

    Set<\/strong> the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.<\/span><\/p>\n

    \"timer-preloading\"<\/a><\/p>\n

    Now, open the main.c<\/strong> file and let’s start developing the firmware for our project.<\/span><\/p>\n

    Our first task is to configure the IO pins for echo & trigger functions. Then, we’ll define the _XTAL_FREQ identifier as we’ll be using the __delay_ms macro in our project. And also we should declare the calc_distance function which we’ve discussed earlier.<\/span><\/p>\n

    #define _XTAL_FREQ 4000000\r\n#define trigger RC2\r\n#define echo\u00a0   RC3\r\nint calc_distance(void); \/\/ Function Declaration<\/pre>\n

    In the main routine, we’ll configure the IO output pins and the Timer1 module to be ready for use when we call the calc_distance function. And we’ll also create a variable dist in which we’ll be storing the sensor’s readings.<\/span><\/p>\n

    void main(void) \r\n{\r\n  \/\/ Create Distance Variable\r\n  int dist=0;\r\n  \r\n  \/\/--[ Configure The IO Pins ]--\r\n  \/\/ Set PORTB To Be Output Port (All The 8 Pins)\r\n  TRISB = 0x00;\r\n  \/\/ Set PORTB To Be LOW For initial State\r\n  PORTB = 0x00;\r\n  \/\/ Set RC2 To Be Output Pin ( Trigger )\r\n  TRISC2 = 0;\r\n  RC2 = 0;\r\n  \/\/ Set RC3 To Be Input Pin ( Echo )\r\n  TRISC3 = 1;\r\n  \r\n  \/\/--[ Configure Timer Module To Operate in Timer Mode ]--\r\n  \/\/ Clear The Pre-Scaler Select Bits\r\n  T1CKPS0=0;\r\n  T1CKPS1=0;\r\n  \/\/ Choose The Local Clock As Clock Source\r\n  TMR1CS=0;\r\n  \r\n  \/\/ Write The System's Main Routine !\r\n  while(1) \r\n  {\r\n    dist = calc_dist()\/5;\r\n    if(dist==1)\r\n    {PORTB = 0x01; __delay_ms(50);}\r\n    if(dist==2)\r\n    {PORTB = 0x03; __delay_ms(50);}\r\n    if(dist==3)\r\n    {PORTB = 0x07; __delay_ms(50);}\r\n    if(dist==4)\r\n    {PORTB = 0x0F; __delay_ms(50);}\r\n    else\r\n    {PORTB = 0x00; __delay_ms(50);}\r\n  }\r\n  return;\r\n}<\/pre>\n

    The idea here is to turn ON an LED if the distance is larger than 5cm, and turn ON 2 LEDs if the distance exceeds 10cm and so on. Meaning that we’re turning ON an LED for each 5cm and turning them OFF one-by-one while the distance is dropping down by 5cm. That’s easily implemented by a switch or if-statements as shown in the code above.<\/span><\/p>\n

    The full code listing is provided in the attachments section at the end of this tutorial. Get everything done! Cross your fingers! Hit the compile button and we’re done!<\/span><\/p>\n

     <\/p>\n

    \u00a0 \u00a0 \u00a0 \u00a02. Prototyping\u00a0 \u00a0 \u00a0 \u00a0<\/strong><\/span><\/h4>\n

    Make sure to connect everything as supposed to and you can follow the schematic diagram for this LAB. And don’t forget to flash the code to your microcontroller chip.<\/span><\/p>\n

    \"Ultrasonic-Sensor-Schematic\"<\/p>\n

    Here is a video for the running project output in case you’re curious<\/span><\/p>\n\n\n\n\n
    \"Play<\/a><\/td>\n<\/tr>\n