Ultrasonic distance measurement with RL78 and HC-SR04 module

Hello folks! Today I would like to show you a simple project for ultrasonic distance measurement using the RL78 and a HC-SR04 ultrasonic ranging module.

The sensor module itself is a small PCB with two ultrasonic transducers (one for transmitting and one for receiving) along with some circuitry for signal generation and reception. The sensor module is pictured below.

HC-SR04 ultrasonic module

It can be easily purchased at any electronics store and online at DealExtreme, eBay, WayEngineer, Goodluckbuy, etc.

Its usage is fairly simple: all you have to do it is to supply its power supply pins (VCC and GND pins) with 5V and then trigger a measurement by applying a pulse (minimum period is 10µs) on Trig pin. The sensor will transmit 5 ultrasonic pulses and when the echo is received the ECHO pin outputs a pulse proportional to the time elapsed between the pulse trigger and the echo receiving.

One can easily calculate the distance between the sensor and the target by using the following equation (written in Portuguese, pulso_retorno = ECHO output pulse width)

distance_f1

Note that the equation considers a constant value for the sound speed. In real life applications that speed varies with temperature, so it is better account for it too.

So, if the measured pulse has a 1000µs width, the target is located about 0,17m far from the sensor. In order to get the distance in centimeters one could use the following equation:

distance_f2

Please note that, for calculation purposes, the measured pulse should always use 1µs time base! The code listing is shown below. The TRIG pin must be wired to RL78/G13’s P4.1 pin and ECHO must me wired to RL78/G13’s P4.2 pin (TI04 input). The application was tested on the RL78/G13 RSK board.

RL78 RSK with the ultrasonic module mounted

#include "ior5f100le.h"
#include "ior5f100le_ext.h"
#include "intrinsics.h"
#include "myRL78.h"
#include "lcd_8x2.c"

// Watchdog config
#pragma location = "OPTBYTE"
__root __far const char opbyte0 = WDT_OFF;
// Low voltage detector off
#pragma location = "OPTBYTE"
__root __far const char opbyte1 = LVD_OFF;
// Internal 32MHz oscillator selected
#pragma location = "OPTBYTE"
__root __far const char opbyte2 = FLASH_HS | CLK_32MHZ;
// Debug enabled, erase on passsword incorrect
#pragma location = "OPTBYTE"
__root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Configura security ID */
#pragma location = "SECUID"
__root __far const char password[10] = {0,0,0,0,0,0,0,0,0,0};

#define TRIGGER       P4_bit.no1

volatile unsigned int interval;
unsigned long distance;
volatile __saddr struct
{
  unsigned char display_update  : 1;
  unsigned char echo_received   : 1;
  unsigned char trig_mode       : 1;
  unsigned char aux             : 1;
} bits;

#pragma vector = INTTM00_vect
__interrupt void TAU0_channel0_ISR(void)
{
  if (bits.trig_mode)
  {
    TRIGGER = 1;
    TDR00 = 9; // 10us trigger pulse interval
    TS0L = TAU_CH0;
    bits.echo_received = 0; 
  } else
  {
    TRIGGER = 0;
    TDR00 = 0xFFFF;
    TS0L = TAU_CH0;
    if (!bits.echo_received) interval=0xFFFF;    
  }  
  bits.trig_mode = !bits.trig_mode;
}
#pragma vector = INTTM04_vect
__interrupt void trata_TAU0_canal4(void)
{
  interval = TDR04;         // stores the captured pulse width
  bits.echo_received = 1;   // flags echo received
  bits.aux = !bits.aux;
  if (bits.aux) bits.display_update = 1;  // update the display every two pulses
}

void LCD_write_frac_int(unsigned int data)
{
  unsigned char aux, space;
  unsigned int sub = 10000;
  aux = 0;
  space = 1;
  while (sub)
  {
    aux = 0;
    while (data>=sub)
    {
      data -= sub;
      aux++;
      space = 0;
    }
    if (!space) LCD_write_char(aux+'0');
    sub /= 10;
    if (sub==10)
    {
      if (space) LCD_write_char('0');
      LCD_write_char('.');
      space = 0;
    }
  }
  if (space) LCD_write_char('0');
}

void TAU_init(void)
{
  TAU0EN = 1;         // TAU0 enabled
  TPS0 = TAU_CK0_DIV32; // CK0=1MHz, CK1=32MHz, CK2=16MHz e CK3=125kHz
  // TAU0, channel 0 in timer mode
  TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_ONECOUNT;
  TDR00 = 9;          // initial interval = 9+1=10us
  // TAU0, channel 4 in high level pulse capture mode
  TMR04 = TAU_CK0|TAU_EDGE_RISE_FALL|TAU_TRIG_BOTH_EDGE|TAU_MD_CAPTURE_LEVEL;  
  TS0L = TAU_CH4 | TAU_CH0; // Starts channels 0 and 4
  TMMK00 = 0;         // TAU0 channel 0 interrupt enabled
  TMMK04 = 0;         // TAU0 channel 4 interrupt enabled
}

void SYS_init(void)
{
  PM4_bit.no1 = 0;        // P41 as output (TRIGGER)  
  TAU_init();             // TAU0 init
  LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED);
  LCD_write_char('\f');   // clears the display
  __enable_interrupt();   // interrupts enabled
}

void main(void)
{
  SYS_init();  
  LCD_pos_xy(0,0);              // cursor at line 0, column 0
  LCD_write_string("Distanc");
  TRIGGER = 1;	// triggers ultrasonic distance measurement
  bits.trig_mode = 0;           
  TS0L = TAU_CH0;               // fires TAU0 channel 0 
  while(1)
  {
    if (bits.display_update)
    {
      bits.display_update = 0;  // clears display update flag
      LCD_pos_xy(0,1);          // cursor at column 0, line 1
      // distance calculation (in cm)
      distance = ((long)interval*100)/58;
      if (distance<=40000)      // if the distance is less than or equal to 4m
      {
        LCD_write_frac_int(distance);
        LCD_write_string("cm   ");
      } else LCD_write_string("---.--cm");
    }
  }
}

4 thoughts on “Ultrasonic distance measurement with RL78 and HC-SR04 module

  1. Olá Fábio! Tudo bem?
    Estou começando a trabalhar com MSP430, e estou montando um medidor de distancias, usando um MSP430G2553, um LCD 16×2 e um sensor ultrassônico HC-SR04.

    Não tenho dificuldades em trabalhar com o display, mas estou encontrando algumas dificuldades com o sensor ultrassônico. Gostaria de saber se você tem exemplos com MSP430G2553 e HC-SR04 ou tutoriais com aplicações semelhantes.

    De antemão agradeço.

    Abraço,
    Vinícius

    1. Olá Vinicius,

      Desculpe a demora, infelizmente não tenho este programa portado para outras plataformas, mas não é difícil de fazer isso no MSP430, basta capturar o pulso com um canal do timer.

      Att.

      Fábio

Leave a Reply