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:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

// Conexões do hardware
#define SENSOR  _BV(PB0)
#define LED_VD  _BV(PB1)

// Variaveis
static const uint8_t imagem[16] =
{
    0x80, 0xC1, 0x82, 0xC3, 0x84, 0xC5, 0x86, 0xC7,
    0x88, 0xC9, 0x8A, 0xCB, 0x8C, 0xFD, 0x8E, 0x00
};

// Rotinas
static void initHw (void);

// Programa principal
int main(void)
{
    uint8_t  fOvf = 1;
    uint8_t  fSensor = 0;
    uint16_t tempo = 0;
    uint16_t prox = 0;
    uint16_t passo = 0;
    uint8_t  setor = 0;
    
    // Inicia o hardware
    initHw ();
    
    // Eterno enquanto dure
    for (;;)
    {
        // Trata o sensor
        if (fSensor)
        {
            // já detectou o sensor, aguardando desligar
            fSensor = (PINB & SENSOR) == 0;
            if (!fSensor)
                PORTB &= ~LED_VD;       // apaga LED verde
        }
        else if ((PINB & SENSOR) == 0)
        {
            // Detectou sensor
            if (fOvf == 0)
            {
                // funcionamento normal
                tempo = TCNT1;          // registra o tempo da volta
                PORTA = imagem [0];     // LEDs para o primeiro setor
                passo = tempo >> 4;     // divide a volta em 16 setores
                prox = passo;
                setor = 1;
            }
            else
            {
                // ultrapassou o tempo máximo
                fOvf = 0;               // limpa o flag, vamos tentar de novo
            }
            TCNT1 = 0;          // reinicia a contagem de tempo
            fSensor = 1;        // lembra que detectou o sensor
            PORTB |= LED_VD;    // indica detecção
        }

        // Testa overflow do timer
        if (TIFR1 & _BV(TOV1))
        {
            fOvf = 1;               // ultrapassou o tempo máximo
            PORTA = 0;              // apaga os LEDs
            tempo = 0;              // não atualizar os LEDs
            TIFR1 |= _BV(TOV1);     // limpa o aviso do timer
        }
        
        // Atualiza os LEDs
        if (tempo != 0)
        {
            if (TCNT1 >= prox)
            {
                PORTA = imagem [setor++];   // passa para o setor seguinte
                prox += passo;
                if (setor == 16)
                    tempo = 0;              // acabaram os setores
            }
        }
        
    }
    
}

// Inicia o hardware
static void initHw (void)
{
    // Port A são os LEDs
    DDRA = 0xFF;    // tudo saida
    PORTA = 0;      // LEDs apagados
    
    // PORT B tem o sensor e o LED verde
    DDRB &= ~SENSOR;    // sensor é entrada
    DDRB |= LED_VD;     // LED é saida
    PORTB = SENSOR;     // com pullup
    
    // Timer 1
    // Modo normal, clock/1024
    TCCR1A = 0;
    TCCR1B = _BV(CS12) | _BV(CS10);
    TCCR1C = 0;
}
O vídeo abaixo é um pequeno teste.



Nenhum comentário: