Thursday, September 1, 2016

Interfacing PIC18F4550 Microcontroller with HC-SR04 Ultrasonic Sensor


Distance measurement using PIC18F4550 microcontroller and HC-SR04 ultrasonic sensor
The distance to an obstacle can be measured with the low cost ultrasonic sensor HC-SR04 (HC-SR05). The HC-SR04 sensor can measure distances form 2 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 for distance measurement 
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. You 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 * velocity (340M/S) / 2.
HC-SR04 Ultrasonic sensor for distance measurement timing
Interfacing PIC18F4550 with HC-SR04 ultrasonic sensor circuit:
Project circuit schematic is shown below.
Interfacing PIC18F4550 with HC-SR04 ultrasonic sensor circuit
The microcontroller runs with its internal oscillator at 8MHz.
HC-SR04 Ultrasonic sensor Trigger pin is connected to RB0 pin and  the Echo pin is connected to RB1 pin.
Interfacing PIC18F4550 with HC-SR04 ultrasonic sensor CCS C code:
Here are some hints about the C code.
The sensor needs at least 10µs pulse at Trigger pin which is done as follows (Trigger pin is connected to RB0 pin:
output_high(PIN_B0);
delay_us(10);
output_low(PIN_B0);

After sending the trigger pulse we have to wait until the module raises its Echo output pin where the Echo pin is connected to pin RB1. If the waiting time is too long that means there is a problem and the code returns error. Timer1 module is used to count elapsed time which is configured to increment by 1 every 1µs (8MHz mcu frequency used).
If you choose to run your microcontroller with different frequency you have to change Timer1 configuration, otherwise you will get a wrong results.
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_2);
Waiting HC-SR04 module to raise its Echo pin with timeout property code where variable check is used as a return variable (if there is a timeout problem check = 1).
The timeout property is used to prevent the microcontroller from hanging.
while(!input(PIN_B1) && (get_timer1() < 1000));
if(get_timer1() > 990)
  check = 1;

If there is no problem the module raises its Echo pin for a certain time, this time is proportional to distance from the sensor the the obstacle. Timer1 is used to count this time as follows:
while(input(PIN_B1) && (i < 25000))
  i = get_timer1();
if(i > 24990)
  check = 2;

If there is an out of range the code returns error by making the variable check = 2.
For the variable check:
If check = 0: There is no problem
If check = 1: There is a timeout error
If check = 2: There is an out of range error.
Project full code is as below:
// Interfacing PIC18F4550 with HC-SR04 usltrasonic sensor CCS C code
// 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 <18F4550.h>
#fuses NOMCLR INTRC_IO
#use delay(clock = 8000000)
#include <lcd.c>
#use fast_io(B)

int8 check;
unsigned int16 i, distance;
void main(){
  setup_oscillator(OSC_8MHZ);                      // Set internal oscillator to 8MHz
  setup_adc_ports(NO_ANALOGS);
  output_b(0);
  set_tris_b(2);                                   // Configure RB1 as input
  lcd_init();                                      // Initialize LCD module
  setup_timer_1 (T1_INTERNAL | T1_DIV_BY_2);       // Configure Timer1 module
  set_timer1(0);                                   // Reset Timer1
  lcd_putc('\f');                                  // LCD Clear
  lcd_gotoxy(4, 1);                                // Go to column 4 row 1
  lcd_putc("Distance:");
  while(TRUE){
    check = 0;
    i = 0;
    output_high(PIN_B0);
    delay_us(10);
    output_low(PIN_B0);
    set_timer1(0);                                 // Reset Timer1
    while(!input(PIN_B1) && (get_timer1() < 1000));
    if(get_timer1() > 990)
      check = 1;                                   // Timeout error
    set_timer1(0);                                 // Reset Timer1
    while(input(PIN_B1) && (i < 25000))
      i = get_timer1();                            // Store Timer1 value in i 
    if(i > 24990)                                  // Out of range error
      check = 2;
    if(check == 1){
      lcd_gotoxy(3, 2);                            // Go to column 3 row 2
      lcd_putc("  Time Out  ");
    }
    if(check == 2){
      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);
    }
    delay_ms(100);
  }
}

Interfacing PIC18F4550 with HC-SR04 ultrasonic sensor video:
The following video shows the project in prototype hardware circuit.