/*****************************************************
Chip type           : ATmega8
Program type        : Application
Clock frequency     : 8,0000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/

#include <mega8.h>
#include <delay.h>
#include <string.h>
#include <stdlib.h>

#define ADC_VREF_TYPE 0x00         

#define	KEY1_DOWN	(PINB.6 == 0)
#define	KEY2_DOWN	(PINB.7 == 0)
#define	KEY3_DOWN	(PINB.5 == 0)
#define	KEY4_DOWN	(PINB.4 == 0)
#define	KEY5_DOWN	(PINB.3 == 0)
   

/* 0,1,2,3,4,5,6,7,8,9 */
flash unsigned char digit[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
flash unsigned char off[] = {0x3f,0x71,0x71};

volatile unsigned int i = 1, j, Read_Key, T_digit[3], n;
volatile unsigned int adc_data, T, T_alldigit, T_disp, Mem[3];
unsigned int Time, Time_m, beep_i, set_time = 2000; 
bit stop, blink, set, c_beep, Keybit1, Keybit2, Keybit3, Keybit4, Keybit5, beep_bit, t;
volatile long pwm_val, ee_tmprSet, K_pwm = 30;
volatile int i2 = 500;

eeprom unsigned int T_prog[3] = { 200, 250, 300 };

static void avr_init();
void ReadKey (void);
void green (void);
void red (void);
void my_beep (void);
void One_Digit (void);
void Display (void);
 
// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
// Read the AD conversion result
adc_data=ADCW;
}

// Read the AD conversion result
// with noise canceling
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
#asm
    in   r30,mcucr
    cbr  r30,__sm_mask
    sbr  r30,__se_bit | __sm_adc_noise_red
    out  mcucr,r30
    sleep
    cbr  r30,__se_bit
    out  mcucr,r30
#endasm
return adc_data;
}


// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    TCNT0=0xb2; // 10мс
       
	i--;
    if (!i) {
            t++;
	        i = 20;  // скорость смены отображаемой на индикаторе температуры паяльника (25мс*10=0,25сек)
            T_disp = T;
	}
    
    // Timer
    if (!stop) {
            Time++;
            if (Time == 6000) {
                   Time_m++;
                   Time = 0;
            }
            if ((T >= 400 && Time_m == 15) || (T < 400 && Time_m == 60)) { // 15мин если Т > или = 400°
                   stop = 1;                                               // 60мин если меньше
                   Time = 0;
                   Time_m = 0;
                   c_beep = 1;
            }
    }
    
    // "beep по норм. температуре" (если температура 350мс*10=3,5сек в 2° рамках- то бип)
    if ((T > (ee_tmprSet - 3)) && (T < (ee_tmprSet + 3))) {
            beep_i--;
            if (!beep_i && !beep_bit && !stop) {
                   my_beep();
                   beep_bit = 1;
            }
    }
    else {
            beep_bit = 0;
            beep_i = 350;
    }
    
    i2--;
    
}

// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void) // Для индикации. Mожно конечно было повесить всё на одно
{
TCNT2=0x83; // 1мс
    
    if (set) {
            T_alldigit = ee_tmprSet;
            set_time--;
            if (!t) blink++;
            if (!set_time) set = blink = 0;
    }
    else T_alldigit = T_disp;
    
    One_Digit();
    Display();
    j++;
    if (j > 2) j = 0;

}

void main(void)
{
        avr_init();

while (1)
{
        adc_data = read_adc(0);
        T = adc_data / 2;
        
            // Подстройка коэф.ШИМ (ООС по темературе, стремление к "0")
        if (i2 <= 0) {
            if ((T > (ee_tmprSet - 8)) && (T < (ee_tmprSet + 4))) {
                   if (T < ee_tmprSet) K_pwm++;
                   if (T > ee_tmprSet) K_pwm--;
                   if (K_pwm < 0) K_pwm = 0;
                   if (K_pwm > 511) K_pwm = 511;
            }
            else {                  // чем выше температура, тем больше нужна величина ШИМ для поддержания температуры
                   if (ee_tmprSet > 150 && T > (ee_tmprSet - 36) && T < (ee_tmprSet + 36)) K_pwm = 30 + ((ee_tmprSet - 150) / 2);
                   else K_pwm = 30; // А ошибку исправит ООС
            }                       
            i2 = 25; // Скорость подстройки. Oсторожно, при маленьком значении будет болтание температуры
        }            // при большом стабилизация займёт больше времени
                     
        if (!stop) {
                pwm_val = K_pwm * (ee_tmprSet - T + 2);
                if (T > (ee_tmprSet - 6) && T < (ee_tmprSet + 6)) green();
                else red();
        }
        else {
                pwm_val = 0;
                PORTC.1 = PORTC.2 = 0;
        }
        
        if (pwm_val > 1023) pwm_val = 1023;
        if (pwm_val < 0) pwm_val = 0;
        
        ReadKey();
        
        if (Read_Key == 1) {
                ee_tmprSet++;
                if (ee_tmprSet > 480) ee_tmprSet = 480;
                Read_Key = 0;
        }
        
        if (Read_Key == 2) {
                ee_tmprSet--;
                if (ee_tmprSet < 50) ee_tmprSet = 50;
                Read_Key = 0;
        }
        
        if (Read_Key > 2 && Read_Key < 6) {       
                ee_tmprSet = Mem[Read_Key - 3];
                set = 1;
                Read_Key = 0;
        }
        
        if (Read_Key > 5 && Read_Key < 9) {
                #asm("cli")
                Mem[Read_Key - 6] = ee_tmprSet;
                T_prog[Read_Key - 6] =  Mem[Read_Key - 6];
                #asm("sei")
                my_beep();
                delay_ms(50);
                my_beep();
                delay_ms(50);
                my_beep();
                set = 1;
                Read_Key = 0;
        }        
        
        if (c_beep) {
                my_beep();
                delay_ms(50);
                my_beep();
                delay_ms(50);
                my_beep();
                delay_ms(50);
                my_beep();
                c_beep = 0;
        }
        
        
        OCR1AH = (unsigned char)(pwm_val>>8); // T.к регистр OCR1A - два 8-битных: делим по ним    
        OCR1AL = (unsigned char)pwm_val;      
        
      };
}

