#include <avr/io.h>

/* nastavenie premennych */
char napatie_vstup;
char P_gain =2, I_gain = 1, D_gain = 0;
char napatie_konst = 128;
signed int I_error = 0, P_error = 0, D_error = 0;
signed int error;
signed int PWM;
signed int sumerror;
signed int control;

/* nastavenie timeru pre PWM, phase correct, maximalna frekvencia, plus
nastavenie prerusenia */
void init_timer1(void)
{
TCCR1A |= _BV(WGM10)| _BV(COM1A1); // A normal, phase correct
TCCR1B |= _BV(CS10); 					
DDRD |= _BV(DDD5); //OC1A PD5
}

/* inicializuje nastavenie adc prevodnika */
void init_adc(void) 
{
/* delicka 64, vysledok ma byt medzi 50 000 a 200 000 Mhz, vysledok =
frekvencia krystalu delene delicka. moznosti delenia 2,2,4,8,16,32,64,128  */ 
ADCSRA |= (1 << ADPS2) | (1 << ADPS1); // delicka 64
ADCSRA |= (1 << ADEN); // Enable ADC 
/* admux nastavuje referencne volty, REFS1/REFS0. 0/0 Aref=Vref, 0/1 VCC=
Vref, 1/0 NIČ,1/1 Internal 2.56 Voltage Reference */
ADMUX |= (1 << REFS0); // nastavene VCC ako referencne
ADMUX |= (1 << ADLAR); //8 bit reading
ADMUX |= (1 << MUX2); // vstup ADC port
}

/* spusti ad prevodnik, vrati vystup napatia */
int read_adc(void) 
{
ADCSRA |= (1 << ADSC); // Start A2D Conversions
while(!((ADCSRA&_BV(ADIF))>>ADIF)); 
napatie_vstup=ADCH;
return napatie_vstup; 
}

/* hlavny program, spustenie nastavenia timeru, spustenie nastavenia AD
prevodniku */
int main (void) 
{ 
init_timer1(); // inicializuje timer
init_adc(); // inicializuje AD prevodnik

for(;;) // Loop Forever 
   { 
//_delay_ms(1);
read_adc();
error=napatie_konst-napatie_vstup;
sumerror=sumerror+error;
if(sumerror>=4096)
{sumerror=4096;}
else if(sumerror<=-4096)
{sumerror=-4096;}

control=(error*P_gain+I_gain*(sumerror))/10;
PWM=control;
if(PWM>=255)
{PWM=255;}
else if(PWM<=0)
{PWM=0;}

OCR1A=PWM;
} }