Olá pessoal!
Após a correria de lançamento do meu último livro, volto a postar um artigo técnico aproveitando um dos exemplos do livro. Neste artigo mostro como utilizar um sensor ultrassônico HC-SR04 para efetuar a medição de distâncias (até cerca de quatro metros) de forma simples e barata.
O sensor propriamente dito consiste numa pequena placa de circuito impresso contendo dois transdutores de ultrassom (um transmissor e um receptor), além de circuitos para geração e recepção do sinal de US. A figura abaixo mostra o sensor e a pinagem do mesmo.
Este sensor pode ser adquirido na DealExtreme, eBay, WayEngineer, Goodluckbuy, etc.
A utilização do mesmo é bastante simples: alimenta-se o mesmo (pinos VCC e GND) com uma tensão de 5V e, a cada pulso no pino de disparo (Trig) o sensor dispara um trem de 5 pulsos ultrassônicos. A largura do sinal de disparo deve ser de no mínimo 10µs. Ao receber o eco do sinal, o sensor gera no seu pino Echo um pulso com largura proporcional ao tempo decorrido entre o envio dos pulsos e a recepção do eco.
O cálculo da distância pode ser facilmente realizado através da seguinte fórmula:
Assim, se o pulso tiver uma largura de 1000µs, o alvo estará a 0,17m do sensor. Para obter a distância em cm:
Note que, para o cálculo, o pulso deverá sempre ser medido em µs. A seguir apresento a listagem do exemplo completo. O pino TRIG do módulo HC-SR04 deve ser conectado ao pino P4.1 do RL78 e o pino ECHO deve ser conectado ao pino P4.2 (entrada TI04) do RL78 (foi utilizada a placa do Starter Kit do RL78/G13).
#include "ior5f100le.h"
#include "ior5f100le_ext.h"
#include "intrinsics.h"
#include "myRL78.h"
#include "lcd_8x2.c"
// Configura watchdog
#pragma location = "OPTBYTE"
__root __far const char opbyte0 = WDT_OFF;
// Configura detector de baixa tensão
#pragma location = "OPTBYTE"
__root __far const char opbyte1 = LVD_OFF;
// oscilador 32MHz flash high speed
#pragma location = "OPTBYTE"
__root __far const char opbyte2 = FLASH_HS | CLK_32MHZ;
// debug ativado, com apagamento em caso de falha de autenticação
#pragma location = "OPTBYTE"
__root __far const char opbyte3 = DEBUG_ON_ERASE;
/* Configura security ID */
#pragma location = "SECUID"
__root __far const char senha[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 trata_TAU0_canal0(void)
{
if (bits.trig_mode)
{
TRIGGER = 1;
TDR00 = 9; // intervalo de 10us para o disparo
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; // salva o valor capturado
bits.echo_received = 1; // sinaliza que recebeu um pulso de eco
bits.aux = !bits.aux;
if (bits.aux) bits.display_update = 1; // atualiza o display
}
/*
Esta função escreve um valor inteiro no LCD. Ela utiliza uma formatação
especial para representar um valor fracionário através de inteiros.
Os dígitos de dezenas de milhares, milhares e centenas são impressos,
seguidos do ponto decimal e dos dígitos de dezenas e unidades.
Assim, o valor 1001 é apresentado como 10.01.
*/
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; // habilita a TAU0
TPS0 = TAU_CK0_DIV32; // CK0=1MHz, CK1=32MHz, CK2=16MHz e CK3=125kHz
// configura o canal 0 da TAU0 no modo temporizador
TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_ONECOUNT;
TDR00 = 9; // intervalo inicial de 10us
// configura o canal 4 da TAU0 no modo de captura de ciclo ativo
TMR04 = TAU_CK0|TAU_EDGE_RISE_FALL|TAU_TRIG_BOTH_EDGE|TAU_MD_CAPTURE_LEVEL;
TS0L = TAU_CH4 | TAU_CH0; // Arma os canais 0 e 4
TMMK00 = 0; // habilita a interrupção do canal 0 da TAU0
TMMK04 = 0; // habilita a interrupção do canal 4 da TAU0
}
void SYS_init(void)
{
PM4_bit.no1 = 0; // P41 como saída (TRIGGER)
TAU_init(); // inicializa a TAU0
LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED);
LCD_write_char('\f'); // apaga o display
__enable_interrupt(); // habilita as interrupções do RL78
}
void main(void)
{
SYS_init();
LCD_pos_xy(0,0); // cursor na coluna 0 da linha 0
LCD_write_string("Distanc");
TRIGGER = 1; // inicia um pulso de disparo para o módulo de ultrassom
bits.trig_mode = 0;
TS0L = TAU_CH0; // Dispara o canal 0
while(1)
{
if (bits.display_update)
{
bits.display_update = 0; // apaga o bit de atualização
LCD_pos_xy(0,1); // cursor na coluna 0 da linha 1
// calcula a distância em cm
distance = ((long)interval*100)/58;
if (distance<=40000) // se a distância for <= 400cm
{
LCD_write_frac_int(distance);
LCD_write_string("cm ");
} else LCD_write_string("---.--cm");
}
}
}




