#include <mega64.h>
#include <delay.h>
#include <stdio.h>

    int array[100];          // pole hodnot z AD prevodniku (1023 max)
    int voltage[100];        // prepocitane hodnoty na napeti v mV

    unsigned int sound_speed;           // rychlost zvuku
    unsigned int temperature;           // teplota
    unsigned char period_signal;        // pocet period ve vyslanem signalu    
    unsigned char period_adc;           // perida prevodu adc 
    unsigned char scale;                // meritko
              
//********************************************************************************************************        
// fuknkce pro cteni hodnoty z AD prevodniku - pro ulrazvukovy signal
unsigned int read_adc_usonic(void)
{
ADMUX=0x00;                     // ADC0 input, 10bit, externi reference
//delay_us(1);                  //10
ADCSRA|=0x40;                   // spusteni prevodu
while ((ADCSRA & 0x10)==0);     // cekam dokud neni prevod hotovy
ADCSRA|=0x10;                   // vypnu ADC
return ADCW;                    // navratova hodnota - vysledek prevodu
}

//********************************************************************************************************    
// fuknkce pro cteni hodnoty z AD prevodniku - pro mereni teploty
unsigned int read_adc_temperature(void)
{
ADMUX=0x03;         // ADC3 input, 10bit, externi reference
delay_us(200);                           // prodleva kvuli stabilizaci napeti
ADCSRA|=0x40;                            // spusteni prevodu
while ((ADCSRA & 0x10)==0);              // cekam dukud neni prevod hotovy
ADCSRA|=0x10;                            // vypnu ADC
return ADCW;                             // navratova hodnota vysledek
}

//********************************************************************************************************
// zobrazi integer na pozici ktera je aktualne nastavena, je potreba ji nastavit predem !!!!
void show_int(int temp)
{     
    unsigned int a;
    unsigned char b;  

      a = temp;           // nahraju zobrazovanou hodnotu
      b=a/10000;
      LCD_char(b+'0');    // zobrazeni desetitisicu
      a=a-b*10000;
      b=a/1000;
      LCD_char(b+'0');    // zobrazeni tisicu
      a=a-b*1000;            
      b=a/100;
      LCD_char(b+'0');    // zobrazeni stovek
      a=a-b*100;
      b=a/10;
      LCD_char(b+'0');    // zobrazeni desitek
      a=a-b*10;
      b=a;
      LCD_char(b+'0');    // zobrazeni jednotek
}

//********************************************************************************************************
// fuknce pro zobrazeni vzdelenosti - v mm
void show_distance(int temp)
{
    unsigned int a;
    unsigned char b,x=0;           
    
      a = temp; 
      x=0;          
      b=a/10000;
      a=a-b*10000;
      b=a/1000;                     // tisice
      if(b==0) LCD_char(' ');       // pokud prvni nula, tak ji nezobrazu
      else {    LCD_char(b+'0');
                x=1; }
      a=a-b*1000;            
      b=a/100;                      // stovky
      if((b==0)&&(x==0))  LCD_char(' ');
      else {    LCD_char(b+'0');
                x=1; }
      a=a-b*100;
      b=a/10;                       //desitky
      if((b==0)&&(x==0))  LCD_char(' ');      
      else {    LCD_char(b+'0');
                x=1; }
      a=a-b*10;
      b=a;
      LCD_char(b+'0');              // jednotky
      LCD_char('m');                // mm
      LCD_char('m');      
}

//********************************************************************************************************
// zobrazeni hodnoty napeti na displeji - v mV
void show_voltage(int temp)
{     
    unsigned int a;
    unsigned char b, x=0;  
    
      a = temp;         
      x=0;  
      b=a/10000;
      a=a-b*10000;
      b=a/1000;                     // tisice
      if(b==0) LCD_char(' ');       // nezobrazuj prvni nulu
      else {    LCD_char(b+'0');
                x=1; }
      a=a-b*1000;            
      b=a/100;                      // stovky
      if((b==0)&&(x==0))  LCD_char(' ');
      else {    LCD_char(b+'0');
                x=1; }
      a=a-b*100;
      b=a/10;                       // desitky
      if((b==0)&&(x==0))  LCD_char(' ');
      else {    LCD_char(b+'0');
                x=1; }
      a=a-b*10;
      b=a;
      LCD_char(b+'0');              // jednotky
      LCD_char('m');
      LCD_char('V');
}

//********************************************************************************************************
// funkce pro zobrazeni citlivosti - v dB
void show_sens(int temp)
{
    unsigned int a;
    unsigned char b;
      
      a = temp;          
      b=a/10000;
      a=a-b*10000;
      b=a/1000;
      a=a-b*1000;            
      b=a/100;                         // stovky
      if(b==0) { LCD_string(" -");     //minus + prvni nulu nezobrazuj 
                }                
      else {LCD_char('-');
            LCD_char(b+'0'); }
      a=a-b*100;                       // desitky
      b=a/10;
      LCD_char(b+'0');
      a=a-b*10;
      b=a;
      LCD_char(b+'0');                  // jednotky
      LCD_char('d');
      LCD_char('B');
}

