Projetos
Velocímetro para hamsters
Os hamsters são animais conhecidos por seu habito de correr incessantemente em suas rodinhas, desse modo é normal se perguntar que velocidade eles alcançam, ou ainda, querer saber que distancia eles percorrem. Pensando nisso construímos um velocímetro e contador de voltas para rodinhas de hamsters. Curioso para saber como? Não se preocupe que contamos neste post.
Antes de mais nada vamos aos materiais usados, que são os seguintes:
-
Arduino Uno;
-
Display LCD 16×2;
-
Sensor infravermelho TCRT5000;
-
Resistores de 330Ω, 3,3kΩ e 10kΩ (1 de cada);
Montando o velocímetro
A ideia aqui é usar um sensor infravermelho TCRT5000 para encontrar o momento em que o hamster completa uma volta na sua rodinha, e com o tempo de cada volta, juntamente ao tamanho da rodinha calcularmos a velocidade e a distancia percorrida por ele, para em seguida exibir esses valores em um display LCD. Para isso, vamos montar o circuito como mostrado na figura abaixo.
Nessa figura temos que o display LCD esta ligado com os pinos D4 a D7 nos pinos de mesmo nome do Arduino (ou seja, nos pinos PD4 a PD7 no Atmega328p), além disso, os pinos E, R/W e RS estão conectados nos pinos A0, A1 e A2 (ou PC0, PC1 e PC2) respectivamente. Para a alimentação do display, assim como o TCRT5000, esta sendo utilizado os 5V fornecidos pelo próprio Arduino.
O funcionamento do TCRT5000 se da por meio de um fototransistor acoplado a um LED infravermelho, assim, quando um objeto é posto próximo desse sensor, a luz infravermelha é refletida para o fototransistor, que atuara como um circuito fechado. No nosso circuito, o emissor do fototransistor esta conectado ao terra (gnd), portanto quando ele atuar como um circuito fechado temos que a tensão no coletor do fototransistor e consequentemente pino D8 do Arduino (ou PB0 para o Atmega, pino onde o conector esta ligado) sera de 0V. Já quando não existir nenhum objeto próximo ao TCRT5000, o fototransistor funciona como um circuito aberto, e a tensão de seu coletor sera de 5V, ja que o mesmo esta ligado nessa tensão por meio de um resistor de 10kΩ.
Programando nosso velocímetro
Agora que já temos os materiais em mãos e montamos o nosso circuito, iremos programar o Arduino. O código completo usado nesse projeto, além da biblioteca usada para controlar o LCD estão presentes no nosso GitHub.
O que vamos fazer no código é usar o timer0 para nos fornecer uma medida de tempo para o calculo da velocidade de nosso velocímetro, para isso, precisamos que ele seja reiniciado a cada volta completada pelo hamster. Com esse fim vamos usar a interrupção por mudança de estado do pino PB0, assim, sempre que o microcontrolador receber um sinal do TCRT5000, ele sofrera uma interrupção, e nela ocorrera a contagem da quantidade de voltas dada pelo Hamster e a inicialização do timer, sendo que após duas interrupções suscetivas, ou seja, duas voltas completas, a velocidade é calculada. Entretanto, se a rodinha ficar inativa por muito tempo (mais que 10 segundos), usaremos a interrupção por estouro do timer para desliga-lo.
Para simplificar a escrita e a compreensão do nosso código, usamos 5 funções (além da main e das interrupções), que servem para ligar o LCD, configurar o pino PB0 como entrada habilitando as interrupções, configurar o timer0, realizar os cálculos necessários e criar um loop que mantem o circuito sempre em funcionamento. Cada função usada esta explicada abaixo.
Função “Liga_LCD()”
A primeira função que vamos discutir é a função “Liga_LCD()”, ela foi implementada como presente abaixo.
void Liga_LCD(void){
LCD_init();
LCD_clear();
LCD_move_cursor(0,1);
LCD_write("Hodometro para");
LCD_move_cursor(1,4);
LCD_write("Hamsters");
_delay_ms(2000);
LCD_clear();
}
Nela iniciamos o display usando “LCD_init()”, então limpamos o display com “LCD_clear()” e finalmente a mensagem “Hodometro para Hamsters” é exibida por dois segundos com as funções “LCD_write()”, “LCD_move_cursor()” e “_delay_ms()”.
A função LCD_init() envia um conjunto de instruções que configuram o display no modo de 4 bits com o cursor ligado. Enquanto isso a função LCD_clear() apaga tudo o que esta exibido no display e retorna o cursor para a primeira posição da primeira linha. Já a função LCD_move_cursor() posiciona o cursor na posição desejada no display, essas funções fazem parte da biblioteca LCD.h. Já a ultima função _delay_ms() pertence a biblioteca <util/delay.h> e pausa a execução do programa pelo tempo desejado.
Função “configura_contador()”
A próxima função configura PB0 como entrada no registrador DDRB, em seguida, o pull up é ativado, isso mantém o nível de tensão do pino PB0 em 5V, a menos que a entrada seja 0V, o que facilita a identificação de transições para baixo. Logo após, usamos os registradores PCICR e PCMSK0, para habilitar as interrupções por mudança de estado do pino PB0, assim, sempre que o pino PB0 muda de estado, ocorre uma interrupção. Essa função ficou como mostra o exemplo abaixo:
void configura_contador(void){
DDRB &= ~(1<<PB0);
PORTB |= (1<<PB0);
PCICR |= (1<<PCIE0);
PCMSK0 |= (1<<PCINT0);
}
A rotina da interrupção para a mudança de estado do pino PB0 em primeiro lugar realiza a leitura desse pino, e se este sofreu transição para nível alto, apenas um pequeno delay de 50ms é realizado, mas se a transição é para nível baixo, então o timer0 é reiniciado, a quantidade de voltas é incrementada, e o valor do tempo é salvo na variável “tempo”. Essa interrupção foi implementada como mostrado a seguir:
ISR(PCINT0_vect){
if(PINB & (1<<PB0)){
_delay_ms(50);
}
else{
voltas +=1;
voltas_total +=1;
tempo = i;
i = 0;
_delay_ms(50);
TCCR0B |= (1<<CS00);
TCNT0 = 0;
}
}
Função “configura_timer()”
Da mesma forma que a função configura contador, essa função configura uma interrupção, mas desta vez por estouro do timer0. Para isso, primeiro configura-se o timer0 no modo de operação normal e desconectado. Essa configuração foi selecionada, pois com ela é possível obter uma precisão de 0,16ms, que é o suficiente para a construção do velocímetro. Por fim a interrupção por estouro do timer é habilitada. A função que configura o timer esta presente abaixo.
void configura_timer(void){
TCCR0A = 0;
TCCR0B = 0;
TIMSK0 |= (1<<TOIE0);
}
Com essa configuração temos 62500 interrupções por estouro por segundo, sendo que a cada interrupção a variável “i” é acrescida em 1 e quando ocorre uma interrupção por mudança de estado do pino PB0, o valor de “i” é salvo em “tempo” e “i” é reiniciada com zero. Entretanto, se não ocorre nenhuma mudança de estado em PB0 dentro de 10 segundos, então i>624999 e quando isso ocorre, a interrupção desconecta o timer e reinicia as variáveis “voltas” e “i”. Essa interrupção está abaixo.
ISR(TIMER0_OVF_vect){
i++;
if (i>624999){
i=0;
voltas = 0;
TCNT0 = 0;
TCCR0B &= ~(1<<CS00);
}
}
Ao se desconectar o timer o Arduino fica aguardando uma interrupção por mudança de estado do PB0 para reiniciar o timer. Além disso o velocímetro é zerado.
Função “calcula_velocidade()”
O código desta função está abaixo:
void calcula_velocidade(float tempo, float raio){
if (voltas > 1){
tempo = tempo/(62500);
distancia = (voltas_total-1)*2*3.1416*raio;
velocidade = 3.6*2*3.1416*raio/tempo;
}
else {
velocidade = 0;
}
}
Esta função é a responsável pelo calculo da velocidade do hamster em km/h. Para isso, primeiro é verificado se houveram 2 incrementos na variável “voltas”, uma vez que na primeira vez que o TCRT5000 é ativado, o timer está zerado. Se já houveram 2 incrementos em voltas, então o tempo em segundos é calculado usando:
(1)
Com o tempo em segundos calculamos a velocidade com a equação abaixo.
(2)
Nessa equação temos que é o comprimento da circunferência da rodinha do HHamster, ou seja, a distancia que ele percorre em uma volta completa. Assim a velocidade será obtida dividindo este valor pelo tempo. O fator 3.6 é usado para converter a velocidade (encontrada em metros por segundo) para quilômetros por hora.
Além disso, para calcular a distancia percorrida pelo Hamster basta multiplicar a circunferência de sua rodinha pelo numero de voltas dada, como abaixo.
(3)
Função “loop()”
Por fim temos a função loop(), nossa ultima função, que ficará sempre em execução, sendo implementada como abaixo:
void loop(void){
char str_distancia[20];
char str_velocidade[20];
int vel_int;
int vel_dec;
int distancia_int;
int distancia_dec;
while(1){
calcula_velocidade(tempo, raio);
distancia_int = floor(distancia);
distancia_dec = 100*(distancia-distancia_int);
sprintf(str_distancia, "Dis: %d,%d[m] ", distancia_int, distancia_dec);
vel_int = floor(velocidade);
vel_dec = 100*velocidade - 100*vel_int;
sprintf(str_velocidade, "Vel: %d,%d[km/h] ", vel_int, vel_dec);
LCD_move_cursor(0,0);
LCD_write(str_distancia);
LCD_move_cursor(1,0);
LCD_write(str_velocidade);
voltas_cont=voltas;
}
}
}
Nessa função, primeiro temos a declaração das variáveis a serem utilizadas sendo duas strings e quatro variáveis int. Em seguida, temos um loop infinito (while(1)), nele utiliza-se a função calcula_velocidade() para se calcular a velocidade e a distancia total percorridas pelo Hamster. Em seguida, estes valores são gravados em números inteiros, primeiro a parte inteira, depois as duas primeiras casas depois da virgula. Isso porque a função sprintf, usada para transformar números em strings, não funciona com variáveis do tipo float. Finalmente esses valores são exibidos no display do nosso velocímetro.
Função “main()”
Por fim, temos a função main do nosso programa, que ficou como a seguir:
void main(void){
SREG |= (1<<7);
voltas = 1;
Liga_LCD();
configura_contador();
configura_timer();
loop();
}
Na função main, apenas habilita-se as interrupções globais e chama-se as funções Liga_LCD(), configura_contador(), configura_timer() e loop().
Testando
Para testar o nosso projeto contamos com a ajuda do Antônio, o nosso hamster atleta, e ao final de uma noite ele correu por 3200 metros. No link abaixo você encontra o nosso projeto funcionando.
https://youtube.com/shorts/fL2wfnrB3ng?feature=share
E então, o que vocês acharam deste projeto? Conte pra gente nos comentários.