#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

unsigned char digit[10] = {
    0b01111110, // = 0
    0b00110000, // = 1
    0b01101101, // = 2
    0b01111001, // = 3
    0b00110011, // = 4
    0b01011011, // = 5
    0b01011111, // = 6
    0b01110000, // = 7
    0b01111111, // = 8
    0b01110011  // = 9
};

void display(int value)
{
    // Configura o PORTB e PORTD baseado nos bits do dígito
    for (int i = 0; i < 7; ++i) {
        if (i != 6) { // Para segmentos de 'a' até 'f'
            if (digit[value] & (1 << (6 - i)))
                PORTB |= (1 << i);
            else
                PORTB &= ~(1 << i);
        } else { // Para o segmento 'g'
            if (digit[value] & 1)
                PORTD |= (1 << PORTD7);
            else
                PORTD &= ~(1 << PORTD7);
        }
    }
}

int main(void)
{
    DDRB = 0xFF;         // Configura PORTB como saída
    DDRD |= (1 << DDD7); // Configura o pin 7 de PORTD como saída

    ADMUX |= (1 << REFS0);                                // Configura a referência de tensão para AVcc
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Configura o prescaler do ADC para 128 (16MHz/128 = 125kHz)
    ADCSRA |= (1 << ADEN);                                // Habilita o ADC

    int adc_value; // Variável para armazenar o valor lido do ADC

    while (1) {
        ADCSRA |= (1 << ADSC); // Iniciando a conversão ADC

        // Espera a conversão terminar
        while (ADCSRA & (1 << ADSC))
            ; // ADSC é limpo automaticamente após a conversão

        adc_value = ADCL;         // Lê o valor baixo do ADC primeiro
        adc_value |= (ADCH << 8); // Lê o valor alto do ADC e combina com o valor baixo

        // Calcula qual número mostrar baseado no valor ADC, multiplica o valor do ADC por 10 e divide por 1024
        display((adc_value * 10) / 1024);

        _delay_ms(50); // Atraso para facilitar a visualização e não sobrecarregar o ADC
    }
}