TrifasicEthernetEthercard
- include <EtherCard.h>
// ethernet interface mac address, must be unique on the LAN static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x06 }; static byte myip[] = { 192,168,130,6 }; static byte gwip[] = { 192,168,130,1 }; byte Ethernet::buffer[500]; BufferFiller bfill;
// The Animation loop is to provide some bling to the LCD diaplay
- define FILTERSETTLETIME 5000 // Time (ms) to allow the filters to settle before sending data
- define SERIALPRINT // include print statement for commissioning - comment this line to exclude
- define PHASE2 8 // Number of samples delay for L2
- define PHASE3 17 // Number of samples delay for L3, also size of array
- define RF69_COMPAT 0 // set to 1 to use RFM69CW
const int UNO = 0;
int inPinV = 6; int inPinI1 = 1; int inPinI2 = 4; int inPinI3 = 7; //Calibration coefficients - see http://openenergymonitor.org/emon/modules/emontx/firmware/calibration%20 //These need to be set in order to obtain accurate results double Vcal = 163.8; // Calibration - constant for voltage input - for ideal power voltage adapter double Ical1 = 60.6; // Calibration constant for current transformer 1 double Ical2 = 60.6; // Calibration constant for current transformer 2 double Ical3 = 60.6; // Calibration constant for current transformer 3 double Phasecal1 = 1.0; // Calibration constant for phase shift L1 double Phasecal2 = 1.6; // Calibration constant for phase shift L2 double Phasecal3 = 1.0; // Calibration constant for phase shift L3
//-------------------------------------------------------------------------------------- // Variable declaration for filters, phase shift, voltages, currents & powers //-------------------------------------------------------------------------------------- int lastSampleV,sampleV; //sample_ holds the raw analog read value, lastSample_ holds the last sample int lastSampleI1,sampleI1; int lastSampleI2,sampleI2; int lastSampleI3,sampleI3;
double lastFilteredV,filteredV; //Filtered_ is the raw analog value minus the DC offset double lastFilteredI1, filteredI1; double lastFilteredI2, filteredI2; double lastFilteredI3, filteredI3;
double phaseShiftedV1; //Holds the calibrated delayed & phase shifted voltage. double phaseShiftedV2; double phaseShiftedV3;
double sqV,sumV,sqI1,sumI1,sqI2,sumI2,sqI3,sumI3; double instP1,sumP1,instP2,sumP2,instP3,sumP3; //sq = squared, sum = Sum, inst = instantaneous
int startV; //Instantaneous voltage at start of sample window. int Vrms2;
double realPower1, // The final data
apparentPower1,
powerFactor1,
Irms1,
realPower2,
apparentPower2,
powerFactor2,
Irms2,
realPower3,
apparentPower3,
powerFactor3,
Irms3,
Vrms;
typedef struct { int power1, power2, power3, Vrms; } PayloadTX; // neat way of packaging data for RF comms
// (Include all the variables that are desired,
// ensure the same struct is used to receive)
PayloadTX emontx; // create an instance
const int LEDpin = 9; // On-board emonTx LED
boolean settled = false;
void calcVI3Ph(int cycles, int timeout) { int SupplyVoltage = readVcc(); int crossCount = 0; // Used to measure number of times threshold is crossed. int numberOfSamples = 0; // This is now incremented int numberOfPowerSamples = 0; // Needed because 1 cycle of voltages needs to be stored before use boolean lastVCross, checkVCross; // Used to measure number of times threshold is crossed. double storedV[PHASE3]; // Array to store >120 degrees of voltage samples
//------------------------------------------------------------------------------------------------------------------------- // 1) Waits for the waveform to be close to 'zero' (500 adc) part in sin curve. //------------------------------------------------------------------------------------------------------------------------- boolean st=false; // an indicator to exit the while loop
unsigned long start = millis(); // millis()-start makes sure it doesnt get stuck in the loop if there is an error.
while(st==false) // Wait for first zero crossing... { startV = analogRead(inPinV); // using the voltage waveform if ((startV < 550) && (startV > 440)) st=true; // check it's within range if ((millis()-start)>timeout) st = true; }
//------------------------------------------------------------------------------------------------------------------------- // 2) Main measurment loop //------------------------------------------------------------------------------------------------------------------------- start = millis();
while ((crossCount < cycles * 2) && ((millis()-start)<timeout)) {
lastSampleV=sampleV; // Used for digital high pass filter - offset removal lastSampleI1=sampleI1; lastSampleI2=sampleI2; lastSampleI3=sampleI3;
lastFilteredV = filteredV; lastFilteredI1 = filteredI1; lastFilteredI2 = filteredI2; lastFilteredI3 = filteredI3;
//----------------------------------------------------------------------------- // A) Read in raw voltage and current samples //----------------------------------------------------------------------------- sampleV = analogRead(inPinV); // Read in raw voltage signal sampleI1 = analogRead(inPinI1); // Read in raw current signal sampleI2 = analogRead(inPinI2); // Read in raw current signal sampleI3 = analogRead(inPinI3); // Read in raw current signal
//----------------------------------------------------------------------------- // B) Apply digital high pass filters to remove 2.5V DC offset (to centre wave on 0). //----------------------------------------------------------------------------- filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV); filteredI1 = 0.996*(lastFilteredI1+sampleI1-lastSampleI1); filteredI2 = 0.996*(lastFilteredI2+sampleI2-lastSampleI2); filteredI3 = 0.996*(lastFilteredI3+sampleI3-lastSampleI3);
storedV[numberOfSamples%PHASE3] = filteredV; // store this voltage sample in circular buffer
if (crossCount > 2) // one complete cycle has been stored, so can use delayed { // voltage samples to calculate instantaneous powers //----------------------------------------------------------------------------- // C) Root-mean-square method voltage //----------------------------------------------------------------------------- sqV= filteredV * filteredV; //1) square voltage values sumV += sqV; //2) sum
//----------------------------------------------------------------------------- // D) Root-mean-square method current //----------------------------------------------------------------------------- sqI1 = filteredI1 * filteredI1; //1) square current values sumI1 += sqI1; //2) sum sqI2 = filteredI2 * filteredI2; sumI2 += sqI2; sqI3 = filteredI3 * filteredI3; sumI3 += sqI3;
//----------------------------------------------------------------------------- // E) Phase calibration - for Phase 1: shifts V1 to correct transformer errors // for phases 2 & 3 delays V1 by 120 degrees & 240 degrees respectively // and shifts for fine adjustment and to correct transformer errors. //----------------------------------------------------------------------------- phaseShiftedV1 = lastFilteredV + Phasecal1 * (filteredV - lastFilteredV); phaseShiftedV2 = storedV[(numberOfSamples-PHASE2-1)%PHASE3] + Phasecal2 * (storedV[(numberOfSamples-PHASE2)%PHASE3] - storedV[(numberOfSamples-PHASE2-1)%PHASE3]); phaseShiftedV3 = storedV[(numberOfSamples+1)%PHASE3] + Phasecal3 * (storedV[(numberOfSamples+2)%PHASE3] - storedV[(numberOfSamples+1)%PHASE3]);
//-----------------------------------------------------------------------------
// F) Instantaneous power calc
//-----------------------------------------------------------------------------
instP1 = phaseShiftedV1 * filteredI1; //Instantaneous Power
sumP1 +=instP1; //Sum
instP2 = phaseShiftedV2 * filteredI2;
sumP2 +=instP2;
instP3 = phaseShiftedV3 * filteredI3;
sumP3 +=instP3;
numberOfPowerSamples++; //Count number of times looped for Power averages.
}
//----------------------------------------------------------------------------- // G) Find the number of times the voltage has crossed the initial voltage // - every 2 crosses we will have sampled 1 wavelength // - so this method allows us to sample an integer number of half wavelengths which increases accuracy //----------------------------------------------------------------------------- lastVCross = checkVCross; if (sampleV > startV) checkVCross = true; else checkVCross = false; if (numberOfSamples==1) lastVCross = checkVCross;
if (lastVCross != checkVCross) crossCount++;
numberOfSamples++; //Count number of times looped.
}
//------------------------------------------------------------------------------------------------------------------------- // 3) Post loop calculations //------------------------------------------------------------------------------------------------------------------------- //Calculation of the root of the mean of the voltage and current squared (rms) //Calibration coefficients applied.
double V_Ratio = Vcal *((SupplyVoltage/1000.0) / 1023.0); Vrms = V_Ratio * sqrt(sumV / numberOfPowerSamples);
double I_Ratio1 = Ical1 *((SupplyVoltage/1000.0) / 1023.0); Irms1 = I_Ratio1 * sqrt(sumI1 / numberOfPowerSamples); double I_Ratio2 = Ical2 *((SupplyVoltage/1000.0) / 1023.0); Irms2 = I_Ratio2 * sqrt(sumI2 / numberOfPowerSamples); double I_Ratio3 = Ical3 *((SupplyVoltage/1000.0) / 1023.0); Irms3 = I_Ratio3 * sqrt(sumI3 / numberOfPowerSamples);
//Calculation power values realPower1 = V_Ratio * I_Ratio1 * sumP1 / numberOfPowerSamples; apparentPower1 = Vrms * Irms1; powerFactor1 = realPower1 / apparentPower1;
realPower2 = V_Ratio * I_Ratio2 * sumP2 / numberOfPowerSamples; apparentPower2 = Vrms * Irms2; powerFactor2 = realPower2 / apparentPower2;
realPower3 = V_Ratio * I_Ratio3 * sumP3 / numberOfPowerSamples; apparentPower3 = Vrms * Irms3; powerFactor3 = realPower3 / apparentPower3;
//Reset accumulators sumV = 0; sumI1 = 0; sumI2 = 0; sumI3 = 0; sumP1 = 0; sumP2 = 0; sumP3 = 0; //--------------------------------------------------------------------------------------
// Include these statements for development/debugging only. Not used Gerard /*#ifdef DEBUGGING
Serial.print("Total Samples: "); Serial.print(numberOfSamples); Serial.print(" Power Samples: "); Serial.print(numberOfPowerSamples); Serial.print(" Time: "); Serial.print(millis() - start); Serial.print(" Crossings: "); Serial.println(crossCount);
for (int j=0; j<PHASE3; j++) { Serial.print(storedV[j]); Serial.print(" "); Serial.println(); }
- endif*/
}
//*********************************************************************************************************************
long readVcc() {
long result; ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); ADCSRA |= _BV(ADSC); while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = 1126400L / result; return result;
}
// Setup - bring Ethernet, LCD and DHT11 live
void setup () {
Serial.begin(9600); if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0) Serial.println( "Failed to access Ethernet controller"); ether.staticSetup(myip, gwip);
}
// Here we build a web page and pass the t and h values into it
static word homePage() {
//ReadDHT11();
bfill = ether.tcpOffset(); bfill.emit_p(PSTR( "HTTP/1.0 200 OK\r\n" "Content-Type: text/html\r\n" "\r\n" "$T L1 $T $T $T $T L2 $T $T $T $T L3 $T $T $T $T"), Vrms, Irms1, realPower1, apparentPower1, powerFactor1, realPower2, apparentPower2, powerFactor2, Irms2, realPower3, apparentPower3, powerFactor3, Irms3); return bfill.position();
}