/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.9 Professional
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : 
Version : 
Date    : 18.05.2009 - **.**.2009
Author  : LINKS_234 (Шимко А.В.)                     
Company :                            
Comments: Ваттметр 


Chip type           : ATmega8
Program type        : Application
Clock frequency     : 8,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/

#include <mega8.h>
#include <delay.h> 
#include <stdio.h>
#include <math.h>

#define RS PORTB.0  
#define E PORTB.1 
#define us delay_us
#define ms delay_ms  

 // глобальные переменные ...

bit znak=1; // переменная для определения знака "косинуса" , при выводе данных на ЖКИ не используется.
bit cycle=0;  /* счётчик для определения первого преобразования 
(оно длится больше чем последующие ).впринципе это не критично к данной
 программе ,но пусть лучше так будет .                    
 */      

unsigned long int sqr_summ_U=0;   //переменная для интегрирования измеренных значений напряжения 
unsigned long int sqr_summ_A=0;   // --//-- тока   

unsigned char clk_U=0;          //подсчёт числа преобразований напряжения и тока
unsigned char clk_A=0;

unsigned char flag_U=0; //флаг для считывания перехода фазы через ноль для напруги и тока соотв.
unsigned char flag_A=0;
unsigned char my_timer=0;



unsigned int timer_U=0; //время  перехода через ноль напруги
unsigned int timer_A=0;  // время перехода через ноль тока  


        unsigned char S_o[4];     
        unsigned char P_o[4];
        unsigned char Q_o[4]; 
        unsigned char cos_fi_o[2];
          
        
unsigned int S=0;
unsigned int u=0;
unsigned int a=0;   
unsigned int P=0;    
unsigned int aprox_S=0;
unsigned int aprox_P=0;
unsigned int aprox_Q=0;
unsigned int aprox_fi=0;

unsigned long int P_temp=0;
unsigned long int Q_temp=0;
unsigned long int S_temp=0;
unsigned int Q=0;
unsigned int timer=0;
 
unsigned int cos_fi=0;
unsigned int sin_fi=0;
unsigned long int adc_data=0; //для результата АЦП 


void ini_lcd(void);       // инициализация ЖКИ
void lcd_data(unsigned char data);    // вывод данных на ЖКИ
void lcd_command(unsigned char cmd);  // отправление команд на ЖКИ 
unsigned int my_cos(unsigned char fi);







///////////////////////////////////////////////////////////////////////
/////////////////////   ПРЕРЫВАНИЕ АЦП   //////////////////////////////
///////////////////////////////////////////////////////////////////////

interrupt [ADC_INT] void adc_isr(void)      // не запускаются последующие преобразования почему-то . 
{

if (TCNT1<0xFC17)    // проверяем счётчик на значение до переполнения
{
TCNT0=0xA5;
adc_data=ADCW;    // генератор кода вставил эту строку . по-моему совсем лишняя , но хрен с ней - памяти у МК много ещё :)
   
        if (cycle==1)    // последующий цикл после начала преобразования
        {  
                if (ADMUX==0xC1)        //напряжение или ток меряем, мониторим 0хС1 потому как
                                        //преобразования запаздывают за переключением канала
                                        //по сути без разницы что из них что, 
                                        //тут главное в программе не запутаться  
                {
                //  ADMUX|=0x01;  // перещёлкиваем на ADC1     
                clk_U++;
                sqr_summ_U+=(adc_data*adc_data);                
                
                
                
                
                        /*
                        опеределение перехода синусоиды через ноль                        
                        */
                        if ((adc_data>3)&&(flag_U==0))
                                {
                                flag_U=1;
                                };
                        if ((flag_U==1)&&(adc_data<2))
                                {
                                timer_U=TCNT1;
                                flag_U=3;
                                };
                
                //us(120); // задержка после перещёлкивания для уверенности в отсутствии погрешностей при перещёдкивании                            
                }
                else 
                {
                //  ADMUX&=0xFE;    // перещёлкиваем на ADC0
                clk_A++;
                sqr_summ_A+=(adc_data*adc_data);
                        
                
                
                        /*
                        опеределение перехода синусоиды через ноль                        
                        */
                        if ((adc_data>3)&&(flag_A==0))
                                {
                                flag_A=1;
                                };
                        if ((flag_A==1)&&(adc_data<2))
                                {
                                timer_A=TCNT1;
                                flag_A=3;
                                };
                
                }; 
        
        }
        else 
        { 
        TCCR0=0x02;        // запуск таймера0 (он щёлкает канал АЦП до конца преобразования)
        ADCSRA|=0x20;      // free runing mode
         
        cycle=1;           // последующий цикл
        adc_data=0;        // обнуление переменной . на всякий случай
        TCNT1=0xADF7;      // установка значения таймера на отсчёт 21мс до переполнения
                    
        ADCSRA|=0x40;      //запуск преобразования в автоматич. режиме 
        TCNT0=0xA5;        // установка значения таймера0 на отсчёт 90мкс
        TCCR1B=0x02;       // установка деления частоты на 8 (запуск таймера)  
        ADMUX|=0x01;       // сразу после запуска АЦП щёлкаем канал , дабы потом в обработке данных не было косяков
        };  
        


}
else         
{
TCCR0=0x00;
ADCSRA&=0xDF;     //останавливаем преобразования
};  

}



