segunda-feira, agosto 31, 2015

Timer para Apresentações - Testes

Montagem concluída, é hora de ver se funciona.

O primeiro teste foi desligar os conectores KK (pois o display compartilha pinos com o conector de programação), conectar um programador e confirmar que o avrdude consegue conversar com o ATtiny.

Nesta foto os conectores KK estão conectado, o display não influi muito no programador

O segundo teste usa um software que aciona os LEDs e buzzer conforme o pressionamento dos botões. No display é apresentado 12:34. O display deu um pouco de trabalho, pois parti do código que eu fiz para o MSP430 e não percebi que lá eu estava enviando primeiro o bit menos significativo e no ATtiny a única opção é enviar primeiro o mais significativo. Percebido isto, foi só inverter os valores enviados ao display. O software ficou assim:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>

// Bits correspondentes aos pinos de E/S
#define TEC1    _BV(PB0)
#define TEC2    _BV(PB1)
#define LED1    _BV(PA0)
#define LED2    _BV(PA1)
#define LED3    _BV(PA2)
#define LED4    _BV(PA3)
#define BUZZER  _BV(PA7)

// Pinos para comunicação I2C
#define DDR_USI             DDRA
#define PORT_USI            PORTA
#define PIN_USI             PINA
#define PORT_USI_SDA        PORTA6
#define PORT_USI_SCL        PORTA4
#define PIN_USI_SDA         PINA6
#define PIN_USI_SCL         PINA4

// Endereços dos registradores do TM1637
#define TM1637_I2C_COMM1    0x02 //0x40
#define TM1637_I2C_COMM2    0x03 //0xC0
#define TM1637_I2C_COMM3    0x01 //0x80

// Rotinas para comunicação I2C
void    I2C_Init        (void);
void    I2C_Start       (void);
uint8_t I2C_Write       (uint8_t b);
void    I2C_Stop        (void);

// Programa Principal
int main (void)
{
    int passo1 = 0;
    int passo2 = 0;
    
    // Configura o port A
    DDRA |= LED1 | LED2 | LED3 | LED4 | BUZZER;
    PORTA = 0;
    
    // Configura o port B
    DDRB &= ~(TEC1 | TEC2);
    PORTB = TEC1 | TEC2;

    // Inicia I2C
    I2C_Init();
    
    // Inicia o TM1637
    I2C_Start ();
    I2C_Write (TM1637_I2C_COMM1);
    I2C_Stop ();
    
    I2C_Start ();
    I2C_Write (TM1637_I2C_COMM2);
    I2C_Write (0x60);
    I2C_Write (0xDB);
    I2C_Write (0xF2);
    I2C_Write (0x66);
    I2C_Stop ();
    
    I2C_Start ();
    I2C_Write (TM1637_I2C_COMM3 | 0xF0);
    I2C_Stop ();
    
    
    // Loop infinito
    for (;;)
    {
        if ((PINB & TEC1) == 0)
        {
            // Apertou botão 1
            switch (passo1)
            {
                case 0:     // Acende LED1
                    PORTA |= LED1;
                    passo1 = 1;
                    break;
                case 1:     // Apaga LED1, acende LED3
                    PORTA &= ~LED1;
                    PORTA |= LED3;
                    passo1 = 2;
                    break;
                case 2:     // Apaga LED3
                    PORTA &= ~LED3;
                    passo1 = 0;
                    break;
            }
            // Dá um bip
            PORTA |= BUZZER;
            _delay_ms (300);
            PORTA &= ~BUZZER;
            // Espera soltar a tecla
            while ((PINB & TEC1) == 0)
                ;
            _delay_ms (100);    // debounce
        }
        if ((PINB & TEC2) == 0)
        {
            // Apertou botão 2
            switch (passo2)
            {
                case 0:     // Acende LED2
                    PORTA |= LED2;
                    passo2 = 1;
                    break;
                case 1:     // Apaga LED2, acende LED4
                    PORTA &= ~LED2;
                    PORTA |= LED4;
                    passo2 = 2;
                    break;
                case 2:     // Apaga LED4
                    PORTA &= ~LED4;
                    passo2 = 0;
                    break;
            }
            // Dá um bip
            PORTA |= BUZZER;
            _delay_ms (300);
            PORTA &= ~BUZZER;
            // Espera soltar a tecla
            while ((PINB & TEC2) == 0)
                ;
            _delay_ms (100);    // debounce
        }
    }
}

