TrifasicEthernetEthercard

De Comissió Energia Can Fugarolas
Salta a la navegació Salta a la cerca


  #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();
  }