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.
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)
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:
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.
#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"); } } }
Por coincidência, também andei brincando com este sensor (no meu caso com um Arduino). O relato está em http://dqsoft.blogspot.com.br/search?q=hc-sr04
Que legal Daniel!
Muito legais as informações no seu artigo!
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
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