SN-HC-SR04 + PIC16F887


We had receive suggestion from user on how to integrate the SN-HC-SR04 sensor with PIC. In this section, we are using the SK40C with PIC16F887 to read the pulse width with proportion to distance and lastly display on LCD.

BTW, if you have further inquiry about this tutorial, please post it in our technical forum as we seldom check the comment section in tutorial site.

Hardware Required


SK40C                                                      PIC16F887


SN-HC-SR04 Ultrasonic Sensor

Software Required

  • XC8 Complier

Additional Information

According to the sensor datasheet, to start measurement, Trig of SR04 must receive a pulse of high (5V) for at least 10us, this will initiate the sensor will transmit out 8 cycle of ultrasonic burst at 40kHz and wait for the reflected ultrasonic burst. When the sensor detected ultrasonic from receiver, it will set the Echo pin to high (5V) and delay for a period (width) which proportion to distance. To obtain the distance, measure the width of Echo pin.


Time = Width of Echo pulse, in uS (micro second)
Distance in centimeters = Time / 58
Distance in inches = Time / 148
Or you can utilize the speed of sound, which is 340m/s


  1. Connect the SN-HC-SR04 VCC and GND to SK40C VDD and GND.
  2. Connect SN-HC-SR04 TRIG to RA0.
  3. Connect SN-HC-SR04 ECHO to RB0.
Untitled Sketch_bb

Code Overview

In this section, the SN-HC-SR04 pulse width from the  ECHO pin is read using the Timer 1 (1:4 Pre-scale) and the the also the PORTB0 Interrupt-On-Change.

1. Configure the Timer 1 to (1:4) pre-scale, Global Interrupt enable and PORTB0 Interrupt-On-Change enable.

[sourcecode language=”cpp” wraplines=”true”]
// Turn on Timer 1 with 4x prescale as counter
T1CON = 0b00100000;
// Turn on PORTC and Global interrupt
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.RBIE = 1;
INTCONbits.RBIF = 0;
// Configuration for Interrupt-On_Change for PORTB0
IOCBbits.IOCB0 = 1;

2.  Clear the Timer before the Timer is start. Then check whether the Echo pin is LOW (which mean no signal).  When there was no signal detected in the Echo pin, PIC will send another 10us LOW-to-HIGH pulse to Ultrasonic sensor.

[sourcecode language=”cpp” wraplines=”true”]
TMR1H = 0; // Clear Timer1
TMR1L = 0;
if(Echo == 0) // If no signal recieved from Ultrasonic</span>
Trig= 0;
Trig = 1;
__delay_us(10); // Send LOW-to-HIGH Pulse of 10us to Ultrasonic
Trig = 0;

3. When PIC detected the changes of signal in PORTB0, it will trigger interrupt and start the timer for Echo Pulse Width counting. Once the Echo is LOW, Timer will stop and combine both 8-bits Timer HIGH and 8-bits Timer LOW to 16-bits.

[sourcecode language=”cpp” wraplines=”true”]
T1CONbits.TMR1ON = 1; // ON Counter
while(Echo == 1);
T1CONbits.TMR1ON = 0;
TMR = (unsigned int)TMR1H << 8;
TMR = TMR + TMR1L; // Combine 2x counter byte into single integer

4.  Convert the Pulse Width into time (us) by using the simple calculation. FYI, We are using 20M OSC in this project.

[sourcecode language=”cpp” wraplines=”true”]
Duration(us) = TMR * Clock speed per instruction(Fosc/4) * timer pre-scale(1:4)
Duration(us) = TMR * 5M * 4
= TMR * 0.2 * 4
= TMR * 2/10  * 4
Duration(us) = (TMR/10) * 2 * 4
duration = (TMR/10) * 8; // Duration Formula = TMR * 0.2us(Clock speed) * 4 (Timer Prescale)
distance_cm = duration / 58 ; // Refer HC-SR04 Datasheet
distance_inc = duration / 148;

5. Compare the result and display the value if within the range which is 2cm to 400cm  or 1″ to 157″. If the result is out or range, LCD will display “***“.

[sourcecode language=”cpp” wraplines=”true”]
if(distance_cm < 400 && distance_inc < 157) // If Ultrasonic sense more than 400cm

6. Lastly, clear the interrupt of PORTB0.

[sourcecode language=”cpp” wraplines=”true”]
INTCONbits.RBIF = 0; // Clear PortB Interrupt Flag


SN-HC-SR04 with PIC16F887


15 thoughts on “SN-HC-SR04 + PIC16F887”

  1. Hi! Thanks for the simple tutorial!

    Besides, Can I use another port such as RB1 for the TRIG on the sensor? Actually I’m thinking of using RB1 for the TRIG but I found that RA0 have a ULPWU so I felt a little unsure.

  2. The angels in the league by gaining the spoils of power
    and the protection of your own warriors since you can increase the
    power of the attack, you must do your tasks in the game constantly.
    A poker tournament which is played online can be chosen from a
    wide spectrum of sites available out there looking for the
    attention of the potential players of poker. The Online
    Roulette doesn’t only provide overmuch fun but it is also termed as a pragmatic source of getting some extra
    income as well.

  3. Dear Sir/Madam,

    Beside PIC16F887 used in this guide, any other series of PIC Microcontroller can support without modifying the code?


  4. Dear Sir, you have mention that you compile the code using ‘MPLABX + XC8’. Can I use your code to compile in normal MPLAB with HI-TECH PIC C Compiler?


    How can I use flowcode to write a code for this, I mean; will I use separate an ADC for echo and another one for Trig?

Leave a Comment

Your email address will not be published.

Share this Tutorial

Share on facebook
Share on whatsapp
Share on email
Share on print
Share on twitter
Share on pinterest
Share on facebook
Share on whatsapp
Share on email
Share on print
Share on twitter
Share on pinterest

Latest Tutorial

Sound Level Detector using Maker UNO paired with ESP8266 Grove WiFi on Blynk
Send Meal Selection and Locations through Telegram Bot Using ESP8266 Grove WiFi Module on micro:bit
Real-Time Multitasking on Maker Pi Pico Using pyRTOS
Display Internet Time (NTP) on micro:bit
DIY Automated Vacuum Cleaner Using REKA:BIT With Micro:bit
Tutorials of Cytron Technologies Scroll to Top