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"); } } }