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:
Postar um comentário