#include <18F252.h>
#device ADC=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(crystal=20000000)
#define ADC0_EN   PIN_C2
#define ADC1_EN   PIN_C6

#INCLUDE 

#define LCD_ENABLE_PIN PIN_A0
#define LCD_RS_PIN PIN_A2
#define LCD_RW_PIN PIN_A1
#define LCD_DATA4 PIN_B4
#define LCD_DATA5 PIN_B5
#define LCD_DATA6 PIN_B6
#define LCD_DATA7 PIN_B7

#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H) 

#include 

char read_count=0;
char tick=0;
unsigned int32 adc_accum_v=0;
unsigned int32 adc_accum_i=0;

unsigned int16 adc0_ref=0;
unsigned int16 adc1_ref=0;

float rms_v=0;
float rms_i=0;

float rms_v_cor=1.04245;

float rms_v_accum=0;
float rms_i_accum=0;

float adc0_step=0;

unsigned int32 adc_value_v[41];
unsigned int32 adc_value_i[41];

unsigned int32 sampling_period=60536; // 65536-60536=5000 >> 5000x200ns=1ms 

float apparent_power=0;
float average_power_accum=0;
float vi_accum=0;

char i,k;

#INT_RTCC
void  RTCC_isr(void) 
{

set_rtcc(sampling_period);
tick=1;
read_count++;
return;
}

void initialize() {
   setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_64);
   lcd_init();
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);      //13.1 ms overflow
   
   output_high(ADC0_EN);
   output_high(ADC1_EN);
      
}


unsigned int16 mcp3202_read(char adc_no, char ch_no) {

   unsigned int16 reading = 0;
   unsigned char MSbyte=0x00;
   unsigned char LSbyte=0x00;


   // Chip Select
   if (adc_no==0) {output_low(ADC0_EN);}
   else {output_low(ADC1_EN);}

   // Send Start Bit
   Spi_Write(0x01);


   // Channel Select and Read High Byte
   if (ch_no==0) {MSbyte=Spi_Read(0xA0);}
   else {MSbyte=Spi_Read(0xE0);}


   // Read Low Byte
   LSbyte=Spi_Read(0x00);

   // Join the Bytes
   reading=make16((MSbyte & 0x0F),LSbyte);

   output_high(ADC0_EN);
   output_high(ADC1_EN);

   return reading;
}

void main()
{
   delay_ms(100);
   
   initialize();
   
   adc1_ref = 2048;
   adc0_ref = mcp3202_read(0,1);
   adc0_step = 2.5/adc0_ref;
   
   k=0;
   
   while (1) {
      
      set_rtcc(sampling_period);
      enable_interrupts(INT_RTCC);
      enable_interrupts(GLOBAL);
      
      while (read_count<40) {
      
         while(tick==0) {}
         tick=0;

         adc_value_v[read_count-1] = mcp3202_read(0,0);
         adc_value_i[read_count-1] = mcp3202_read(1,0);

      }
      
      
      disable_interrupts(INT_RTCC);
      disable_interrupts(GLOBAL);
      read_count=0;

     
      for (i=0;i<40;i++) {
         
         if (adc_value_v[i]>=adc0_ref) {adc_value_v[i] = adc_value_v[i] - adc0_ref;}
         else {adc_value_v[i] = adc0_ref - adc_value_v[i];}
         
         if (adc_value_i[i]>=adc1_ref) {adc_value_i[i] -= adc1_ref;}
         else {adc_value_i[i] = adc1_ref - adc_value_i[i];}
   
         
         adc_accum_v +=  (adc_value_v[i] * adc_value_v[i]); 
         adc_accum_i +=  (adc_value_i[i] * adc_value_i[i]);    
         
         vi_accum += ((adc_value_v[i]*adc0_step*201) * rms_v_cor) * (adc_value_i[i] * ((5/4096)/0.100))  ;
       }
      
      
      average_power_accum += vi_accum /40; 
      
      vi_accum=0;
      
      rms_v = ((sqrt(adc_accum_v /40))*adc0_step*201) * rms_v_cor ;
      rms_i = sqrt(adc_accum_i /40) * ((5/4096)/0.100);
      
      rms_v_accum += rms_v;
      rms_i_accum += rms_i;
      
      k++;
      
      if (k == 20) {
         k=0;
         
         printf(lcd_putc,"\f%3.1f V",(rms_v_accum/20));
         lcd_gotoxy(9,1);
         printf(lcd_putc,"%2.2f A",abs(((rms_i_accum/20) - 0.1)));
         
         lcd_gotoxy(5,2);
   
         printf(lcd_putc,"%4.1fW",average_power_accum/20);
         
         rms_v_accum=0;
         rms_i_accum=0;
         
         average_power_accum=0;
     }

      adc_accum_v=0;
      adc_accum_i=0;
      

      
   }

}