terça-feira, agosto 21, 2012

Piscando um LED com o ATtiny85

Vamos cumprir o ritual de todo microcontrolador novo: piscar um LED. Este é um exercício simples mas que requer uma boa leitura do datasheet, a montagem de um circuito básico e a conexão de um gravador.


Hardware

O hardware é uma adaptação do montado para o ATtiny2313 (afinal, ainda estava na protoboard). Foram usados todos os oito pinos do ATtiny85:
  • Dois pinos para a alimentação
  • Um pino para reset
  • Três pinos para a gravação da flash
  • Um pino para a tecla e outro para o LED
Tipicamente se abdica da programação no circuito para liberar mais três pinos de E/S. O pino de reset também pode ser usado para E/S, porém aí não dá mais para fazer a programação low voltage.

Como no projeto anterior a alimentação será com uma bateria de 3V e o clock será o interno de 8MHz dividido por 8. Os fuses do ATtiny serão mantidos na programação de fábrica (que você pode conferir no manual ou neste site).

Software

O software é praticamente o mesmo do ATtiny2313,  apenas trocando as portas onde estão ligados o LED e a tecla.
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

// Bits correspondentes aos pinos de E/S
#define BOTAO   _BV(PB3)
#define LED     _BV(PB4)

// Valor para contar (aproximadamente) 50ms
#define TEMPO_50MS  3

// Controle do LED
static enum { APAGADO, ACESO, PISCANDO } ModoLed;

// Controles do estado do botão
#define BOTAO_ANTERIOR 0x01 // este bit indica o estado anterior
#define BOTAO_APERTADO 0x02 // este bit tem o valor c/ "debounce"
static unsigned char ModoBotao;

// Programa Principal
int main (void)
{
    // Pino do LED é saída
    DDRB |= LED;
    PORTB = 0;
    
    // Pino do Botão é entrada com pullup
    DDRB &= ~BOTAO;
    PORTB |= BOTAO;

    // Configura o timer 0
    TCCR0A = 0;                         // Modo normal: overflow a cada 256 contagens
    TCCR0B = _BV(CS01) | _BV(CS00);     // Usar clkIO/64: int a cada 64*256/1000 ms
                                        //   = 16,384 ms
    TIMSK = _BV(TOIE0);                // Interromper no overflow

    // Inicia os nossos controles
    ModoBotao = 0;
    ModoLed = PISCANDO;
    
    // Permite interrupções
    sei ();
    
    // Loop infinito
    for (;;)
    {
        set_sleep_mode(SLEEP_MODE_IDLE);
        sleep_mode();
    }
}

// Tratamento da interrupção do timer 0
ISR (TIMER0_OVF_vect)
{
    static unsigned char cnt = TEMPO_50MS;
    
    // Aguarda 50 ms
    if (--cnt != 0)
        return;
    cnt = TEMPO_50MS;
    
    // Trata o LED
    if (ModoLed == PISCANDO)
        PORTB ^= LED;
    
    // Trata o botão
    if ((PINB & BOTAO) == 0)
    {
        // Botao está apertado
        if (ModoBotao & BOTAO_ANTERIOR)
        {
            if ((ModoBotao & BOTAO_APERTADO) == 0)
            {
                // Acabamos de detectar o aperto
                ModoBotao |= BOTAO_APERTADO;
                switch (ModoLed)
                {
                    case APAGADO:
                        ModoLed = ACESO;
                        PORTB |= LED;
                        break;
                    case ACESO:
                        ModoLed = PISCANDO;
                        break;
                    case PISCANDO:
                        ModoLed = APAGADO;
                        PORTB &= ~LED;
                        break;
                }
            }
        }
        else
        {
            // Vamos aguardar a confirmação
            ModoBotao |= BOTAO_ANTERIOR;
        }
    }
    else
    {
        if (ModoBotao & BOTAO_ANTERIOR)
            ModoBotao &= ~BOTAO_ANTERIOR;   // aguarda confirmar
        else
            ModoBotao &= ~BOTAO_APERTADO;   // confirmado
    }
}
Um makefile automatiza a geração e gravação do HEX. No caso estou usando o gravador USBtinyISP,

PROGNAME=Led85
AVRDUDEFLAGS=-c usbtiny -p attiny85

all: ${PROGNAME}.hex

program: ${PROGNAME}-upload

${PROGNAME}.hex: ${PROGNAME}.obj
    avr-objcopy -R .eeprom -O ihex ${PROGNAME}.obj ${PROGNAME}.hex

${PROGNAME}.obj: ${PROGNAME}.c
    avr-gcc -g -Os -Wall -mcall-prologues -mmcu=attiny85 \
    -Wl,-Map,${PROGNAME}.map -o ${PROGNAME}.obj ${PROGNAME}.c

${PROGNAME}-upload: ${PROGNAME}.hex
    avrdude ${AVRDUDEFLAGS} -U flash:w:${PROGNAME}.hex:i

Testes

A montagem foi muito simples: retirei o ATtiny2313, espetei o ATtiny85, movi três conexões (terra, tecla e LED). Aí foi só gravar a Flash e ligar a alimentação para ver o LED piscando.

Esta é a vantagem de famílias bem planejadas de microcontroladores: você adapta facilmente o projeto de um modelo para outro.

Nenhum comentário: