#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdio.h>
#define F_CPU 16000000UL

#define BAUD 9600
#define UBRR F_CPU/16/BAUD-1
#define AREF 5

volatile unsigned char	msec4;
//--------------------------------------------------------------------
ISR (TIMER0_OVF_vect) { //4ms prerusenie
	msec4++;
	TCNT0 = 6; 
}
//--------------------------------------------------------------------
void InitTC_0 (void)		
{
	TCCR0B |= (1<<CS02); 	//Timer clock = system clock/256
	TIFR0 |= 1<<TOV0;		//Clear TOV0 flag
	TIMSK0 |= 1<<TOIE0;		//Enable Timer0 overflow interrupt
	TCNT0 = 6; 				//Nastavenie hodnoty 4ms/16MHz
}
//--------------------------------------------------------------------
void USART_Init (unsigned int ubrr)	
{
	UBRR0H = (unsigned char)(ubrr>>8);		
	UBRR0L = (unsigned char)ubrr;
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);	
	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);	
}
//------------------------------------------------------------------------------
void USART_Transmit_Text (char *text) 
{
	unsigned char	i;
	
	for (i=0; i<strlen(text); i++) {
		while(!(UCSR0A & (1 << UDRE0)));
		UDR0 = text[i];
	}	
}
//------------------------------------------------------------------------------
unsigned char USART_Receive( void) 
{
	while( !(UCSR0A & (1<<RXC0)) );
	return UDR0;
}
//------------------------------------------------------------------------------
void Init_ADC (void)				//Init A/D converter
{
	ADCSRA = (1<<ADEN);		//Enable ADC	
	ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);	//Division factor 128 16Mhz/128 = 125kHz
	DIDR0 = 0x3F;			//Disable Digital Input on ADC Channel 0,1,2,3,4,5			
	ADMUX |= (1<<REFS0);	//AVcc Reference 							
}
//--------------------------------------------------------------------
unsigned int ADC_read (unsigned char channel)
{
	ADMUX &= 0xF0;					
	ADMUX |= channel;
	ADCSRA |= (1<<ADSC);			//Start single A/D
	while(!(ADCSRA & (1<<ADIF)));	//Wait for conversion to complete
	ADCSRA &= ~(1<<ADIF);			//Clear flag AD conversion completed
	ADCSRA |= (1<<ADSC);			//Start single A/D
	while(!(ADCSRA & (1<<ADIF)));	//Wait for conversion to complete
	ADCSRA &= ~(1<<ADIF);			//Clear flag AD conversion completed
	return (ADC);					//ADC = ADCH + ADCL
}
//------------------------------------------------------------------------------
int main (void) {
	
	unsigned int	napatie=0;
	float	temp=0.0;
	char	buffer[50], znak;

	wdt_enable (WDTO_1S);
	DDRB |= (1<<DDB5);				//Led 500ms/500ms
	DDRD |= (1<<DDD4);				//Alarm LED
	DIDR1 = (1<<AIN1D);				//Disable Digital Input on AIN1	
	ACSR |= (1<<ACBG);				//Enable Internal 1.1V on AIN0
	USART_Init(UBRR);
	InitTC_0();
	Init_ADC();	
	sei();
	USART_Transmit_Text ("\nTEST ADC");	
	USART_Transmit_Text ("\n0 - Periodicky AD prevod Channel 0");	
	USART_Transmit_Text ("\n1 - AD prevod Channel 1");
	USART_Transmit_Text ("\n2 - AD prevod Channel 2");
	USART_Transmit_Text ("\n3 - AD prevod Channel 3");
	USART_Transmit_Text ("\n4 - AD prevod Channel 4");
	USART_Transmit_Text ("\n5 - AD prevod Channel 5");	
	USART_Transmit_Text ("\nT - Periodicky prevod teploty cipu so sognaliyaciou LED ALARM");
	USART_Transmit_Text ("\nR - Hodnota internej referencnej hodnoty napatia");	
	USART_Transmit_Text ("\nG - Hodnota GND potencialu");
	msec2=0; 
	while(1) { 
		wdt_reset();
		if ((UCSR0A & (1<<RXC0))) {
			znak = USART_Receive();
			switch (znak) {
				case '0': ADMUX = (1<<REFS0); napatie = ADC_read(0); break; //Aref = AVcc
				case '1': ADMUX = (1<<REFS0); napatie = ADC_read(1); break; //Aref = AVcc
				case '2': ADMUX = (1<<REFS0); napatie = ADC_read(2); break; //Aref = AVcc
				case '3': ADMUX = (1<<REFS0); napatie = ADC_read(3); break; //Aref = AVcc
				case '4': ADMUX = (1<<REFS0); napatie = ADC_read(4); break; //Aref = AVcc
				case '5': ADMUX = (1<<REFS0); napatie = ADC_read(5); break; //Aref = AVcc
				case 'T': ADMUX = (1<<REFS1)|(1<<REFS0);	 //Aref = Internal 1.1V Reference
						  ADC_read (8); break;               //Temeperature ADC8
				case 'R': ADMUX = (1<<REFS1)|(1<<REFS0);	 //Aref = Internal 1.1V Reference
						  napatie = ADC_read (14); break;	 //1.1V ADC14
				case 'G': ADMUX = (1<<REFS1)|(1<<REFS0);	 //Aref = Internal 1.1V Reference
						  napatie = ADC_read (15); break;	 //0V (GND) ADC15
				default:  USART_Transmit_Text ("\nNepoznam");
			}
			if (znak=='0'||znak=='1'||znak=='2'||znak=='3'||znak=='4'||znak=='5') {//Ak je zvoleny ADC0-ADC5)
				sprintf (buffer, "%c: %04d  0x%04X  %1.3fV\n", znak, napatie, napatie, napatie*AREF/1024.0);
				USART_Transmit_Text(buffer);
				PORTD &= ~(1<<PORTD4);
			}
			if (znak=='G'||znak=='R') {	//Ak je zvoleny ADC15 alebo ADC14
				sprintf (buffer, "%c: %04d  0x%04X  %1.3fV\n", znak, napatie, napatie, napatie*1.1/1024.0);
				USART_Transmit_Text(buffer);
				PORTD &= ~(1<<PORTD4);
			}
		}
		if (msec4 > 250) {				
			PORTB ^= (1<<PORTB5);
			msec4 = 0; 	
			if (znak == 'T') {			//Teplota chipu ATmega328P
				napatie = ADC_read(8); 
				temp = (napatie - (349 - 314) - 289)/1.06;
				sprintf (buffer, "T: %04d mv  %2.1f°C  ", napatie, temp);
				USART_Transmit_Text(buffer);
				if (temp < 26.0) {PORTD &= ~(1<<PORTD4); strcpy(buffer, "ALARM OFF\n");}
				else {            PORTD |= (1<<PORTD4);  strcpy(buffer, "ALARM ON\n");}
				USART_Transmit_Text(buffer);
			}
			if (znak=='0') {			//Napetie na vstupe 0
				napatie = ADC_read(0);
				sprintf (buffer, "%c: %04d  0x%04X  %1.3fV\n", znak, napatie, napatie, napatie*AREF/1024.0);
				USART_Transmit_Text(buffer);
			}
		}
	}
}
//------------------------------------------------------------------------------