#include <hidef.h> 
#include "derivative.h" 

int starVysledek=555; //předchozí zmáčknutá hodnota
int tlacitko=0; //hodnota zmáčknutého tlačítka
int radek=1; //aktuální řádek, který se snímá

int operand=1; //určuje operaci mezi čísly
int dekCislo1=0; //uchovává hodnotu prvního čísla
int cislo1[4]=0; //číslo 1
int vysledek=0;  //výsledek operace
int zobrazeni=1; //to co bude zobrazovat displej



void inicLCD(void);  //inicializace displeje
void zobrazCislo(int segm1,int segm2,int segm3,int segm4); //funkce pro zobrazeni cisel na LCD
void cislo(int cislo); //funkce pro zobrazeni cisel na LCD
void posuv1 (int dCislo); //nahraje do pole cislo1 číslo na poslední pozici a předchozí čísla posune
void nulovani(void); //vynuluje pole cislo1



void main(void) {

inicLCD();  //inicializace LCD displeje
cislo(0);   //nastavení číselných segmentů LCD, aby ukazovaly 0
PTCPE=0x3C; // připojení pull-up rezistorů k PTC2, PTC3, PTC4, PTC5

TPM1MODH=0x1D;  //nastavení modula registrů pro ošetření zákmitů tlačítek (doba 200ms)
TPM1MODL=0x4C; 

//nastaveni-vystupu-PTC1, PTC0, PTA0, PTA6
PTADD_PTADD0=1;
PTCDD_PTCDD1=1;
PTCDD_PTCDD0=1;
PTADD_PTADD6=1;
//-------------------------------

//-nastaveni ktera-rada-jede- 
PTAD_PTAD0=0;  //rada 1
PTCD_PTCD1=1;  //rada 2
PTCD_PTCD0=1;  //rada 3
PTAD_PTAD6=1;  //rada 4
//---------------------------

  for(;;){

 if(PTCD_PTCD5==0){ //snímání prvního sloupce
switch(radek){
  case 2:posuv1(4);break;
  case 3:posuv1(7); break;
  case 4:{zobrazeni=1;dekCislo1=0;nulovani();break;}    //znak # -> C
  default:posuv1(1);break; 
}
  //ošetření zákmitu tlačítka--------
  TPM1SC=0x0F; //zapnutí časovače TPM1
  while(TPM1SC_TOF==0){__RESET_WATCHDOG();} //dokud nedojde k přetečení časovače
  TPM1SC=0x00; //vypnutí časovače TPM1
  //---------------------------------
  
  }
  
  
  if(PTCD_PTCD4==0){ //snímání druhého sloupce
  switch(radek){
  case 1:posuv1(2);break;
  case 2:posuv1(5);break;
  case 3:posuv1(8);break;
  default:posuv1(0);break; 
}
   //ošetření zákmitu tlačítka--------
  TPM1SC=0x0F; //zapnutí časovače TPM1
  while(TPM1SC_TOF==0){__RESET_WATCHDOG();} //dokud nedojde k přetečení časovače
  TPM1SC=0x00; //vypnutí časovače TPM1
  //---------------------------------
  } 
  
    
  if(PTCD_PTCD3==0){ //snímání třetího sloupce
  switch(radek){
  case 2:posuv1(6);break;
  case 3:posuv1(9);break;
  case 4:zobrazeni=3;break;  //vypis vysledku operace znak =
  default:posuv1(3);break; 
}
 //ošetření zákmitu tlačítka--------
  TPM1SC=0x0F; //zapnutí časovače TPM1
  while(TPM1SC_TOF==0){__RESET_WATCHDOG();} //dokud nedojde k přetečení časovače
  TPM1SC=0x00; //vypnutí časovače TPM1
  //---------------------------------
  }
   
 //-znaminka + - * / ---------------------------------------- 
  if(PTCD_PTCD2==0){ //snímání 4 sloupce
  switch(radek){
  case 2:{operand=2;dekCislo1=(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);nulovani();break;}
  case 3:{operand=3;dekCislo1=(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);nulovani();break;}
  case 4:{operand=4;dekCislo1=(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);nulovani();break;}
  default:{operand=1;dekCislo1=(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);nulovani();break;}
}
 //ošetření zákmitu tlačítka--------
  TPM1SC=0x0F; //zapnutí časovače TPM1
  while(TPM1SC_TOF==0){__RESET_WATCHDOG();} //dokud nedojde k přetečení časovače
  TPM1SC=0x00; //vypnutí časovače TPM1
  //---------------------------------
  
  }
 //---------------------------------------------------------- 



//-přepínání a nastavování řádků klávesnice---------------------------
radek=radek+1;  //přepínání řádků klávesnice
if(radek>4){radek=1;}
  
 switch(radek) { //nastavení zeme pro zvolený řádek
  
    case 2:{PTAD_PTAD0=1;PTCD_PTCD1=0;PTCD_PTCD0=1;PTAD_PTAD6=1;break;} //radek 2
    case 3:{PTAD_PTAD0=1;PTCD_PTCD1=1;PTCD_PTCD0=0;PTAD_PTAD6=1;break;} //radek 3
    case 4:{PTAD_PTAD0=1;PTCD_PTCD1=1;PTCD_PTCD0=1;PTAD_PTAD6=0;break;} //radek 4
default:{PTAD_PTAD0=0;PTCD_PTCD1=1;PTCD_PTCD0=1;PTAD_PTAD6=1;break;} //radek 1 
}
//-------------------------------------------------------------------- 
 

//-provedeni matematicke operace----------------------------- 
  switch(operand) {
    case 1: {vysledek=dekCislo1+(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);break;}
    case 2: {vysledek=dekCislo1-(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);break;}
    case 3: {vysledek=dekCislo1*(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);break;}
    case 4: {
    
    
    if((cislo1[0]==0)&&(cislo1[1]==0)&&(cislo1[2]==0)&&(cislo1[3]==0)){ //ošetření dělení 0
    vysledek=0;
    }else{      
    vysledek=dekCislo1/(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);}
   
    break;
    }
  default: vysledek=1;break;
 }
//----------------------------------------------------------- 
   
    
    
    
//-zobrazování na LCD displej------------------------------------------    
 switch(zobrazeni) { //zobrazí na displeji buď výsledek, číslo 1 nebo číslo 2
  case 1: cislo(cislo1[0]*1000+cislo1[1]*100+cislo1[2]*10+cislo1[3]);break;
  default: cislo(vysledek);break; 
 }
//---------------------------------------------------------------------  
 
    __RESET_WATCHDOG(); 
  } 
  
}

