TrifasicEthernetEthercard: diferència entre les revisions

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

Revisió del 08:43, 27 oct 2015


  1. 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

  1. define FILTERSETTLETIME 5000 // Time (ms) to allow the filters to settle before sending data
  2. define SERIALPRINT // include print statement for commissioning - comment this line to exclude
  3. define PHASE2 8 // Number of samples delay for L2
  4. define PHASE3 17 // Number of samples delay for L3, also size of array
  5. 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(); }

  1. 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();

}