# Pic Lab, PIC16, Experiment #25: An ultrasonic sensor HC-SR04

The next step of my small project was an embedding of the ultrasonic sensor to it.

Let me try to make it work with pic16f628a.

As usual, starting from the datasheet reading.

There are 4 pins in the device: Vcc, Gnd, Trig and Echo. The first two are kind of obvious, lets focus on the two rest – the Trig is a control wire, while the Echo pin is a data wire with results.

That’s how it looks in the datasheet:

We initiate a 10us pulse on the Trig wire and waiting for a signal on the echo wire. Have to say that I was quite puzzled by two things: the picture above and the next lines from the datasheet:

You can calculate the range through the time interval between sending trigger signal and receiving echo signal.

The picture states that the pulse length is proportional to the distance, while this text says that time from the trigger to receive the echo signal. Two different statements from the same datasheet. The picture statement is appeared to be right, so make sure you are using a right way.

To get the distance in centimeters we need to:

Distance (cm) = pulse duration (us) / 58

Time to get some code strings:

if (!RB1)
{
__delay_ms(100);
if (!RB1)
{
RMeas = 0;
RMeas = 1;
__delay_us(10);
RMeas = 0;
}//if (!RB1) inner
}//if (!RB1)

RMeas – is a pin on which I hanged the Trig wire from the sensor. It is configured as an output. The code is quite simple – it just generates a short 10us pulse when button is pressed. I have not used the timer there, decided that a macros is good enough for me so far.

Building a test setup:

We have about 13 cm from the pcb to the “obstacle”, well we might add one more cm for the sensor by itself, lets try:

630/58 = 11 cm, i.e. the inaccuracy is about 1-1.5 cm, quite good enough for my application.

The algorithm of processing looks like should not be complicated:

• To detect the rising edge and launch the timer
• To detect the falling edge and check the timer value
• To convert the timer value to microseconds and making all necessary calculations

The function of gathering values looks like this:

void GetRange()
{
tempTmr1 = 0;
StRMeas = 0;                //Инициализируем модуль
RMeas = 0;
RMeas = 1;
__delay_us(10);
RMeas = 0;
StRMeas = 0;
__delay_us(100);
RBIE = 1; //Включаем прерывания по изменению состояния порта
RBlowFlag = 0; //Статусная переменная

while (!RBlowFlag)         //Цикл пока не закончится импульс от Echo
{
if (RBhighFlag)          //По возрастающему фронту
{
InitTimer1();         //Запускаем таймер1
RBhighFlag = 0;
}
}

TMR1ON = 0;
tempTmr1 = TMR1H;          //Сливаем значение таймера в локальную переменную
tempTmr1 <<= 8;
tempTmr1 |= TMR1L;

lcd_clear();               //и выводим инфу на дисплей
lcd_goto(0x00);

Range = tempTmr1/174 + 2; //Поправочный коэффициент - 2 см
lcd_puts("Range, cm");
display_digit(Range, 0x40);
}

And the interrupts handler:

The correction coefficient 2 is chosen in an experimental way to fine tune the results.

void interrupt isr()
{
if (RBIF)
{
if (!Recho)
{
RBlowFlag = 1;
RB5 = 0;
}
if (Recho)
{
RB5 = 1;
RBhighFlag = 1;
}
RBIF = 0;

}//if (RBIF)

} //isr()

The video demonstration is available 🙂