#include <avr/io.h>
#include <util/delay.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif

#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#define LCDBUS_PORT PORTD
#define LCDBUS_DDR DDRD

unsigned char LCD_msg1[]="Welcome to AVR  Hello World     ";

void init_ports(void);
void InitADC(void);
long ReadChannel(int channel);

void LCD_init(void);
void LCD_cmd(void);
void LCD_data(void);
void display_msg1(void);
void display_count(int);

int main(void)
{
	init_ports();
	LCD_init();				// LCD initialization routines
	display_msg1();
	
	long Adc_reading;
	int i;
	int output_data;
	
	InitADC();
	
	i=0;

	while(1)
	{		
		Adc_reading = ReadChannel(i);
		output_data = Adc_reading;
		display_count(output_data);
		_delay_ms(2000);
		_delay_ms(2000);
	}
	return 0;
}


void init_ports(void)
{
	DDRB = 0xFF;
	LCDBUS_DDR = 0xFF;
	
	sbi(DDRB,0);	//set B.0 as output - used for LCD RS
	sbi(DDRB,1);	//set B.1 as output - used for LCD R/W
	sbi(DDRB,2);	//set B.2 as output - used for LCD EN
}

void InitADC(void)
{
	ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX1) | _BV(MUX0);
	ADCSRA=0X83; 	
}
	/*	ADC	Initialisation starts here	
	ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(ADLAR) | _BV(MUX1);
	ADCSRA = _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0);
	ADCSRA |= _BV(ADSC);
	while(ADCSRA&(1<<ADSC));
	ADC	Initialisation ends here	*/
	
	
long ReadChannel(int channel)
{
	switch(channel)
	{
		case 0:
			ADMUX = _BV(REFS1) | _BV(REFS0); 
			break;
		case 1:
			ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX0);
			break;
		case 2:
			ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX1); 
			break;
		case 3:
			ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX1) | _BV(MUX0); 
			break;
		case 4:
			ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2);
			break;
		case 5:
			ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX0); 
			break;
		
	}
	
	ADCSRA |= _BV(ADSC); 
	while (ADCSRA & (1 << ADSC));
 	
	ADCSRA |= _BV(ADSC); 
	while (ADCSRA & (1 << ADSC)); 	
	
	return ADC;	
}


void display_count(int count_f)
{
	count_f = count_f / 4;
	
	int count_in_hex_0;
	int count_in_hex_1;
	int count_in_hex_2;
	int count_in_hex_3;
	int thousand;
	int highquot_temp;
	int highquot;
	int quot_temp;
	int quot;
	int rem;
	
	
	thousand = count_f / 1000;
	highquot_temp = count_f % 1000;
	
	highquot = highquot_temp / 100;
	quot_temp = highquot_temp % 100;
	
	quot = quot_temp / 10;
	rem = quot_temp % 10;
	
	count_in_hex_0 = thousand + 48;
	count_in_hex_1 = highquot + 48;
	count_in_hex_2 = quot + 48;
	count_in_hex_3 = rem + 48;

	LCDBUS_PORT = 0xCC;
	LCD_cmd();	
	LCDBUS_PORT = count_in_hex_0;
	LCD_data();
	
	LCDBUS_PORT = 0xCD;
	LCD_cmd();	
	LCDBUS_PORT = count_in_hex_1;
	LCD_data();
	
	LCDBUS_PORT = 0xCE;
	LCD_cmd();	
	LCDBUS_PORT = count_in_hex_2;
	LCD_data();
	
	LCDBUS_PORT = 0xCF;
	LCD_cmd();	
	LCDBUS_PORT = count_in_hex_3;
	LCD_data();
	
	return;
}


void LCD_init(void)
{
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x0c;
	LCD_cmd();
	LCDBUS_PORT = 0x01;
	LCD_cmd();
	LCDBUS_PORT = 0x06;
	LCD_cmd();
	return;				// not sure weather to use this or not
}

void LCD_cmd(void)
{
	cbi(PORTB,0);	//clear B.0 - used for LCD RS
	cbi(PORTB,1);	//clear B.1 - used for LCD R/W
	sbi(PORTB,2);	//set B.2 - used for LCD EN
	_delay_us(5);
	cbi(PORTB,2);	//clear B.2 - used for LCD EN
	_delay_ms(5);
	return;				// not sure weather to use this or not
}

void LCD_data(void)
{
	sbi(PORTB,0);	//clear B.0 - used for LCD RS
	cbi(PORTB,1);	//clear B.1 - used for LCD R/W
	sbi(PORTB,2);	//set B.2 - used for LCD EN
	_delay_us(5);
	cbi(PORTB,2);	//clear B.2 - used for LCD EN
	_delay_ms(5);
	return;				// not sure weather to use this or not
}

void display_msg1(void)
{
	int char_count;
	LCDBUS_PORT = 0x01;
	LCD_cmd();	
	for(char_count=0;char_count<16;char_count++)
	{		
		LCDBUS_PORT = LCD_msg1[char_count];
		LCD_data();
	}

	LCDBUS_PORT = 0xc0;
	LCD_cmd();
	
	for(char_count=16;char_count<32;char_count++)
	{			
		LCDBUS_PORT = LCD_msg1[char_count];
		LCD_data();
	}
}