///////////////////////////////////////////////////////////////////////
/////////////////////   ПРЕРЫВАНИЕ ТАЙМЕРА-0   ////////////////////////
///////////////////////////////////////////////////////////////////////



interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
ADMUX^=0x01;
}


///////////////////////////////////////////////////////////////////////
/////////////////////   ПРЕРЫВАНИЕ ТАЙМЕРА-1   ////////////////////////
///////////////////////////////////////////////////////////////////////


interrupt [TIM1_OVF] void timer1_ovf_isr(void)          // переполнение таймера
{ 
 




ADCSRA|=0x20;    //устанавливаем обратно бит ADFR (free runing mode)

if ((sqr_summ_U!=0)&&(sqr_summ_A!=0)&&(clk_U!=0)&&(clk_A!=0))
{
sqr_summ_U*=2;
sqr_summ_U/=clk_U;     
sqr_summ_U=sqrt(sqr_summ_U);
sqr_summ_U*=364;                   
u=sqr_summ_U/1024;

sqr_summ_A*=2;
sqr_summ_A/=clk_A;
sqr_summ_A=sqrt(sqr_summ_A);            
sqr_summ_A*=366;                         
a=sqr_summ_A/1024;


S_temp=(a*u);
S=S_temp/10;         


}
else
{
S=0;
};

 // ADF7
 
if (S!=0) //&&(timer_U!=0)&&(timer_A!=0))
{
        if (timer_U<timer_A)
        {
        timer=(timer_A-timer_U);
                if (timer>5000)
                {
                timer=20000-timer;
                znak=1;
                }
                else
                {
                znak=0;
                };

        }
        else
        {
        timer=(timer_U-timer_A);
                if(timer>5000)
                {
                timer=20000-timer;
                znak=0;
                }
                else
                { 
                znak=1;
                };

        }; 
           
timer=(timer/55);
cos_fi=my_cos(timer);     
timer=90-timer;
sin_fi=my_cos(timer);
P_temp=(long)S*cos_fi;  
P=P_temp/10000;    
Q_temp=(long)S*sin_fi;
Q=Q_temp/10000;
}
else
{ 
P=0;
Q=0;
cos_fi=0;
}; 

if (my_timer<15)
{
aprox_S+=S;
aprox_P+=P;
aprox_Q+=Q;
//timer=90-timer;
//aprox_fi+=timer;
aprox_S/=2;
aprox_P/=2;
aprox_Q/=2;
aprox_fi=90-timer; //aprox_fi/=2;
my_timer++;

TCNT1=0xADF7;
ADCSRA|=0x40;
TCCR0=0x02;
TCNT0=0xA5;
};
 
clk_U=0;
clk_A=0; 
timer_U=0;
timer_A=0; 
sqr_summ_A=0;
sqr_summ_U=0;  
flag_U=0;
flag_A=0;

}