void ReadKey (void) {
if (!Read_Key) {        
        if (!KEY1_DOWN && Keybit1) Keybit1 = 0;
        if (!KEY2_DOWN && Keybit2) Keybit2 = 0;
        if (!KEY3_DOWN && Keybit3) Keybit3 = 0;
        if (!KEY4_DOWN && Keybit4) Keybit4 = 0;
        if (!KEY5_DOWN && Keybit5) Keybit5 = 0;

        if (KEY1_DOWN)	{
              if (!Keybit1) my_beep();
              delay_ms(100); // скорость установки температуры в "+" сторону
              Read_Key = 1;
              Keybit1 = 1; 
        }
        
        if (KEY2_DOWN)	{
              if (!Keybit2) my_beep();
              delay_ms(100); // в минусовую
              Read_Key = 2;
              Keybit2 = 1; 
        }
        
        if (KEY3_DOWN && !Keybit3)	{
              my_beep();
              for (n = 0; (KEY3_DOWN && n < 40); n++) {
                     delay_ms(50);
                     set = 1;
                     set_time = 2000;
                     }
              if (KEY3_DOWN) {      // Если кнопка нажата более 2сек (n40 * 50ms)
                     Read_Key = 6;  // тогда это (запись в память)
                     Keybit3 = 1;
              }
              else Read_Key = 3;    // иначе это (из памяти)
        }
        
        if (KEY4_DOWN && !Keybit4)	{
              my_beep();
              for (n = 0; (KEY4_DOWN && n < 40); n++) {
                     delay_ms(50);
                     set = 1;
                     set_time = 2000; // set_time - время индикации устанавливаемой Т в мс
                     }
              if (KEY4_DOWN) {
                     Read_Key = 7;
                     Keybit4 = 1;
              }
              else Read_Key = 4;
        }
        
        if (KEY5_DOWN && !Keybit5)	{
              my_beep();
              for (n = 0; (KEY5_DOWN && n < 40); n++) {
                     delay_ms(50);
                     set = 1;
                     set_time = 2000;
                     }
              if (KEY5_DOWN) {
                     Read_Key = 8;
                     Keybit5 = 1;
              }
              else Read_Key = 5;
        }
        
        if (Read_Key) {
              set_time = 2000;
              set = 1;
              Time = Time_m = 0;
              if (stop && Read_Key == 2) stop = 0;
        }
}
}

void green (void) {
        PORTC.1 = 0;
        PORTC.2 = 1;
}

void red (void) {
        PORTC.1 = 1;
        PORTC.2 = 0;
}

void my_beep (void) {
        PORTB.0 = 1;
        delay_ms(80); // длительность бип-сигнала
        PORTB.0 = 0;
}

void One_Digit (void) {
        T_digit[0] = T_digit[1] = 0;
        while (T_alldigit >= 100) {
               T_alldigit -= 100;  
               T_digit[0]++; // Сотни 
        }
        while (T_alldigit >= 10) {
               T_alldigit -= 10;  
               T_digit[1]++; // Десятки
        }
        T_digit[2] = T_alldigit; // Единицы
}

void Display (void) {
        PORTC &= ~(7<<3); // Гасим аноды
        if (stop) PORTD = ~off[j];
        else PORTD = ~digit[T_digit[j]]; // Ставим цифру на катоды
        if (!blink) PORTC |= 1<<(5-j);   // Включаем один из анодов 
}

static void avr_init() {
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=Out 
// State7=P State6=P State5=P State4=P State3=P State2=P State1=0 State0=0 
PORTB=0xFC;
DDRB=0x03;

// Port C initialization
// Func6=In Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=In 
// State6=P State5=0 State4=0 State3=0 State2=0 State1=0 State0=T 
PORTC=0x40;
DDRC=0x3E;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out 
// State7=1 State6=1 State5=1 State4=1 State3=1 State2=1 State1=1 State0=1 
PORTD=0xFF;
DDRD=0xFF;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 7,813 kHz
TCCR0=0x05;
TCNT0=0xB2;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Ph. correct PWM top=03FFh
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x83;
TCCR1B=0x03;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x04;
TCNT2=0x83;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x41;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AREF pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x8E;

if (T_prog[0] < 50 || T_prog[0] > 480) {
T_prog[0] = 200;
T_prog[1] = 250;
T_prog[2] = 300;
}
Mem[0] = T_prog[0];
Mem[1] = T_prog[1];
Mem[2] = T_prog[2];
ee_tmprSet = Mem[0];
stop = 1;

// Global enable interrupts
#asm("sei")   

}
