// Power Line 3rd Harmonic Meter // Hardware: PIC18F2550 PIC project board // Fuse settings: 4MHz, no divide CPU clock, 4MHz input // The hex file is ready to be loaded by PICkit II // Ananlog input 0-5Vpeak fullwave 50Hz AC signal // Alarm when distortion >3% // source code was compiled with Mikro-C compiler // Copyright 2006-9 Wichit Sirichote, kswichit@kmitl.ac.th #define ADC_CS1 PORTC.F0 // output bit #define ADC_SDO PORTC.F1 // input bit #define ADC_SCK PORTC.F2 // output bit #define protect1 PORTC.F7 // test indicator #define protect PORTC.F6 // output protect #define on 0 #define off 1 // change the maximum distortion here // IEEE 519-1992 for low voltage THDV is 5% #define max 5.0 char *text = "Power Line 3rd"; char *text2 = "Harmonic Meter"; short alarm=0; short overload=0; const float sine[] = { 0, 0.098016374, 0.195088811, 0.290282466, 0.382680585, 0.47139334, 0.55556639, 0.634389115, 0.707102423, 0.773006055, 0.831465332, 0.881917269, 0.923875995, 0.956937428, 0.980783176, 0.995183594, 1, 0.99518601, 0.980787986, 0.956944585, 0.923885429, 0.881928891, 0.831479029, 0.773021695, 0.707119856, 0.634408173, 0.555586888, 0.471415082, 0.382703362, 0.290306057, 0.195112991, 0.098040908}; const float cosine[]={ 1, 0.995184802, 0.980785581, 0.956941007, 0.923880712, 0.88192308, 0.83147218, 0.773013875, 0.707111139, 0.634398644, 0.555576639, 0.471404211, 0.382691974, 0.290294261, 0.195100901, 0.098028641, 1.23268E-05, -0.098004106, -0.195076721, -0.290270669, -0.382669197, -0.471382468, -0.55555614, -0.634379586, -0.707093707, -0.772998234, -0.831458483, -0.881911458, -0.923871277, -0.95693385, -0.980780771, -0.995182385}; const float sinex3[]={ 0, 0.290282466, 0.55556639, 0.773006055, 0.923875995, 0.995183594, 0.980787986, 0.881928891, 0.707119856, 0.471415082, 0.195112991, -0.097991839, -0.382657808, -0.634370058, -0.831451635, -0.956930271, -0.999999999, -0.956951741, -0.831492725, -0.63442723 , -0.382726139, -0.098065443, 0.195040451, 0.471349854, 0.707067556, 0.881894025, 0.980773555, 0.995190841, 0.923904296, 0.773052973, 0.555627884, 0.290353241}; const float cosinex3[]={ 1, 0.956941007, 0.83147218, 0.634398644, 0.382691974, 0.098028641, -0.195076721, -0.471382468, -0.707093707, -0.881911458, -0.980780771, -0.995187218, -0.923890146, -0.773029514, -0.555597137, -0.290317853, -3.69804E-05, 0.290247077 , 0.555535641, 0.772982594, 0.923861842, 0.995179968, 0.980795199, 0.881946322, 0.707146004, 0.471447695, 0.19514926, -0.097955036, -0.382623642, -0.63434147, -0.831431088, -0.956919535}; const float inputsine[]={ 0, 30.38507582, 60.47753134, 89.98756431, 118.6309814, 146.1319353, 172.2255807, 196.6606258, 219.2017511, 239.6318769, 257.7542529, 273.3943535, 286.4015583, 296.6506028, 304.0427846, 308.5069141, 310, 308.5076632, 304.0442756, 296.6528213, 286.404483, 273.3979562, 257.7584989, 239.6367253, 219.2071552, 196.6665335, 172.2319353, 146.1386754, 118.6380423, 89.99487781, 60.48502709, 30.39268162, }; const float inputsquare[]={ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9 , 8, 8, 8, 8, 7, 7, 7, }; unsigned int read_ADC() { unsigned int temp; temp =0; ADCON0 = 0x03; // start ADC while(ADCON0&0x02) // wait unitl done continue; temp = ADRESH; temp <<=8; return (temp|ADRESL); } float xin[32]; void capture_input() { int i; char buffer[32]; if(alarm) {Lcd_Out(1,15,"><"); } else Lcd_Out(1,15,"--"); Delay_ms(200); if(overload) Lcd_Out(1,10,"ov"); else Lcd_Out(1,10," "); // finding start with cycle limit for(i=0; read_ADC()>3 && i<64; i++) continue; for(i=0; i<32; i++) { xin[i] = read_ADC(); //Delay_us(104); //50); //312); //(312); // for 10ms/32 } // tested delay value for 0 to 180 degrees with 32 samples overload=0; for(i=0; i<32; i++) { if(xin[i]>1010) overload=1; } /* for(i=0; i<32; i++) { sprintf(buffer,"ADC(%d)= %f",i,xin[i]); Lcd_Cmd(LCD_FIRST_ROW); Lcd_Out_CP(buffer); Delay_ms(3000); } */ } void compute_THD() { char i; char buffer[32]; float n=0; float k=0; float nx3=0; float kx3=0; float THD; Lcd_Out(1,15," "); Delay_ms(100); for(i=0; i<32; i++) { n+= sine[i]*xin[i]*0.31; // input * fundamental k+= cosine[i]*xin[i]*0.31; // 1000 = 310V nx3+= sinex3[i]*xin[i]*0.31; // input * 3rd harmonic kx3+= cosinex3[i]*xin[i]*0.31; } n = sqrt(n*n+k*k); n=(4*0.0003125/0.02)*n; // compute amplitude of fundamental frequency nx3 = sqrt(nx3*nx3+kx3*kx3); nx3=(4*0.0003125/0.02)*nx3; // compute amplitude of 3rd harmonic THD = nx3*100/n; // compute %THD 3rd/fundamental // if %THD >10 or 1st harmonic amplitude <20 then shutdown if (THD>max || n <20) { protect = protect1= on; alarm=1; } else { protect = protect1=off; alarm=0; } sprintf(buffer,"Fund=%.0f",n); Lcd_Cmd(LCD_FIRST_ROW); Lcd_Out_CP(buffer); sprintf(buffer,"3rd=%.0f",nx3); Lcd_Cmd(LCD_SECOND_ROW); Lcd_Out_CP(buffer); sprintf(buffer,"HD=%.1f%% ",THD); Lcd_Out(2,9,buffer); } void main() { Delay_ms(200); ADCON1 = 0x0E; // ADC0 = analog input ADCON0 = 0x00; // select channel 0 ADCON2 = 0x92; // ADC frequency = FOSC/32 TRISA = 0xFF; // PORTA is input TRISB = 0; // PORTB is output PORTC = 0xFF; TRISC = 0x02; // PORTC is output port protect = protect1= on; protect = protect1=off; Lcd_Init(&PORTB); // Initialize LCD connected to PORTB Lcd_Cmd(Lcd_CLEAR); // Clear display Lcd_Cmd(Lcd_CURSOR_OFF); // Turn cursor off Lcd_Out(1, 1,text); Lcd_Out(2, 1,text2); Delay_ms(3000); Lcd_Cmd(Lcd_Clear);Lcd_Cmd(Lcd_Clear); while(1) { capture_input(); compute_THD(); } }