#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t contador = 0;
volatile uint16_t tempo = 0;
volatile uint8_t rodando = 1;
// Controle de tempo de debounce do botão por hardware
volatile uint8_t tempo_debounce = 0;
volatile uint8_t em_debounce = 0;
// Interrupção do Botão no Pino D2 (PD2 / INT0)
ISR(INT0_vect)
{
// Desabilita INT0 no registrador EIMSK para evitar debounce/ruído
EIMSK &= ~(1 << INT0);
em_debounce = 1;
tempo_debounce = 0;
// Alterna o estado do contador (Start / Pause)
rodando = !rodando;
// LED Magenta no pino D8 (PB0)
if (rodando)
{
PORTB |= (1 << PB0); // Liga LED Magenta
}
else
{
PORTB &= ~(1 << PB0); // Desliga LED Magenta
}
}
// Timer1 - Base de tempo de 1ms (Módulo CTC)
ISR(TIMER1_COMPA_vect)
{
// Tratamento do Debounce do botão (200ms)
if (em_debounce)
{
tempo_debounce++;
if (tempo_debounce >= 200)
{
em_debounce = 0;
EIFR |= (1 << INTF0); // Limpa qualquer flag pendente de interrupção
EIMSK |= (1 << INT0); // Reabilita a interrupção INT0
}
}
// Incrementa a contagem a cada 200ms quando ativo
if (rodando)
{
tempo++;
if (tempo >= 200)
{
tempo = 0;
contador++;
if (contador > 15)
contador = 0;
}
}
}
// Exibe o contador binário nos LEDs (D9, D10, D11, D12 -> PORTB)
void mostrarContador()
{
// Limpa as saídas PB1, PB2, PB3, PB4 (D9..D12)
PORTB &= ~((1 << PB1) | (1 << PB2) | (1 << PB3) | (1 << PB4));
// Aplica o valor do contador bit a bit
if (contador & 0x01) PORTB |= (1 << PB1); // Bit 0 -> Pino D9
if (contador & 0x02) PORTB |= (1 << PB2); // Bit 1 -> Pino D10
if (contador & 0x04) PORTB |= (1 << PB3); // Bit 2 -> Pino D11
if (contador & 0x08) PORTB |= (1 << PB4); // Bit 3 -> Pino D12
}
void setup()
{
// Configura Pinos D8, D9, D10, D11 e D12 como SAÍDA (DDRB = 1)
DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB2) | (1 << DDB3) | (1 << DDB4);
// Liga o LED Magenta (D8) no início
PORTB |= (1 << PORTB0);
// Configura Pino D2 (PD2) como ENTRADA com Resistor de Pull-Up interno ativado
DDRD &= ~(1 << DDD2);
PORTD |= (1 << PORTD2);
// Configura INT0 para disparar na Borda de Descida (FALLING Edge: ISC01=1, ISC00=0)
EICRA &= ~(1 << ISC00);
EICRA |= (1 << ISC01);
EIMSK |= (1 << INT0); // Habilita a interrupção externa INT0
// Configura Timer1 em modo CTC (Prescaler = 64)
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
OCR1A = 249; // Interrupção a cada 1ms para clock de 16MHz
TIMSK1 |= (1 << OCIE1A); // Habilita interrupção por comparação do Timer1
// Habilita interrupções globais no registrador SREG
sei();
}
void loop()
{
mostrarContador();
}