quinta-feira, fevereiro 05, 2015

LEDs na Roda da Bicicleta

Estou revendo um dos meu projetos antigos (Spoke-o-dometer). O objetivo agora é mais modesto: mostrar imagens simples na roda de uma bicicleta aproveitando a persistência da visão.



Hardware

O hardware continua sendo composto por um sensor de Efeito Hall, LEDs e um microcontrolador. A grande alteração no circuito é a troca do MSP430 por um ATtiny44. O principal motivo é ter as ferramentas (compilador e gravador) mais disponíveis.

O modelo do sensor é o A1120 (que vimos aqui). Além de permitir trabalhar com 3V (no caso com uma bateria do tipo "moeda" CR2032), este sensor tem uma saída digital (o que permitiria usar o ATtiny2313, ligeiramente mais barato e capaz de acionar mais LEDs, mas sem ADC). A saída do sensor é do tipo "open drain", o que requer um resistor de pullup; usei o pullup interno do ATtiny.

O circuito (incluindo um conector para programação) fica assim:


A montagem foi feita em uma placa padrão, infelizmente o pouco espaçamento entre os LEDs impediu alinhá-los bem (o que não é problema quando a roda está girando).



Software

Para este projeto eu decidi fazer um software bem simples. A lógica toda é feita no loop principal, as interrupções não são nem habilitadas. Toda vez que o sensor é detectado é lido o valor do Timer1, que em seguida é zerado. Desta forma temos uma medição do tempo para a roda dar uma volta. Este tempo é dividido por 16, criando assim 16 setores. O início de cada setor é determinado olhando o valor do Timer1; para cada setor é programado um padrão nos LEDs conforme uma tabela. Se o tempo de uma volta ultrapassa o que pode ser medido pelo Timer1 os LEDs ficam apagados.

O software fica assim:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <inttypes.h>  
  4. #include <avr/io.h>  
  5. #include <avr/interrupt.h>  
  6.   
  7. // Conexões do hardware  
  8. #define SENSOR  _BV(PB0)  
  9. #define LED_VD  _BV(PB1)  
  10.   
  11. // Variaveis  
  12. static const uint8_t imagem[16] =  
  13. {  
  14.     0x80, 0xC1, 0x82, 0xC3, 0x84, 0xC5, 0x86, 0xC7,  
  15.     0x88, 0xC9, 0x8A, 0xCB, 0x8C, 0xFD, 0x8E, 0x00  
  16. };  
  17.   
  18. // Rotinas  
  19. static void initHw (void);  
  20.   
  21. // Programa principal  
  22. int main(void)  
  23. {  
  24.     uint8_t  fOvf = 1;  
  25.     uint8_t  fSensor = 0;  
  26.     uint16_t tempo = 0;  
  27.     uint16_t prox = 0;  
  28.     uint16_t passo = 0;  
  29.     uint8_t  setor = 0;  
  30.       
  31.     // Inicia o hardware  
  32.     initHw ();  
  33.       
  34.     // Eterno enquanto dure  
  35.     for (;;)  
  36.     {  
  37.         // Trata o sensor  
  38.         if (fSensor)  
  39.         {  
  40.             // já detectou o sensor, aguardando desligar  
  41.             fSensor = (PINB & SENSOR) == 0;  
  42.             if (!fSensor)  
  43.                 PORTB &= ~LED_VD;       // apaga LED verde  
  44.         }  
  45.         else if ((PINB & SENSOR) == 0)  
  46.         {  
  47.             // Detectou sensor  
  48.             if (fOvf == 0)  
  49.             {  
  50.                 // funcionamento normal  
  51.                 tempo = TCNT1;          // registra o tempo da volta  
  52.                 PORTA = imagem [0];     // LEDs para o primeiro setor  
  53.                 passo = tempo >> 4;     // divide a volta em 16 setores  
  54.                 prox = passo;  
  55.                 setor = 1;  
  56.             }  
  57.             else  
  58.             {  
  59.                 // ultrapassou o tempo máximo  
  60.                 fOvf = 0;               // limpa o flag, vamos tentar de novo  
  61.             }  
  62.             TCNT1 = 0;          // reinicia a contagem de tempo  
  63.             fSensor = 1;        // lembra que detectou o sensor  
  64.             PORTB |= LED_VD;    // indica detecção  
  65.         }  
  66.   
  67.         // Testa overflow do timer  
  68.         if (TIFR1 & _BV(TOV1))  
  69.         {  
  70.             fOvf = 1;               // ultrapassou o tempo máximo  
  71.             PORTA = 0;              // apaga os LEDs  
  72.             tempo = 0;              // não atualizar os LEDs  
  73.             TIFR1 |= _BV(TOV1);     // limpa o aviso do timer  
  74.         }  
  75.           
  76.         // Atualiza os LEDs  
  77.         if (tempo != 0)  
  78.         {  
  79.             if (TCNT1 >= prox)  
  80.             {  
  81.                 PORTA = imagem [setor++];   // passa para o setor seguinte  
  82.                 prox += passo;  
  83.                 if (setor == 16)  
  84.                     tempo = 0;              // acabaram os setores  
  85.             }  
  86.         }  
  87.           
  88.     }  
  89.       
  90. }  
  91.   
  92. // Inicia o hardware  
  93. static void initHw (void)  
  94. {  
  95.     // Port A são os LEDs  
  96.     DDRA = 0xFF;    // tudo saida  
  97.     PORTA = 0;      // LEDs apagados  
  98.       
  99.     // PORT B tem o sensor e o LED verde  
  100.     DDRB &= ~SENSOR;    // sensor é entrada  
  101.     DDRB |= LED_VD;     // LED é saida  
  102.     PORTB = SENSOR;     // com pullup  
  103.       
  104.     // Timer 1  
  105.     // Modo normal, clock/1024  
  106.     TCCR1A = 0;  
  107.     TCCR1B = _BV(CS12) | _BV(CS10);  
  108.     TCCR1C = 0;  
  109. }  
O vídeo abaixo é um pequeno teste.



Nenhum comentário: