#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

//vycet referencnich napeti:
enum TUref{refinterni, refexterni};
//vycet kanalu:
enum TKanal{ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3,
            ADC4 = 4, ADC5 = 5, ADC6 = 6, ADC7 = 7,
            ADTeplSenzor = 8,
            ADInterniRef = 14,
            ADGND = 15};

//globalni promenne:
volatile uint16_t adcudaj = 0;
volatile bool novyudaj = false;

inline void nastavADMUX(TUref ref, TKanal kanal)
{
  if(ref == refinterni)
    //Uref = Urefint = 1,1 V
    ADMUX = (1 << REFS1) | (1 << REFS0);
  else
    //Uref = AVCC = 5 V
    ADMUX = (1 << REFS0);
  
  ADMUX = ADMUX | kanal;
}

void inicializace()
{
  //externi reference, vstup ADC2:
  nastavADMUX(refexterni, ADC2);
  //delicka 128 (125 kHz), povolene preruseni:
  ADCSRA = (1 << ADIE)
         | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  
  //konfigurace c/c 1 (CTC, vrchol ICR1, D = 1024):
  TCCR1A = 0;
  TCCR1B = (1 << WGM13) | (1 << WGM12)
         | (1 << CS12) | (1 << CS10);
  ICR1 = 31249;  //500 ms
  TIMSK1 = (1 << ICIE1);  //povoli preruseni
}

int main(void)
{
  inicializace();
  
  //vypnuti analog. komparatoru:
  ACSR = (1 << ACD);
  //predvolba rezimu Idle:
  set_sleep_mode(SLEEP_MODE_IDLE);
  
  sei();
  
  while (1)
  {
    if(!novyudaj)
    {
      //vstupu do rezimu Idle:
      sleep_mode();
    }      
    
    if(novyudaj)
    {
      novyudaj = false;
      //vypis napeti v milivoltech:
      printf("ADC2 = %04u mV\n",
        uint16_t(adcudaj / 1024.0 * 5000));
    }
  }
}

//obsluha CTC:
ISR(TIMER1_CAPT_vect)
{
  //spusti A/D prevod programove:
  ADCSRA = ADCSRA | (1 << ADEN) | (1 << ADSC);
}

inline void clearbit(volatile uint8_t &reg, uint8_t bit)
{
  reg = reg & ~(1 << bit);
}

//obsluha dokonceni A/D prevodu
ISR(ADC_vect)
{
  adcudaj = ADC;
  novyudaj = true;
  clearbit(ADCSRA, ADEN);  //zastavi A/D prevodnik
}
