This topic shows how to make a simple distance meter using PIC16F887 microcontroller and HC-SR04 ultrasonic sensor.
The HC-SR04 ultrasonic sensor can measure distances form 2cm to 400cm with an accuracy of 3mm. This sensor module includes ultrasonic transmitter, ultrasonic receiver and control circuit.
The HC-SR04 ultrasonic sensor has 4 pins as shown below where:
VCC : Positive power supply (+5V)
Trig : Trigger input pin
Echo : Echo output pin
GND : Ground (0V)
HC-SR04 ultrasonic sensor timing diagram:
The timing diagram of the HC-SR04 ultrasonic sensor is shown below.
First we have to supply the sensor trigger pin with a pulse of 10µs and the sensor will automatically send 8 cycles burst of ultrasound at 40 kHz and raise its echo pin. The Echo is a distance object that is pulse width and the range in proportion. We can calculate the range through the time interval between sending trigger signal and receiving echo signal. Formula: uS / 58 = centimeters or uS / 148 =inch; or:
the range = high level time * sound velocity (340M/S) / 2.
- PIC16F887 microcontroller
- HC-SR04 ultrasonic sensor
- 16x2 LCD screen
- 10K variable resistor
- +5V source
- Breadboard
- Jumper Wires
In this project the PIC16F887 MCU runs with its internal oscillator and MCLR pin function is disabled.
Distance meter using PIC16F887 and HC-SR04 ultrasonic sensor C code:
The C code below was tested with CCS C compiler version 5.051.
The PIC16F887 runs with its internal oscillator @ 8MHz.
Basically I used Timer1 module to measure the pulse widths which comes from the Echo pin of the HC-SR04 sensor, the width of the pulse is related to the distance. Timer1 is configured to increment every 1us (prescaler = 2):
SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_2);
First of all the MCU sends a pulse of 10 us to the sensor via pin RB1 which is the trigger pin of the sensor, then the MCU waits until the sensor raises its Echo pin (function wait_sensor() ). If the waiting time is higher than 990 us ==> time out and the function wait_sensor() returns 0.
if the function wait_sensor() returned 1, the microcontroller starts measuring the width of the Echo pin pulse (in us) using the function get_distance(), if the time > 24990 (distance > 400 cm) ==> out of range, otherwise the measured time will be converted to distance (in cm) by dividing it by 58.
No interrupt is used in this example.
The complete C code is below.
/* Distance meter using HC-SR04 ultrasonic sensor and PIC16F887 CCS C code. Echo and trigger pins of the HC-SR04 are connected to RB0 and RB1 respectively. http://ccspicc.blogspot.com/ electronnote@gmail.com */ //LCD module connections #define LCD_RS_PIN PIN_D0 #define LCD_RW_PIN PIN_D1 #define LCD_ENABLE_PIN PIN_D2 #define LCD_DATA4 PIN_D3 #define LCD_DATA5 PIN_D4 #define LCD_DATA6 PIN_D5 #define LCD_DATA7 PIN_D6 //End LCD module connections #include <16F887.h> #fuses INTRC_IO, NOMCLR, NOBROWNOUT, NOLVP #use delay(clock = 8MHz) #use fast_io(B) #include <lcd.c> int16 i, distance; int1 wait_sensor(){ i = 0; set_timer1(0); // Reset Timer1 while(!input(PIN_B0) && (i < 1000)) i = get_timer1(); // Read Timer1 and store its value in i if(i > 990) return 0; else return 1; } int16 get_distance(){ i = 0; set_timer1(0); while(input(PIN_B0) && (i < 25000)) i = get_timer1(); return i; } void main(){ setup_oscillator(OSC_8MHZ); // Set internal oscillator to 8MHz output_b(0); set_tris_b(1); // Configure RB0 pin as input delay_ms(1000); lcd_init(); // Initialize LCD module lcd_putc('\f'); // Clear LCD lcd_gotoxy(4, 1); // Go to column 4 row 1 lcd_putc("Distance:"); SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_2); // Configure Timer 1 to increment by 1 every 1 us while(TRUE){ // Send 10us pulse to HC-SR04 Trigger pin output_high(PIN_B1); delay_us(10); output_low(PIN_B1); // Read pulse comes from HC-SR04 Echo pin if(wait_sensor()){ distance = get_distance(); if(distance > 24990){ lcd_gotoxy(3, 2); // Go to column 3 row 2 lcd_putc("Out Of Range"); } else { distance = i/58; // Calculate the distance lcd_gotoxy(3, 2); // Go to column 3 row 2 lcd_putc(" cm "); lcd_gotoxy(6, 2); // Go to column 6 row 2 printf(lcd_putc, "%3Lu", distance); } } else { lcd_gotoxy(3, 2); // Go to column 3 row 2 lcd_putc(" Time Out "); } delay_ms(100); } } // End of code