#include <mega48p.h>  
//тактовая частота 8МГц
//фьюзы:CKSEL3=CKSEL2=CKSEL0=SUT0=0-галочки
#include <delay.h>

#define ADC_VREF_TYPE 0xC0
#define KEY_UP        PINB.6
#define KEY_DOWN      PINB.7
#define TOP_PWM       0x1FF

// Declare your global variables here
unsigned char cifra[4];//0-й-после какой цифры стоит запятая, 0-это нигде 1-при первой и т.д.
                       //1-й - код отображаемого первого символа по ACS|| и т.д.
eeprom unsigned int T_zad_rez_eep=2505; //уставка для резистивного паяльника  
eeprom unsigned int T_zad_THA_eep=2505; //уставка для термопарного паяльника
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)  // раз в 0,005с 200Гц
{static unsigned char numer=1;
 unsigned char simbol;
// Reinitialize Timer 0 value
TCNT0=0x63;
// Place your code here
 numer++;
if(numer>3){numer=1;};
simbol=cifra[numer];
PORTC|=0b00111000;//отрываем от земли все катоды - гасим все
//выставляем на выводах нужный символ
switch(simbol)
 {case 0x30: PORTC.2=1;PORTB.0=1;PORTD.7=1;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=0;break;
  case 0x31: PORTC.2=0;PORTB.0=1;PORTD.7=1;PORTD.6=0;PORTD.5=0;PORTD.4=0;PORTD.3=0;break;
  case 0x32: PORTC.2=1;PORTB.0=1;PORTD.7=0;PORTD.6=1;PORTD.5=1;PORTD.4=0;PORTD.3=1;break;
  case 0x33: PORTC.2=1;PORTB.0=1;PORTD.7=1;PORTD.6=1;PORTD.5=0;PORTD.4=0;PORTD.3=1;break;
  case 0x34: PORTC.2=0;PORTB.0=1;PORTD.7=1;PORTD.6=0;PORTD.5=0;PORTD.4=1;PORTD.3=1;break;
  case 0x35: PORTC.2=1;PORTB.0=0;PORTD.7=1;PORTD.6=1;PORTD.5=0;PORTD.4=1;PORTD.3=1;break;
  case 0x36: PORTC.2=1;PORTB.0=0;PORTD.7=1;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;
  case 0x37: PORTC.2=1;PORTB.0=1;PORTD.7=1;PORTD.6=0;PORTD.5=0;PORTD.4=0;PORTD.3=0;break;
  case 0x38: PORTC.2=1;PORTB.0=1;PORTD.7=1;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;
  case 0x39: PORTC.2=1;PORTB.0=1;PORTD.7=1;PORTD.6=1;PORTD.5=0;PORTD.4=1;PORTD.3=1;break;
  case 0x41: PORTC.2=1;PORTB.0=1;PORTD.7=1;PORTD.6=0;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;//A
  case 0x43: PORTC.2=1;PORTB.0=0;PORTD.7=0;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=0;break;//C
  case 0x63: PORTC.2=0;PORTB.0=0;PORTD.7=0;PORTD.6=1;PORTD.5=1;PORTD.4=0;PORTD.3=1;break;//c
  case 0x48: PORTC.2=0;PORTB.0=1;PORTD.7=1;PORTD.6=0;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;//H
  case 0x2D: PORTC.2=0;PORTB.0=0;PORTD.7=0;PORTD.6=0;PORTD.5=0;PORTD.4=0;PORTD.3=1;break;//-
  case 0x55: PORTC.2=0;PORTB.0=1;PORTD.7=1;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=0;break;//U
  case 0x50: PORTC.2=1;PORTB.0=1;PORTD.7=0;PORTD.6=0;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;//P
  case 0x45: PORTC.2=1;PORTB.0=0;PORTD.7=0;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;//E
  case 0x24: PORTC.2=1;PORTB.0=1;PORTD.7=0;PORTD.6=0;PORTD.5=0;PORTD.4=1;PORTD.3=1;break;//значок градуса
  case 0x64: PORTC.2=0;PORTB.0=1;PORTD.7=1;PORTD.6=1;PORTD.5=1;PORTD.4=0;PORTD.3=1;break;//d
  case 0x74: PORTC.2=0;PORTB.0=0;PORTD.7=0;PORTD.6=1;PORTD.5=1;PORTD.4=1;PORTD.3=1;break;//t
  case 0x72: PORTC.2=0;PORTB.0=0;PORTD.7=0;PORTD.6=0;PORTD.5=1;PORTD.4=0;PORTD.3=1;break;//r
  default: PORTC.2=0;PORTB.0=0;PORTD.7=0;PORTD.6=0;PORTD.5=0;PORTD.4=0;PORTD.3=0;
 };
//выставляем если нужно точку
if(numer==cifra[0]){PORTD.2=1;}else{PORTD.2=0;};
//включаем нужный катод
switch(numer)
 {case 1: PORTC.5=0;break;
  case 2: PORTC.4=0;break;
  case 3: PORTC.3=0;break;
 };
}

// Read the AD conversion result
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);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

void main(void)
{
// Declare your local variables here
const unsigned int const_drt=160;  //постоянная терморезистора - к-во шагов ADC на изменение в 100С 
const unsigned int const_rt0=373; //к-во шагов ADC при 0С для терморез
const unsigned int const_THA=303; //к-во шагов АЦП на 100 С для термопары
const unsigned int const_THA0=230; //температура*10 холодного спая для термопары
unsigned int buf=0,T_izm,T_zad,OCR_1=0,Tsm=20;//T_izm,T_zad-измер и задан температуры *10  OCR_1-действующее значение ШИМ (макс 511)
unsigned char a,cnt_proh=0,cnt_proh_sm=0;     //Tsm - относительное смещение уставки в град*10, т.е. сначала на 2С вверх
unsigned int sum_Tizm=0;
unsigned char flg_tch=0;   //флаг мигания точки
unsigned char flg_payaln=1; //1-резистивный 0-термопарный
unsigned char menu=0;  //меню - 0-обычный режим, >0-меняем уставку
unsigned long buf_l;
unsigned int zap_max=0;  //максимальное заполнение - для плавного включения
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=Out Func2=In Func1=Out Func0=Out 
// State7=P State6=P State5=0 State4=P State3=0 State2=P State1=0 State0=0 
PORTB=0xD4;
DDRB=0x2B;

// Port C initialization
// Func6=In Func5=Out Func4=Out Func3=Out Func2=Out Func1=In Func0=In 
// State6=P State5=0 State4=0 State3=0 State2=0 State1=T State0=T 
PORTC=0x40;
DDRC=0x3C;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=In Func0=In 
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=P State0=P 
PORTD=0x03;
DDRD=0xFC;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 31,250 kHz
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x04;
TCNT0=0x63;
OCR0A=0x00;
OCR0B=0x00;



// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Fast PWM top=01FFh
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x82;
TCCR1B=0x09;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;      //OCR1A Указывает коэф заполнения ШИМ, 511(1FF)-100%, 255(FF)-50%
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

  
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x01;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 62,500 kHz
// ADC Voltage Reference: Int., cap. on AREF
// ADC Auto Trigger Source: None
// Digital input buffers on ADC0: On, ADC1: On, ADC2: Off, ADC3: Off
// ADC4: Off, ADC5: Off
DIDR0=0x3C;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x87;

// Global enable interrupts
delay_ms(1000);

start:
#asm("cli")
OCR1AH = 0;
OCR1AL = 0;
#asm("sei")
buf=0;
for(a=1;a<=10;a++)
       {buf+=read_adc(1);
       };
       buf=buf/10;
if(buf<1000){flg_payaln=1;}else{flg_payaln=0;}; //если при включении не максимум - то резист паяльник: flg_payaln=1
if(flg_payaln==0)  //для термопарного паяльника
 {buf=0;
  for(a=1;a<=10;a++)
       {buf+=read_adc(0);
       };
       buf=buf/10;
  if(buf>800)
   {cifra[1]=0x45;cifra[2]=0x72; cifra[3]=0x72;   //Err - ошибка паяльника
    delay_ms(1000);goto start; 
   };
 }else       //для резистивного паяльника
      {buf=0;
       for(a=1;a<=10;a++)
         {buf+=read_adc(1);
         };
       buf=buf/10;
      if((buf<const_rt0)||(buf>950)) //если температура ниже 0С или больше 350С- ошибка терморезистора
       {cifra[1]=0x45;cifra[2]=0x72; cifra[3]=0x72;   //Err - ошибка паяльника
        delay_ms(1000);goto start; 
       };
      };
if(flg_payaln==1){T_zad=T_zad_rez_eep;}else{T_zad=T_zad_THA_eep;}; //извлекаем уставки для соответствующих паяльников
while (1)
      {cnt_proh++;
       buf=0;
       
       if(flg_payaln==1) //для резист паяльника
       {for(a=1;a<=10;a++)   
          {buf+=read_adc(1);
          };
        buf=buf/10;
       if((buf>1010)||(buf<const_rt0)){goto start;}; //если обрыв или КЗ то на диагностику
              
       buf=buf-const_rt0;
       buf_l=buf;
       buf_l=buf_l*1000;
       buf_l=buf_l/const_drt;
       T_izm=(int)buf_l; //измеренная температура *10  
       }
        else      //для термопарного паяльника
            {for(a=1;a<=10;a++)   
               {buf+=read_adc(0);
               };
            buf=buf/10;
            if(buf>1010){goto start;}; //если обрыв то на диагностику 
            buf_l=const_THA0+((long)buf*1000)/const_THA; 
            T_izm=(int)buf_l; //измеренная температура *10 
            };
              
       if((T_zad+Tsm)>T_izm) //смещаем уставку на Tsm С(град*10) вверх, а потом на каждый градус отклонения даем 10%шим
        {buf_l=(((long)T_zad+(long)Tsm-(long)T_izm))*TOP_PWM/100;
         buf=(int)buf_l;
         if(buf>zap_max)    //для плавного включения
          {zap_max=zap_max+10;
           if(zap_max>TOP_PWM){zap_max=TOP_PWM;};
           buf=zap_max;
          };
        }else
             {buf=0;
             };
       
       if(flg_payaln==1)
        {if(buf>(TOP_PWM*7/10)){buf=TOP_PWM*7/10;};//для резистивного паяльника даем максимальное заполнение 70%
        }else
             {if(buf>TOP_PWM){buf=TOP_PWM;};   //для термопарного 100%
             };
       OCR_1=buf;
       #asm("cli")
       OCR1AH = (char)(OCR_1>>8);
       OCR1AL = (char)OCR_1;
       #asm("sei")
       sum_Tizm=sum_Tizm+T_izm; 
       if(cnt_proh>9)
        {cnt_proh=0;buf=sum_Tizm/100; //усреднили температуру за 10 проходов для дисплея и убрали десятые
         if(!menu)    //если не изменяем уставку, то высвечиваем текущую температуру
         {#asm("cli")
          cifra[1]=(char)((buf/100)%10+0x30);cifra[2]=(char)((buf/10)%10+0x30); cifra[3]=(char)(buf%10+0x30);
          #asm("sei")
         };
         buf=sum_Tizm/10;//в буфере измеренная усредненная температура с десятыми
         if(((T_zad+Tsm)>=buf)&&(buf>=(T_zad+Tsm-100))) //считаем проходы когда измер температура в диапазоне Тзад+-5С
          {cnt_proh_sm++; //счетчик проходов для корректир смещения если темпер в диапазоне
           flg_tch=0;
          }else
              {cnt_proh_sm=0;
               flg_tch=1; //флаг мигания точки если набор температуры
              }; 
         sum_Tizm=0;
         if(cnt_proh_sm>3) //если температура в пределах была уже 3проходов, то корректируем смещение уставки
          {if((buf>T_zad)&&(Tsm>0)){Tsm--;};
           if((buf<T_zad)&&(Tsm<100)){Tsm++;};
           cnt_proh_sm=0;
          };
        };
        
        #asm("cli")
        if(flg_tch)
         { if(cifra[0]==0){cifra[0]=3;}else{cifra[0]=0;}; //Точка мигает - температура в корректировке
         } else 
                {if(flg_payaln==1){cifra[0]=0;}else{cifra[0]=3;}; //гасим точку - температура в диапазоне для резист паяльн
                };                                                //зажигаем точку - температура в диапазоне для термопарного паяльн
        #asm("sei")
       
       if((!KEY_UP)||(!KEY_DOWN))
        {menu=50;
         if((!KEY_UP)&&(T_zad<=3450)){T_zad=T_zad+50;};
         if((!KEY_DOWN)&&(T_zad>250)){T_zad=T_zad-50;};
        };
       
       if(menu)   //печать мигающей уставки в режиме меню
        {#asm("cli")
         if((cnt_proh>=5)||(!KEY_UP)||(!KEY_DOWN))
           {buf=T_zad/10;
            cifra[1]=(char)((buf/100)%10+0x30);cifra[2]=(char)((buf/10)%10+0x30); cifra[3]=(char)(buf%10+0x30);
           }else
                {cifra[1]=0;cifra[2]=0; cifra[3]=0;
                };
         #asm("sei")
        };
        
       delay_ms(154);
       if(menu>0)
        {menu--;      //отсчитывает таймер на выход из меню изменения уставки
         
         if(menu==1)  //перед выходом из меню запис в еепром измененное значение
          {if(flg_payaln==1){buf=T_zad_rez_eep;}else{buf=T_zad_THA_eep;};
           if(T_zad!=buf)
            {if(flg_payaln==1){T_zad_rez_eep=T_zad;}else{T_zad_THA_eep=T_zad;};
            };
          menu=0;
          }; 
        }; 
       if(PINB.3==0){PORTB.3=1;}else{PORTB.3=0;}; 
       
      };
}