/*
 IR_Station
 ATmega8 8MHz
 */

#include <avr/io.h>
#include <avr/iom8.h>
#include <avr/interrupt.h>
//#include <stdlib.h>
//#include "lcd.h"

#define setbit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clearbit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define checkbit(ADDRESS,BIT) (ADDRESS & (1<<BIT))
#define adc_Vref ( (1 << REFS1) | (1 << REFS0) )

unsigned int PWM_CNT = 0;
unsigned int PWM_LEVEL = 0;

void delay(void);
void testPID(void);


void delay(void){
	for (int i = 0; i < 100; i++);
}
/********************************************************************************************/
static int error = 0, derivative = 0, integral = 0, previousValue = 0;
unsigned int currentTemp = 20, targetTemp = 200;

unsigned char normalizer(float U) {
	unsigned char result;

	if (U > 100) {
		result = 100;
	}

	if (U < 0) {
		result = 0;
	}

	if ((U >= 0) && (U <= 100)) {
		result = (unsigned char) U;
	}

	return result;
}
/********************************************************************************************/
unsigned char PID(unsigned int currentTemp, unsigned int targetTemp) {
	unsigned char result;
	float Ig = 0.0001;
	float Dg = 1.2;
	float Eg = 2;

	error = targetTemp - currentTemp;
	derivative = error - previousValue;
	integral = integral + error;

	result = normalizer(Ig * integral + Dg * derivative + Eg * error);
	previousValue = error;

	return result;
}
/********************************************************************************************/
unsigned int adc_read(unsigned char chanel) {
	unsigned int result = 0;

	ADMUX = chanel | adc_Vref;
	delay();
	ADCSRA |= (1 << ADSC); // start conv
	while ((ADCSRA & 0x10) == 0)
		; // wait for conv completed
	ADCSRA |= (1 << ADIF); // clear ADIF flag
	result = (ADCL | (ADCH << 8));
	return result;
}
/********************************************************************************************/
ISR( TIMER0_OVF_vect) {
	PWM_CNT++;

	if (PWM_CNT == 1000) {
		PWM_CNT = 0;
		setbit(PORTD, 2);
	}

	if (PWM_CNT == (PWM_LEVEL * 10)) {
		clearbit(PORTD, 2);
	}

	TCNT0 = 0x83;
}
/********************************************************************************************/
ISR( TIMER1_OVF_vect) {
	testPID();
	TCNT1 = 0x30D4;
}
/********************************************************************************************/
void io_init(void) {
	PORTB = 0x00;
	DDRB = 0xFF;

	PORTC = 0xFF;
	DDRC = 0x00;

	PORTD = 0x00;
	DDRD = 0xFF;

	/* ADC init */
	ADMUX |= adc_Vref;
	ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (ADPS0); // adc - enable; clk/128

	/* Timer 0 init */
	TCCR0 = (1 << CS01) | (1 << CS00); // clk/64
	TCNT0 = 0x7D; // TCNT0 = 125 --- T=(1/125k)*125 = 1ms
	TIMSK = (1 << TOIE0); // timer 0 overflow enable

	/* Timer 1 init */
	TCCR1B |= (1 << CS11) | (1 << CS10); // clk / 64
	TCNT1 = 0x30D4; // TCNT1 = 12500 --- T=(1/125k)*12500 = 0.1s
	TIMSK |= (1 << TOIE1); // timer 1 overflow enable

	sei();
}
/********************************************************************************************/
void testPID(void) {
	char buffer[5];
	if (bit_is_clear(PINC, 2)) {
		currentTemp++;
		if (currentTemp > 215) {
			currentTemp = 170;
		}
		PWM_LEVEL = PID(currentTemp, targetTemp);
	}
	currentTemp++;
	PWM_LEVEL = PID(currentTemp, targetTemp);

	//lcd_clrscr();
	//lcd_puts("Tt = ");
	//itoa(currentTemp, buffer, 10);
	//lcd_puts(buffer);
	//lcd_puts("\nPWM_LEVEL = ");
	//itoa(PWM_LEVEL, buffer, 10);
	//lcd_puts(buffer);
}
/********************************************************************************************/
int main(void) {
	io_init();
	//lcd_init(LCD_DISP_ON);

	while (1) {
		//testPID();
	}

	return 0;
}