///////////////////////////////////////////////////////////////////////
/////////// Таблица косинусов (синусов=90-косинус) ////////////////////
///////////////////////////////////////////////////////////////////////
 

unsigned int my_cos(unsigned char fi)
{ 

unsigned int cos;

switch (fi)
{ 
case 0:cos=10000;break;
case 1:cos=9998;break;
case 2:cos=9994;break;
case 3:cos=9986;break;
case 4:cos=9976;break;
case 5:cos=9962;break;
case 6:cos=9945;break;
case 7:cos=9925;break;
case 8:cos=9903;break;
case 9:cos=9877;break;
case 10:cos=9848;break;
case 11:cos=9816;break;
case 12:cos=9781;break;
case 13:cos=9744;break;
case 14:cos=9703;break;
case 15:cos=9659;break;
case 16:cos=9613;break;
case 17:cos=9563;break;
case 18:cos=9511;break;
case 19:cos=9455;break;
case 20:cos=9397;break;
case 21:cos=9336;break;
case 22:cos=9272;break;
case 23:cos=9205;break;
case 24:cos=9135;break;
case 25:cos=9063;break;
case 26:cos=8988;break;
case 27:cos=8910;break;
case 28:cos=8829;break;
case 29:cos=8746;break;
case 30:cos=8660;break;
case 31:cos=8572;break;
case 32:cos=8480;break;
case 33:cos=8387;break;
case 34:cos=8290;break;
case 35:cos=8192;break;
case 36:cos=8090;break;
case 37:cos=7986;break;
case 38:cos=7880;break;
case 39:cos=7771;break;
case 40:cos=7660;break;
case 41:cos=7547;break;
case 42:cos=7431;break;
case 43:cos=7314;break;
case 44:cos=7193;break;
case 45:cos=7071;break;        
case 46:cos=6947;break;
case 47:cos=6820;break;
case 48:cos=6691;break;
case 49:cos=6561;break;
case 50:cos=6428;break;
case 51:cos=6293;break;
case 52:cos=6157;break;
case 53:cos=6018;break;
case 54:cos=5878;break;
case 55:cos=5736;break;
case 56:cos=5592;break;
case 57:cos=5446;break;
case 58:cos=5299;break;
case 59:cos=5150;break;
case 60:cos=5000;break;
case 61:cos=4848;break;
case 62:cos=4695;break;
case 63:cos=4540;break;
case 64:cos=4384;break;
case 65:cos=4226;break;
case 66:cos=4067;break;
case 67:cos=3907;break;
case 68:cos=3746;break;
case 69:cos=3584;break;
case 70:cos=3420;break;
case 71:cos=3256;break;
case 72:cos=3090;break;
case 73:cos=2924;break;
case 74:cos=2756;break;
case 75:cos=2588;break;
case 76:cos=2419;break;
case 77:cos=2250;break;
case 78:cos=2079;break;
case 79:cos=1908;break;
case 80:cos=1736;break;
case 81:cos=1564;break;
case 82:cos=1392;break;
case 83:cos=1219;break;
case 84:cos=1045;break;
case 85:cos=872;break;
case 86:cos=698;break;
case 87:cos=523;break;
case 88:cos=349;break;
case 89:cos=175;break;
case 90:cos=0;break;

}
return cos;
}
    
///////////////////////////////////////////////////////////////////////
/////////////////////   Инициализация ЖКИ   ////////////////////////
///////////////////////////////////////////////////////////////////////