// Inicia a USI no modo I2C
void I2C_Init ()
{
    USIDR =  0xFF;
    USICR =  _BV(USIWM1) | _BV(USICS1) | _BV(USICLK);   // Sem interrupções
                                                        // Modo TWI
    USISR = _BV(USISIF) | _BV(USIOIF) |                 // Limpa flags e zera contador
            _BV(USIPF) | _BV(USIDC);
    DDR_USI  |= _BV(PIN_USI_SDA) | _BV(PIN_USI_SCL);    // colocar como saída
    PORT_USI |= _BV(PIN_USI_SDA) | _BV(PIN_USI_SCL);    // repouso = high (solto)
}

// Sinaliza Start
void I2C_Start ()
{
    PORT_USI |= _BV(PIN_USI_SCL);               // Solta SCL
    while ((PIN_USI & _BV(PIN_USI_SCL)) == 0)   // Espera SCL alto
        ;
    _delay_us (4);
    PORT_USI &= ~_BV(PIN_USI_SDA);          // Baixa SDA
    _delay_us (4);
    PORT_USI &= ~_BV(PIN_USI_SCL);          // Baixa SCL
    PORT_USI |= _BV(PIN_USI_SDA);           // Solta SDA
}

// Envia um uint8_t e lê o ACK ou NAK
uint8_t I2C_Write (uint8_t b)
{
    uint8_t temp;
    
    PORT_USI &= ~_BV(PIN_USI_SCL);          // Baixa SCL
    USIDR = b;                              // Coloca dado no shift register
    USISR = _BV(USISIF) | _BV(USIOIF) |     // Limpa flags e zera contador
            _BV(USIPF) | _BV(USIDC);
    do
    {
        _delay_us (4);
        USICR |= _BV(USICLK) | _BV(USITC);          // Pulsa clock p/ cima
        while ((PIN_USI & _BV(PIN_USI_SCL)) == 0)   // Espera SCL subir
            ;
        _delay_us (4);              
        USICR |= _BV(USICLK) | _BV(USITC);          // Pulsa clock p/ baixo
    } while ((USISR & _BV(USIOIF)) == 0);       // Repete para todos os bits

    _delay_us (4);                
    USIDR = 0xFF;                            // Solta SDA
    DDR_USI &= ~_BV(PIN_USI_SDA);            // SDA passa a ser entrada
    USISR = _BV(USISIF) | _BV(USIOIF) |      // Limpa flags e inicia contador
            _BV(USIPF) | _BV(USIDC) |        //   para ler 1 bit
            (0xE<<USICNT0);
    do
    {
        _delay_us (4);
        USICR |= _BV(USICLK) | _BV(USITC);          // Pulsa clock p/ cima
        while ((PIN_USI & _BV(PIN_USI_SCL)) == 0)   // Espera SCL subir
            ;
        _delay_us(4);              
        USICR |= _BV(USICLK) | _BV(USITC);          // Pulsa clock p/ baixo
    } while ((USISR & _BV(USIOIF)) == 0);    // Repete para todos os bits
    temp  = USIDR;                           // Lê a resposta
    USIDR = 0xFF;                            // Solta SDA
    DDR_USI |= _BV(PIN_USI_SDA);             // SDA passa a ser saída
    return temp;
}

// Sinaliza Stop
void I2C_Stop ()
{
    PORT_USI &= ~_BV(PIN_USI_SDA);          // Baixa SDA
    PORT_USI |= _BV(PIN_USI_SCL);           // Solta SCL
    while ((PIN_USI & _BV(PIN_USI_SCL)) == 0)   // Espera SCL alto
        ;
    _delay_us (4);
    PORT_USI |= _BV(PIN_USI_SDA);           // Solta SDA
    _delay_us (4);
}
O vídeo abaixo mostra o teste em uso, sofri um pouco com os botões.

 
Finalizada a montagem e os testes, é hora de fazer o software definitivo. Isto fica para o próximo post.

Nenhum comentário: