//********************************************
//
// JLT02 forrasztóállomás
// program verzió: 2.001
// panel verzió: 5.4
// MCU: ATTINY 26
// CLK: 4 MHz (internal)
//
//********************************************

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>

//Szegmensek          Dgfedcba
#define NO_0		0b00111111
#define NO_1		0b00000110
#define NO_2		0b01011011
#define NO_3		0b01001111
#define NO_4		0b01100110
#define NO_5		0b01101101
#define NO_6		0b01111101
#define NO_7		0b00000111
#define NO_8		0b01111111
#define NO_9		0b01101111

//digitek
#define DIGIT_1_ON	PORTB = PORTB |  (1<<PINB0);
#define DIGIT_1_OFF	PORTB = PORTB & ~(1<<PINB0);

#define DIGIT_2_ON	PORTB = PORTB |  (1<<PINB1);
#define DIGIT_2_OFF	PORTB = PORTB & ~(1<<PINB1);

#define DIGIT_3_ON	PORTB = PORTB |  (1<<PINB2);
#define DIGIT_3_OFF	PORTB = PORTB & ~(1<<PINB2);

volatile uint16_t temp = 123;
volatile uint16_t setTemp = 300;
volatile uint16_t change  = 2000;

//port beállítás függvény
//-------------------------------------
void InitPORT(){
//-------------------------------------
    //       76543210
	DDRA = 0b01111111; // 0-bemenet, 1-kimeent
	 //      76543210	
    PORTA =0b10000000; // bemenetnél: 1-felhúzó ellenállás bekapcsolása, kimenetnél: 1/0-kezdőérték megadása

	//       6543210	
	DDRB = 0b0001111; // 0-bemenet, 1-kimeent
     //      6543210	
    PORTB =0b1100000; // bemenetnél: 1-felhúzó ellenállás bekapcsolása, kimenetnél: 1/0-kezdőérték megadása

    GIMSK|= (1<<INT0); // INT0 megszakítás engedélyezése
    sei(); // megszakítás bekapcsolása
} // InitPort

//timer beállítás függvény
//-------------------------------------
void InitTIMER(){
//-------------------------------------

    TCCR0 |= (1<<2);                   
	   
	OCR1C = 0b11110000;    

    //         76543210
    TCCR1A = 0b00100001;

    // 7 - COM1A1
    // 6 - COM1A0
    // 5 - COM1B1
    // 4 - COM1B0
    // 3 - FOC1A
    // 2 - FOC1B
    // 1 - PWM1A
    // 0 - PWM1B

    //         76543210
    TCCR1B = 0b00001101;

    // 7 - CTC1
    // 6 - PSR1
    // 5 - nem használt
    // 4 - nem használt
    // 3 - CS13      (1100 - 2048)
    // 2 - CS12     *(1101 - 4096)*
    // 1 - CS11      (1110 - 8192)
    // 0 - CS10      (1111 - 16384)
    
} // InitTimer

// adc beállítás függvény
//-------------------------------------
void InitADC() {
//-------------------------------------
//********************************************
//            76543210
    ADMUX = 0b00000000;
//********************************************
//    7  REFS1
//    6  REFS0
//       00 - Referencia az AVCC láb, AREF láb kondenzátorral testre kötve.
//       01 - Referencia az AREF láb, belső referencia lekapcsolva.
//       10 - Belső 2.56 Voltos referencia, AREF láb kikapcsolva.
//       11 - Belső 2.56 Voltos referencia, AREF láb kondenzátorral testre kötve.
//--------------------------------------------
//    5  ADLAR
//--------------------------------------------
//    4  MUX4
//    3  MUX3
//    2  MUX2
//    1  MUX1
//    0  MUX0
//       ADC port választás.

//********************************************
//           76543210
    ADCSR = 0b10000111;
//********************************************
//    7  ADEN
//       ADC engedélyezve ha értéke 1, kikapcsolva ha 0.
//--------------------------------------------
//    6  ADSC
//       Egyszeri mérésnél 1-re kell állítani, hogy megtörténjen a mérés.
//       Folyamatos mérésné ha 1-re állítjuk elindul a mérés,
//       ami utánna folyamatosan fut.
//--------------------------------------------
//    5  ADFR
//       Ha 1 akkor folyamatos mérés fut, ha 0 akkor egyszeri.
//--------------------------------------------
//    4  ADIF
//       Interrupt Flag - nem kell piszkálni :)
//       Ha 1 akkor a megszakítás jött létre.
//--------------------------------------------
//    3  ADIE
//       Ha 1 akkor a mérés végén megszakítás jön létre.
//       Ha 0 akkor a megszakítás kikapcsolva.
//--------------------------------------------
//    2  ADSP2
//    1  ADSP1
//    0  ADSP0
//       Előosztás
//       000 - 1
//       001 - 2
//       010 - 4
//       011 - 8
//       100 - 16
//       101 - 32
//       110 - 64
//       111 - 128
} // InitADC

// kijelzés vezérlő függvény
//-------------------------------------
void Display(uint8_t a, uint8_t b, uint8_t c) {
//-------------------------------------
uint8_t tomb[10] = {NO_0,NO_1,NO_2,NO_3,NO_4,NO_5,NO_6,NO_7,NO_8,NO_9};

    PORTA = (PORTA & 0b10000000) | tomb[a]; // PORTA-ra írjuk az aktuális szám kódját
	    DIGIT_1_ON; // első digit bekapcsolása
	    _delay_us(50); // várunk egy kicsit
	    DIGIT_1_OFF; // első digit kikapcsolása

    PORTA = (PORTA & 0b10000000) | tomb[b]; 
		DIGIT_2_ON;
		_delay_us(50);
		DIGIT_2_OFF;

    PORTA = (PORTA & 0b10000000) | tomb[c]; 
		DIGIT_3_ON;
		_delay_us(50);
		DIGIT_3_OFF;
} //display

// INT0 megszakítás függvény
// akkor fut le, ha az INT0 lábat testre húzza az encoder
//-------------------------------------
ISR(INT0_vect) {
//-------------------------------------   
    change=3000; // jelzés a main függvénynek, hogy megszakítás (hőfokállítás) volt
                 // ez az érték adja, hogy mennyi ideig jelzi ki a beállított hőfokot
    GIMSK= 0b00000000; // megszakítás ideiglenes kikapcsolása a folyamatos INT0 lefutás elkerülése miatt
                       // main függvénybe kapcsoljuk vissza, ha már nem érzékelünk alacsony jelet az INT0 lábon
    // jobbra tekerés
    if( PINB & (1<<PINB5) )  { // enkóder másik lábának figyelése, ha ez nem zárt(tehát logikai 1), akkor jobbra fordult
        if(setTemp<450) { // ha kissebb a hőfok mint 450, akkor növeli az értékét
            if( PINA & (1<<PINA7) ) {setTemp=setTemp+9;} // ha nincs lenyomva a gomb, akkor növeli 9-el a beállított hőfokot
            setTemp++; // növeli 1-el a beállított hőfokot
        } // if(setTemp
    } // if(PINB
        
    // balra tekerés
    else { // else ág... ha nem jobbra fordult, akkor balra :)
        if(setTemp>150) { // ha nagyobb a hőfok mint 150, akkor csökkenti az értékét
            if( PINA & (1<<PINA7) ) {setTemp=setTemp-9;} // ha nincs lenyomva a gomb, akkor csökkenti 9-el a beállított hőfokot
            setTemp--; // csökkenti 1-el a beállított hőfokot
        } // if(setTemp
    } // else    
} // ISR


// adc olvasás függvény
//-------------------------------------
uint16_t ReadADC(uint8_t ch) {
//-------------------------------------
    ADMUX = (ADMUX & 0b11110000) | ch; // csatorna kiválasztása
    ADCSR|=(1<<ADSC);          // konverzió elindítás
    while(ADCSR & (1<<ADSC));  // várás az átalakításra
    return (ADCL | (ADCH<<8));  // adc érték visszaadása
} // ReadADC

// fűtésvezérlés függvény
//-------------------------------------
void Heating() {
//-------------------------------------
	OCR1B = 0; // fűtés kikapcsolása... 
    // ezután minnél távolabb vagyunk a beálított hőfok alatt annál nagyobb PWM jelet állítunk a kimenetre
	if(temp<setTemp+5) 		{OCR1B = ((temp/5)-(temp/20));}
	if(temp==setTemp) 		{OCR1B = ((temp/5)-(temp/50));}
    if(temp<(setTemp)) 		{OCR1B = temp/4;}
    if(temp<(setTemp-1)) 	{OCR1B = temp/3;}
    if(temp<(setTemp-5)) 	{OCR1B = temp/2;}
    if(temp<(setTemp-10)) 	{OCR1B = 200;}
    if(temp<(setTemp-20)) 	{OCR1B = 255;}  
} // Heating

// main függvény
//-------------------------------------
int main(void) {
//-------------------------------------
	InitPORT(); // port beállítás lefuttatása
    InitTIMER(); // timer beállítás lefuttatása
    InitADC(); // adc beállítás lefuttatása

    unsigned int i=0, showTemp=0; // helyi változók
    
    _delay_ms(10); // várunk, hogy feltöltődjenek a kondenzátorok

    // EEPROM beállítása 300-ra ("resetelés")
    if( !(PINA & (1<<PINA7)) )  { // ha le van nyomva a gomb, akkor az eeprom-ba írás lefut
        eeprom_busy_wait();
        eeprom_write_word((uint16_t*)0,300); // 300 beírása az eeprom 0-ás címére
        eeprom_busy_wait();
    } // if
       
    // utoljára beállított hőmérséklet beállítása kezdőértéknek
    eeprom_busy_wait();
    setTemp = eeprom_read_word((uint16_t*)0); // eeprom 0-ás címének beolvasása
    eeprom_busy_wait();
        

    for(;;) { // fő végtelen ciklus
        
        if( PINB & (1<<PINB6) )  { // ha INT0 lábon megszünt a jel (tehát 1 mert a kapcsoló már nem zárja testre), akkor...
            GIMSK|= (1<<INT0); // INT0 megszakítás bekapcsolása
        }
	    
        if(change>0) { // ha change nagyobb mint 0 (tehát volt megszakítás)
            Display(setTemp/100, setTemp%100/10, setTemp%100%10); // beálított hőmérséklet kijelzése
            change--; // megszakítás jelző változó csökkentése
            if(change==0) { // ha lejár a beálított hőmérséklet kijelzése akkor mentjük a beálított értéket
                eeprom_busy_wait();
                eeprom_write_word((uint16_t*)0,setTemp); // beállított érték elmentése
                eeprom_busy_wait();
            } // if change==1
        } // if change>0
        
        else { // ha nincs megszakítás (hőfokállítás), akkor az aktuális hőmérséklet kijelzése
            if(i==0) { // csak 2000 ciklusonként frissíti a hőmérsékletet, hogy ne ugráljon a szám
                showTemp=temp; // kijelzett hőmérséklet = aktuális hőmérséklet
                i=2000; // frissítési számláló visszaállítása
            } // for
            i--; // frissítési számláló csökkentése
            Display(showTemp/100, showTemp%100/10, showTemp%100%10); // kijelző függvény meghívása (100-as, 10-es, 1-es) értékekkel
        } // else

        temp = ReadADC(7); // hőmérséklet mérése
		// hőmérséklet kompenzáció valós értékre
		if(temp<300) {temp=temp+((300-temp)/4);}
		if(temp>300) {temp=temp-((temp-300)/3);}

		Heating(); // fűtés vezérlő függvény lefuttatása
        
	} //for
} //main()