void ini_lcd(void)     
{         


ms(60);    //  задержка . не мешает и ладно :) польза сомнительна :)
RS=0;  // перерубаем на всякий случай вход ЛСД на команды 
us(10);  // на всякий 

// 0x30 command    
// команда 8-мибитная устанавливающая контроллер ЖКИ в восьмибитный режим
E=1;
us(10);
PORTC|=(0b00110000>>2);  
us(10);
E=0;
us(10);
PORTC&=(~(0b00110000>>2));  //delete from port command 0x30 
ms(10);

// 0x30 command 
//аналогичная вышеидущей 
E=1;
us(10);
PORTC|=(0b00110000>>2);  
us(10);
E=0;
us(10);
PORTC&=(~(0b00110000>>2));  //delete from port command 0x30 
ms(5); 

// 0x30 command 
// третий раз
E=1;
us(10);
PORTC|=(0b00110000>>2); 
us(10);
E=0;
us(10);
PORTC&=(~(0b00110000>>2));  //delete from port command 0x30 
us(10);    

// send command 0x20 
// 8-мибитная команда установки 4-битного режима общения
E=1;
us(10);
PORTC|=(0b00100000>>2);  
us(10);
E=0;
us(10);
PORTC&=(~(0b00100000>>2)); //delete from port command 0x20
us(10);  

//send command 0x28  
// режим в 2 строки и символы 5*8
lcd_command(0x28);
/*
E=1;
us(1);      
PORTC|=(0b00100000>>2);  
us(1);
E=0;
us(1);
PORTC&=(~(0b00100000>>2)); 
us(1);
E=1;
us(1);
PORTC|=(0b00001000<<2);
us(1);
E=0;
us(1);
PORTC&=(~(0b00001000<<2));
us(1);
*/

//send command 0x08 
//выкл ЖКИ 
lcd_command(0x08);
/*
E=1;
us(5);
E=0;
us(5);
E=1;
us(1);
PORTC|=(0b00001000<<2);
us(1);
E=0;
us(1);
PORTC&=(~(0b00001000<<2));
us(1);
*/

//send command 0x01   
// очистка ЖКИ
lcd_command(0x01); 
/*
E=1;
us(5);
E=0;
us(5);
E=1;
us(1);
PORTC|=(0b00000001<<2);
us(1);
E=0;
us(1);
PORTC&=(~(0b00000001<<2);
us(1); 
*/

//command 0x06 
lcd_command(0x06);
/*
E=1;
us(5);
E=0;
us(5);
E=1;
us(1);
PORTC|=(0b00000110<<2);
us(1);
E=0;
us(1);
PORTC&=(~(0b00000110<<2));
us(1);  
*/

//command 0x0C  
lcd_command(0x0C);
/*
E=1;
us(5);
E=0;
us(5);
E=1;
us(1);
PORTC|=(0b00001100<<2);
us(1);
E=0;
us(1);
PORTC&=(~(0b00001100<<2));
us(1); 
*/

//command 0x02  
// Return Home 
lcd_command(0x02);
/*   
E=1;
us(5);
E=0;
us(5);
E=1;
us(1);
PORTC|=(0b00000010<<2);
us(1);
E=0;
us(1);
PORTC&=(~(0b00000010<<2));
us(10);
*/

} 

///////////////////////////////////////////////////////////////////////
////////////////// Трансляция Комманд на ЖКИ   ////////////////////////
///////////////////////////////////////////////////////////////////////

void lcd_command(unsigned char cmd) 
{
RS=0;
us(10);
E=1;
us(10);
PORTC=(PORTC&0b11000011)|(cmd>>2); // обнуляем ноги данных и пуляем на них старшую тетраду команды
us(10);
E=0;
us(10);
PORTC&=(~(cmd>>2));
us(10);
E=1;
us(10);
PORTC=(PORTC&0b11000011)|(cmd<<2);   // обнуляем ноги данных и пуляем на них младшую тетраду команды
us(10);
E=0;
us(10);
PORTC&=(~(cmd<<2)); 
ms(2);
} 

///////////////////////////////////////////////////////////////////////
///////////////////// Трансляция данных на ЖКИ   //////////////////////
///////////////////////////////////////////////////////////////////////

void lcd_data(unsigned char data)   
{  

RS=1;
us(5);
E=1;
us(1);
PORTC=(PORTC&0b11000011)|(data>>2);  
us(1);
E=0;
us(1);
PORTC&=(~(data>>2));
us(1);
E=1;
us(1);
PORTC=(PORTC&0b11000011)|(data<<2);
us(1);
E=0;
us(1);
PORTC&=(~(data<<2)); 
us(100);
}