void nulovani(void) //vynuluje pole cislo1
{
cislo1[0]=0;
cislo1[1]=0;
cislo1[2]=0;
cislo1[3]=0;
}


void posuv1(int dCislo){
cislo1[0]=cislo1[1]; //posuv čísel v poli cislo1 o jedno vlevo 
cislo1[1]=cislo1[2];
cislo1[2]=cislo1[3];
cislo1[3]=dCislo; //jako poslední číslo se nastaví poslední zmáčklé

if(cislo1[0]>1){cislo1[0]=0;}
}

void inicLCD(void)      // slouzi k inicializaci displeje
{
 
  //--------  inicializační kód pro LCD displej  -------
LCDC0_LCDEN=0; 	//vypínání displeje pro nastavení parametru
LCDC0_SOURCE=0;		//připojení externího zdroje hodinového kmitočtu

//--------nastaveni zdroje hodinového kmitočtu
ICSC2_EREFS=1; //nastaveni oscilátoru jako externí reference 
ICSC2_ERCLKEN=1;	//připojení referenčního zdroje ICSERCLK
while(ICSSC_CLKST!=ICSC1_CLKS){} //čekání na synchronizaci   
//---------

LCDRVC=0x80;   	//povolení regulovaného napětí
LCDSUPPLY=0xB3; 	//vybraná nábojová pumpa, výběr napájení
LCDC1=0x03; 
LCDC0=0x21; 	// nastavení vykreslování, Duty 1/2

//povolení pinů displeje
LCDPEN0=0xFF; LCDPEN1=0xE0;  LCDPEN2=0xFF;LCDPEN3=0x7F; LCDPEN4=0xC0; 
LCDPEN5=0x03; 

//nastavení registrů pro funkci backplane
LCDBPEN0=0x00; LCDBPEN1=0x00; LCDBPEN2=0x00; LCDBPEN3=0x00; LCDBPEN4=0x00; LCDBPEN5=0x03;

LCDWF40=0x01; 	//nastavení COM1
LCDWF41=0x02;  	//nastavení COM2
LCDS=0x80;   	//vynulování přerušení
LCDC0_LCDEN=1;  	//zapnuti displeje, konec inicializace

}

  void zobrazCislo(int segm1,int segm2,int segm3,int segm4)
{
   switch(segm1) 
   {
     case 1: LCDWF0=0x02;break;
     default: LCDWF0=0x00;break;
   }
        
   switch(segm2) // zobrazeni cisel segment 2
   {
    case 1: LCDWF4=0x00;LCDWF5=0x01;LCDWF6=0x01;LCDWF7=0x00; break;
    case 2: LCDWF4=0x02;LCDWF5=0x01;LCDWF6=0x02;LCDWF7=0x03; break;
    case 3: LCDWF4=0x02;LCDWF5=0x01;LCDWF6=0x03;LCDWF7=0x01; break;
    case 4: LCDWF4=0x00;LCDWF5=0x03;LCDWF6=0x03;LCDWF7=0x00; break;
    case 5: LCDWF4=0x02;LCDWF5=0x02;LCDWF6=0x03;LCDWF7=0x01; break;
    case 6: LCDWF4=0x02;LCDWF5=0x02;LCDWF6=0x03;LCDWF7=0x03; break;
    case 7: LCDWF4=0x02;LCDWF5=0x01;LCDWF6=0x01;LCDWF7=0x00; break;
    case 8: LCDWF4=0x02;LCDWF5=0x03;LCDWF6=0x03;LCDWF7=0x03; break;
    case 9: LCDWF4=0x02;LCDWF5=0x03;LCDWF6=0x03;LCDWF7=0x01; break;
   
    default:LCDWF4=0x02;LCDWF5=0x03;LCDWF6=0x01;LCDWF7=0x03;break; // defaultni je 0
   }


 
   switch(segm3) // zobrazeni cisel segment 3
   {
    case 1: LCDWF14=0x00;LCDWF15=0x01;LCDWF16=0x01;LCDWF17=0x00; break;
    case 2: LCDWF14=0x02;LCDWF15=0x01;LCDWF16=0x02;LCDWF17=0x03; break;
    case 3: LCDWF14=0x02;LCDWF15=0x01;LCDWF16=0x03;LCDWF17=0x01; break;
    case 4: LCDWF14=0x00;LCDWF15=0x03;LCDWF16=0x03;LCDWF17=0x00; break;
    case 5: LCDWF14=0x02;LCDWF15=0x02;LCDWF16=0x03;LCDWF17=0x01; break;
    case 6: LCDWF14=0x02;LCDWF15=0x02;LCDWF16=0x03;LCDWF17=0x03; break;
    case 7: LCDWF14=0x02;LCDWF15=0x01;LCDWF16=0x01;LCDWF17=0x00; break;
    case 8: LCDWF14=0x02;LCDWF15=0x03;LCDWF16=0x03;LCDWF17=0x03; break;
    case 9: LCDWF14=0x02;LCDWF15=0x03;LCDWF16=0x03;LCDWF17=0x01; break;
   
    default:LCDWF14=0x02;LCDWF15=0x03;LCDWF16=0x01;LCDWF17=0x03;break; // defaultni je 0
   } 
   
   
    switch(segm4) // zobrazeni cisel segment 4
   {
    case 1: LCDWF18=0x00;LCDWF21=0x01;LCDWF22=0x01;LCDWF23=0x00; break;
    case 2: LCDWF18=0x02;LCDWF21=0x01;LCDWF22=0x02;LCDWF23=0x03; break;
    case 3: LCDWF18=0x02;LCDWF21=0x01;LCDWF22=0x03;LCDWF23=0x01; break;
    case 4: LCDWF18=0x00;LCDWF21=0x03;LCDWF22=0x03;LCDWF23=0x00; break;
    case 5: LCDWF18=0x02;LCDWF21=0x02;LCDWF22=0x03;LCDWF23=0x01; break;
    case 6: LCDWF18=0x02;LCDWF21=0x02;LCDWF22=0x03;LCDWF23=0x03; break;
    case 7: LCDWF18=0x02;LCDWF21=0x01;LCDWF22=0x01;LCDWF23=0x00; break;
    case 8: LCDWF18=0x02;LCDWF21=0x03;LCDWF22=0x03;LCDWF23=0x03; break;
    case 9: LCDWF18=0x02;LCDWF21=0x03;LCDWF22=0x03;LCDWF23=0x01; break;
   
    default:LCDWF18=0x02;LCDWF21=0x03;LCDWF22=0x01;LCDWF23=0x03;break; // defaultni je 0
   } 
   
       }
       
       
 void cislo(int cislo) // zadane cislo zobrazi (zobrazuje rozsah 0 a 1999)
  {    
  int cislo1=0;
  int cislo2=0;
  int cislo3=0;
  int cislo4=0;
  
  if(cislo!=starVysledek) {
 starVysledek=cislo;   

    
  if(cislo>1999)  // osetreni spravneho rozsahu 
  {
    cislo=1999;
  }
  
  if(cislo<0)
  {
    cislo=0 ;
  }
  
 cislo1=cislo/1000;   //dostanu tisicovku
 cislo2=(cislo-(cislo1*1000))/100;   //dostanu stovky
 cislo3=(cislo-(cislo1*1000)-(cislo2*100))/10;       //dostanu desitky
 cislo4=cislo-(cislo1*1000)-(cislo2*100)-(cislo3*10); // dostanu jednotky
  
  zobrazCislo(cislo1,cislo2,cislo3,cislo4);//zobrazeni vysledku 
  }
  }