//********************************************************************************************************
// funkce pro zobrazeni cisla (char) na displeji
void show_char(int temp)
{     
    unsigned int a;
    unsigned char b;
      
      a = temp;           
      b=a/10000;
      a=a-b*10000;
      b=a/1000;
      a=a-b*1000;            
      b=a/100;
      a=a-b*100;
      b=a/10;
      LCD_char(b+'0');      // desitky
      a=a-b*10;
      b=a;
      LCD_char(b+'0');      //jednotky
}

//********************************************************************************************************
// zmeri aktualni teplotu a vypocita rychlost sireni zvuku
void compute_temperature(void)
{
    char n; 
    
      temperature = 0;                                       // 2x oversampling   
      for(n=0;n<4;n++) temperature = temperature + read_adc_temperature();          
      temperature = temperature * 0.625;            
      sound_speed = 331.6 + 0.61 * (temperature/10);        // rychlost zvuku
}

//********************************************************************************************************
// generovani ultrazvukove davky
void generate_usonic(unsigned char m)    // pocet kmitu
{
      unsigned char a;
      TCCR0 = 0x19;     // zapni oscilator
      for(a=0;a<m;a++) delay_us(25);    //6 period  150
      TCCR0 = 0x18;     // vypni oscilator
}

//********************************************************************************************************
// inicializace mikrokontroleru
void init_mcu(void)
{
PORTA=0x00;           // porty a in/out
DDRA=0xFF;

PORTB=0x00;
DDRB=0x10;

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0x00;

PORTE=0x00;
DDRE=0x02;

PORTF=0x00;
DDRF=0x00;

PORTG=0x00;
DDRG=0x00;

// Timer/Counter 0 : syzstem clock 8Mhz, mod CTC (toggle on compare), top=OCR0
ASSR=0x00;
TCCR0=0x18; //oscilator vypnuty
TCNT0=0x00;
OCR0=0x63;  // 40000 kHz

TCCR1A=0x00;         // dalsi casovace nepouzivam
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;

TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;


TCCR3A=0x00;
TCCR3B=0x00;
TCNT3H=0x00;
TCNT3L=0x00;
ICR3H=0x00;
ICR3L=0x00;
OCR3AH=0x00;
OCR3AL=0x00;
OCR3BH=0x00;
OCR3BL=0x00;
OCR3CH=0x00;
OCR3CL=0x00;

EICRA=0x00;
EICRB=0x00;
EIMSK=0x00;

TIMSK=0x00;

ETIMSK=0x00;

// USART0 : asynchronni, 8 Data, 1 Stop, No Parity, 9600 baudu 
UCSR0A=0x00;
UCSR0B=0x98;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x33;

UCSR1B=0x00;       // uart 1 nepouzivam

ACSR=0x80;
SFIOR=0x00;

// AD prevodnik - konkretni nastaveni teprve pred prevodem
ADMUX=0xC3;       
ADCSRA=0x82;      //87

SPCR=0x00;

TWCR=0x00;       // WDT vypnuty
}

//********************************************************************************************************
//funkce pro zobrazeni teploty a rychlosti zvuku
void show_temperature(void)
{
      
    unsigned char b;
    unsigned int a;
    
      LCD_text_xy(5,0);
      
      a=temperature;                // zobrazeni teploty
      b=a/10000;
      a=a-b*10000;
      b=a/1000;
      a=a-b*1000;            
      b=a/100;
      LCD_char(b+'0');
      a=a-b*100;
      b=a/10;
      LCD_char(b+'0');
      LCD_char('.');      
      a=a-b*10;
      b=a;
      LCD_char(b+'0');      
      LCD_char_diacritic(STUPEN);
      LCD_char('C');      
      
      LCD_char(' ');
      
      a=sound_speed;              // zobrazeni rychlosti zvuku
      b=a/10000;
      a=a-b*10000;
      b=a/1000;
      a=a-b*1000;            
      b=a/100;
      LCD_char(b+'0');
      a=a-b*100;
      b=a/10;
      LCD_char(b+'0');
      a=a-b*10;
      b=a;
      LCD_char(b+'0'); 
      LCD_string("m/s"); 
}

//********************************************************************************************************
// perioda prevodu ADC, promenna-konkretni hodnota
void show_period_adc(void)                     
{
switch(period_adc)
            {
            case 1: LCD_string("10  us");
                    break;
            case 2: LCD_string("13  us");
                    break;        
            case 3: LCD_string("21  us");
                    break;              
            case 4: LCD_string("34  us");
                    break;
            case 5: LCD_string("60  us");
                    break;       
            case 6: LCD_string("112 us");
                    break;         
            case 7: LCD_string("224 us");
                    break;
            }
}

