Overview
HC-SR04 is an ultrasonic range finder. It uses sound wave traveling to find detected object distance. Its working range is between 4cm and 4m. To control and get distance data from this sensor we can use a digital circuit, or a microprocessor, or even manually by hand. Its echo output is a logic high level TTL signal with a specific period. A microprocessor's timer is used for calculating the timing signal associated with distance. For more details about using this sensor with a simple PIC16F84A micro-controller you can see this post.
PIC16F887 Prototyping Board |
PIC16F887 Prototyping Board |
HC-SR04 Module Front |
HC-SR04 Module Back |
MPLABX IDE and XC8 C Programming
In this XC8 programming example, I use a PIC16F887 8-bit micro-controller to read distance data, and displaying its timing value with calculated distance on a 16x4 character LCD. I use Timer0 timer/counter to measure the sensor's TTL high pulse period.
Schematic and Program Simulation |
An 8MHz internal RC oscillator is used for the system. Timer0 prescaler is set to 1:2 to get a 1µs timing ticks. Since this timer module is an 8-bit timer/counter I use TIMER0 interrupt to expand its timing period. Hence it becomes a 16-bit timer with the aid of timing interrupt.
An 8-bit micro-controller is easy to program using C in MPLABX IDE and XC8 embedded C compiler from Microchip Technology. An HD44780 character LCD is very simple to interface and program. This character LCD is common operate in 4-bit data transfer mode.
/* * File: main.c * Author: Admin * * Created on December 28, 2023, 9:51 PM */ #include <xc.h> #include "config.h" #include "lcd.h" #include <stdio.h> #define _XTAL_FREQ 8000000UL #define TRIGGER RD6 #define ECHO RD7 volatile uint8_t T0OV=0; volatile uint16_t myCounter=0; volatile uint16_t getDistance=0, temp=0; void __interrupt() T0_ISR(){ if(T0IF==1){ T0OV+=1; myCounter++; T0IF=0; } } void readDistance(void){ char msg[8]; TRIGGER=1; __delay_us(10); TRIGGER=0; __delay_us(30); while(ECHO==0){ /*Waiting For High Pulse Response, Or Sensor Present*/ temp++; __delay_us(10); if(temp>=20) break; } TMR0=0; T0OV=0; while(ECHO==1); temp=(T0OV<<8)+TMR0+14; getDistance=temp/58; lcdXY(5,4); sprintf(msg,"%4d %cS ",temp,228); lcdString(msg); lcdXY(5,2); if(temp>=116&&getDistance<=400){ sprintf(msg,"%3d",getDistance); lcdString(msg); temp%=58; temp=(temp*100)/58; sprintf(msg,".%d%dcm",temp/10,temp%10); lcdString(msg); }else lcdString("Invalid"); temp=0; T0OV=0; TMR0=0; } void main(void) { /*8MHz internal oscillator*/ OSCCONbits.IRCF=7; lcdInit(); /*RD7 as input*/ PORTD=0; TRISD=0x80; /*Select system clock*/ T0CS=0; /*Timer0 Prescaler*/ PSA=0; /*Select 1:2 Prescaler*/ OPTION_REGbits.PS=0; /*Enable Timer0 Interrupt*/ T0IE=1; GIE=1; T0IF=0; lcdXY(5,1); lcdString("PIC16F887 "); lcdXY(1,2); lcdString("HC-SR04 Distance"); lcdXY(2,3); lcdString("Sensor Example"); lcdXY(2,4); lcdString("MPLABX IDE XC8"); __delay_ms(2000); lcdCommand(0x0C); lcdCommand(0x01); __delay_ms(5); lcdXY(5,1); lcdString("Distance: "); lcdXY(1,3); lcdString("TIMER0 Duration:"); TMR0=0; while(1){ if(myCounter>=5000){ readDistance(); myCounter=0; } } return; }
The Interrupt Service Routine (ISR) for PIC micro-controller in XC8 programming is differ depends on the version of the compiler. Some time the source codes can generate error in other version. In some case, it can be build but the ISR does not work during run-time. So we will need to read its compiler user manual.
MPLABX IDE Dashboard |
Click here to download its source file.