///////////////////////////////////////////////////////////////////////
/////////////////////  Основная подпрограмма   ////////////////////////
///////////////////////////////////////////////////////////////////////

void main(void)  
{     
unsigned char create[16]={'C','R','E','A','T','E','D',0x20,'b','y',0x20,'L','I','N','K','S'};  
unsigned char kot[32]={0x20,0x20,'S','P','E','C','I','A','L',0x20,'F','O','R',0x20,0x20,0x20,0x20,0x20,'R','A','D','I','O','K','O','T','.','R','U',0x20,0x20,0x20};
//unsigned char dipl[32]={0xD0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xdA,0xdB,0xdC,0xdD,0xdE,0xdF,0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xeA,0xeB,0xeC,0xeD,0xeE,0xeF}; 
//////////////////////////                                                                                  Д    Ц    Щ    д    ф    ц    щ
//unsigned char dipl[32]={0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF};
//////////////////////////                                                                                  ч    ш    ъ    ы    ь    э   ю    я      
//unsigned char dipl[32]={0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF};
////////////////////////// Б    Г    Ё    Ж    З    И    Й    Л    П    У     Ф    Ч    Ш    Ъ   Ы    Э     Ю    Я    б   в     г    ё    ж   з     и    й    к    л    м    н    п   т 
unsigned char i=0;

PORTB=0b00000000;
DDRB=0b00000011;

PORTC=0b00000000;       // pullup - 0-no 1-yes , output - 0-low , 1-high
DDRC=0b00111100;        // вход-выход порта С     0-input  1- output

PORTD=0b00000000;       
DDRD=0b00000000;

TCCR0=0x00;
TCNT0=0x00;

TCCR1A=0x00;

TCCR1B=0x00;  

TCNT1H=0x00;
TCNT1L=0x00;

ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;

OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
            

ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

MCUCR=0x00;  // sleep  и прерывания внешние 

TIMSK=0x05;     // разрешение прерывания таймеров .

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;   

ADMUX=0b11000000;  //  ИОН , выравнивание , канал АЦП 
ADCSRA=0x8E; // вкл/выкл АЦП , запуск конвертации , прерывания , делитель частоты



ini_lcd(); 

for (i=0;i<16;i++)
{
lcd_data(create[i]);
}                   
ms(1000);
lcd_command(0x01);

for (i=0;i<32;i++)
{  
if (i==16)
{
lcd_command(0xC0);
};

lcd_data(kot[i]);

};
ms(3000);


ADCSRA|=0x40;     // запуск конвертации      
#asm("sei");
while (1)
{   
        if(my_timer==15)
        {



        lcd_command(0x01);      


        sprintf(S_o,"%04u",aprox_S);  
        sprintf(P_o,"%04u",aprox_P); 
        sprintf(Q_o,"%04u",aprox_Q); 
        sprintf(cos_fi_o,"%02u",aprox_fi);     


        // полная моща 
        lcd_data('S');
        lcd_data('=');
        for (i=0;i<4;i++)
                {  
                if (i==3)
                        {
                        lcd_data(',');
                        };
                lcd_data(S_o[i]);
                };

        lcd_data(0x20);
        lcd_data('P');
        lcd_data('=');

        // активная моща 
        for (i=0;i<4;i++)
                {
                if (i==3)
                        {
                        lcd_data(',');
                        };
                lcd_data(P_o[i]);
                };

        lcd_command(0xC0);  
        lcd_data('Q');
        lcd_data('=');

        // реактивная моща 
        for (i=0;i<4;i++)
                {
                if (i==3)
                        {
                        lcd_data(',');
                        };
                lcd_data(Q_o[i]);
                };

        lcd_data(0x20);
        lcd_data('f');
        lcd_data('i');
        lcd_data('=');

        // косинус фи 
        if (znak==1)
                {
                lcd_data('-');
                };
        for (i=0;i<2;i++)
                {
                lcd_data(cos_fi_o[i]);
                }; 
                   
        my_timer=0;        
        TCNT1=0xADF7;
        ADCSRA|=0x40;
        TCCR0=0x02;
        TCNT0=0xA5;
        };


};
}