//********************************************************************************************************
// vypocet meritka - podle hodnoty jak moc delit prubeh
void compute_scale(void)
{
    unsigned int max;
    unsigned char scale_auto,n;
    
    scale_auto = 1; 
      if (scale==0)                  //automaticke meritko
      {
      max = array[0];
      for (n=0;n<100;n++) if(array[n]>max) max=array[n]; 
      
      if (max>918) scale_auto=10;
      if ((max>816)&&(max<=918)) scale_auto=9;             // rozhodovaci urovne
      if ((max>714)&&(max<=816)) scale_auto=8;
      if ((max>612)&&(max<=714)) scale_auto=7; 
      if ((max>510)&&(max<=612)) scale_auto=6;
      if ((max>408)&&(max<=510)) scale_auto=5;
      if ((max>306)&&(max<=408)) scale_auto=4;
      if ((max>204)&&(max<=306)) scale_auto=3;
      if ((max>102)&&(max<=204)) scale_auto=2;
      if (max<=102) scale_auto=1;
      
      for (n=0;n<100;n++)                       // deleni - auto meritko
      {
      array[n]=array[n]/scale_auto;       
      if(array[n]>100) array[n]=100;            // orezani pokud namerena hodnoa je mimo rozsah osy y                   
      }
      }      
      
      if (scale!=0)                             //manualni nastaveni meritka 
      {
      for (n=0;n<100;n++)                       //deleni - meritko
      {
      array[n]=array[n]/scale;       
      if(array[n]>100) array[n]=100;            // orezani pokud namerena hodnoa je mimo rozsah osy y                   
      }           
      }
}

//********************************************************************************************************
// fuknce pro zobrazeni zmereneho prubehu
void show_graph(void)
{
    unsigned n;
      
      for(n=0;n<99;n++)             // vykresleni
      {
      LCD_line(n+13,113-array[n],n+14,113-array[n+1],1);                      
      }  
      
      for(n=0;n<53;n++)             // osy
      {
      LCD_set_pixel(12+n*2,114,1);
      LCD_set_pixel(12,114-n*2,1);     
      }    

      LCD_text_xy(20,13);           // popis os
      LCD_char('t'); 
      LCD_text_xy(0,1);
      LCD_char('U'); 
}

//********************************************************************************************************
// smazani prubehu - stejna funkce jako vyse ale smazu body - kdzbzch mazal cely displej tak by blikal
void clear_graph(void)
{
      unsigned char n;
      
      for(n=0;n<99;n++)                      //smazani prubehu predchoziho
      {      
      LCD_line(n+13,113-array[n],n+14,113-array[n+1],0);                
      }

}

//********************************************************************************************************
// poslani dat po USB do pocitace
void dataUSB(void)
{
    unsigned char b,n=0;
    unsigned int a;
                                                 // napis a pocitani procent - odeslane data
        LCD_text_xy(5,5);
        LCD_char('p');
        LCD_char_diacritic(R_HACEK_M);
        LCD_string("enos dat:");
        LCD_text_xy(11,8);    
        LCD_char('%');
        LCD_text_xy(8,8);
        show_char(n);   
        
        putchar(period_adc+'0');             // poslani hodnoty periody prevodu
        delay_ms(40);                        // zpozdeni - aby se data spolehlive precetla na pocitaci
                    
        a=temperature;                      // poslani dat po USB - teplota - tri znaky
        b=a/10000;
        a=a-b*10000;
        b=a/1000;
        a=a-b*1000;            
        b=a/100;
        putchar(b+'0');
        delay_ms(40);
        a=a-b*100;
        b=a/10;
        putchar(b+'0');
        delay_ms(40);      
        a=a-b*10;
        b=a;
        putchar(b+'0');
        delay_ms(40);      
                    
                    
for(n=0;n<100;n++)                 // poslani dat po USB - napeti - sto hodnot
{
        LCD_text_xy(8,8);
        show_char(n);               // zobrazeni procent                                             
                    
        a = voltage[n];             // napeti                    
        b=a/10000;
        a=a-b*10000;
        b=(a/1000);
        putchar(b+'0');
        delay_ms(40);               // cekani mezi jednotlivymi hodnotami - spolehlivy prenos dat
        a=a-b*1000;            
        b=(a/100);
        putchar(b+'0');
        delay_ms(40);
        a=a-b*100;
        b=(a/10);
        putchar(b+'0');
        delay_ms(40); 
        a=a-b*10;
        b=a;
        putchar(b+'0');
        delay_ms(40);              
}
      
      LCD_text_xy(7,8);            // 100%
      LCD_string("100");
      delay_ms(200);
}