first commit
This commit is contained in:
269
libraries/EmonLib/EmonLib.cpp
Normal file
269
libraries/EmonLib/EmonLib.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
Emon.cpp - Library for openenergymonitor
|
||||
Created by Trystan Lea, April 27 2010
|
||||
GNU GPL
|
||||
modified to use up to 12 bits ADC resolution (ex. Arduino Due)
|
||||
by boredman@boredomprojects.net 26.12.2013
|
||||
Low Pass filter for offset removal replaces HP filter 1/1/2015 - RW
|
||||
*/
|
||||
|
||||
// Proboscide99 10/08/2016 - Added ADMUX settings for ATmega1284 e 1284P (644 / 644P also, but not tested) in readVcc function
|
||||
|
||||
//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
|
||||
#include "EmonLib.h"
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Sets the pins to be used for voltage and current sensors
|
||||
//--------------------------------------------------------------------------------------
|
||||
void EnergyMonitor::voltage(unsigned int _inPinV, double _VCAL, double _PHASECAL)
|
||||
{
|
||||
inPinV = _inPinV;
|
||||
VCAL = _VCAL;
|
||||
PHASECAL = _PHASECAL;
|
||||
offsetV = ADC_COUNTS>>1;
|
||||
}
|
||||
|
||||
void EnergyMonitor::current(unsigned int _inPinI, double _ICAL)
|
||||
{
|
||||
inPinI = _inPinI;
|
||||
ICAL = _ICAL;
|
||||
offsetI = ADC_COUNTS>>1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Sets the pins to be used for voltage and current sensors based on emontx pin map
|
||||
//--------------------------------------------------------------------------------------
|
||||
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
|
||||
{
|
||||
inPinV = 2;
|
||||
VCAL = _VCAL;
|
||||
PHASECAL = _PHASECAL;
|
||||
offsetV = ADC_COUNTS>>1;
|
||||
}
|
||||
|
||||
void EnergyMonitor::currentTX(unsigned int _channel, double _ICAL)
|
||||
{
|
||||
if (_channel == 1) inPinI = 3;
|
||||
if (_channel == 2) inPinI = 0;
|
||||
if (_channel == 3) inPinI = 1;
|
||||
ICAL = _ICAL;
|
||||
offsetI = ADC_COUNTS>>1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// emon_calc procedure
|
||||
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kWh increment
|
||||
// From a sample window of the mains AC voltage and current.
|
||||
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
|
||||
//--------------------------------------------------------------------------------------
|
||||
void EnergyMonitor::calcVI(unsigned int crossings, unsigned int timeout)
|
||||
{
|
||||
#if defined emonTxV3
|
||||
int SupplyVoltage=3300;
|
||||
#else
|
||||
int SupplyVoltage = readVcc();
|
||||
#endif
|
||||
|
||||
unsigned int crossCount = 0; //Used to measure number of times threshold is crossed.
|
||||
unsigned int numberOfSamples = 0; //This is now incremented
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------
|
||||
// 1) Waits for the waveform to be close to 'zero' (mid-scale 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) //the while loop...
|
||||
{
|
||||
startV = analogRead(inPinV); //using the voltage waveform
|
||||
if ((startV < (ADC_COUNTS*0.55)) && (startV > (ADC_COUNTS*0.45))) {
|
||||
st=true; //check its within range
|
||||
}
|
||||
if ((millis()-start)>timeout) st = true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------
|
||||
// 2) Main measurement loop
|
||||
//-------------------------------------------------------------------------------------------------------------------------
|
||||
start = millis();
|
||||
|
||||
while ((crossCount < crossings) && ((millis()-start)<timeout))
|
||||
{
|
||||
numberOfSamples++; //Count number of times looped.
|
||||
lastFilteredV = filteredV; //Used for delay/phase compensation
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) Read in raw voltage and current samples
|
||||
//-----------------------------------------------------------------------------
|
||||
sampleV = analogRead(inPinV); //Read in raw voltage signal
|
||||
sampleI = analogRead(inPinI); //Read in raw current signal
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// B) Apply digital low pass filters to extract the 2.5 V or 1.65 V dc offset,
|
||||
// then subtract this - signal is now centred on 0 counts.
|
||||
//-----------------------------------------------------------------------------
|
||||
offsetV = offsetV + ((sampleV-offsetV)/1024);
|
||||
filteredV = sampleV - offsetV;
|
||||
offsetI = offsetI + ((sampleI-offsetI)/1024);
|
||||
filteredI = sampleI - offsetI;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// C) Root-mean-square method voltage
|
||||
//-----------------------------------------------------------------------------
|
||||
sqV= filteredV * filteredV; //1) square voltage values
|
||||
sumV += sqV; //2) sum
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// D) Root-mean-square method current
|
||||
//-----------------------------------------------------------------------------
|
||||
sqI = filteredI * filteredI; //1) square current values
|
||||
sumI += sqI; //2) sum
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// E) Phase calibration
|
||||
//-----------------------------------------------------------------------------
|
||||
phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// F) Instantaneous power calc
|
||||
//-----------------------------------------------------------------------------
|
||||
instP = phaseShiftedV * filteredI; //Instantaneous Power
|
||||
sumP +=instP; //Sum
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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++;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------
|
||||
// 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) / (ADC_COUNTS));
|
||||
Vrms = V_RATIO * sqrt(sumV / numberOfSamples);
|
||||
|
||||
double I_RATIO = ICAL *((SupplyVoltage/1000.0) / (ADC_COUNTS));
|
||||
Irms = I_RATIO * sqrt(sumI / numberOfSamples);
|
||||
|
||||
//Calculation power values
|
||||
realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
|
||||
apparentPower = Vrms * Irms;
|
||||
powerFactor=realPower / apparentPower;
|
||||
|
||||
//Reset accumulators
|
||||
sumV = 0;
|
||||
sumI = 0;
|
||||
sumP = 0;
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
double EnergyMonitor::calcIrms(unsigned int Number_of_Samples)
|
||||
{
|
||||
|
||||
#if defined emonTxV3
|
||||
int SupplyVoltage=3300;
|
||||
#else
|
||||
int SupplyVoltage = readVcc();
|
||||
#endif
|
||||
|
||||
|
||||
for (unsigned int n = 0; n < Number_of_Samples; n++)
|
||||
{
|
||||
sampleI = analogRead(inPinI);
|
||||
// Digital low pass filter extracts the 2.5 V or 1.65 V dc offset,
|
||||
// then subtract this - signal is now centered on 0 counts.
|
||||
offsetI = (offsetI + (sampleI-offsetI)/1024);
|
||||
filteredI = sampleI - offsetI;
|
||||
|
||||
// Root-mean-square method current
|
||||
// 1) square current values
|
||||
sqI = filteredI * filteredI;
|
||||
// 2) sum
|
||||
sumI += sqI;
|
||||
}
|
||||
|
||||
double I_RATIO = ICAL *((SupplyVoltage/1000.0) / (ADC_COUNTS));
|
||||
Irms = I_RATIO * sqrt(sumI / Number_of_Samples);
|
||||
|
||||
//Serial.println(sumI / Number_of_Samples);
|
||||
//Reset accumulators
|
||||
sumI = 0;
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return Irms;
|
||||
}
|
||||
|
||||
void EnergyMonitor::serialprint()
|
||||
{
|
||||
Serial.print(' ');
|
||||
|
||||
Serial.print(realPower);
|
||||
Serial.print(' ');
|
||||
Serial.print(apparentPower);
|
||||
Serial.print(' ');
|
||||
Serial.print(Vrms);
|
||||
Serial.print(' ');
|
||||
Serial.print(Irms);
|
||||
Serial.print(' ');
|
||||
Serial.print(powerFactor);
|
||||
Serial.println(' ');
|
||||
delay(100);
|
||||
}
|
||||
|
||||
//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
|
||||
//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
|
||||
|
||||
long EnergyMonitor::readVcc() {
|
||||
long result;
|
||||
|
||||
//not used on emonTx V3 - as Vcc is always 3.3V - eliminates bandgap error and need for calibration http://harizanov.com/2013/09/thoughts-on-avr-adc-accuracy/
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
|
||||
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
|
||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
|
||||
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__)
|
||||
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
|
||||
ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560 http://openenergymonitor.org/emon/node/2253#comment-11432
|
||||
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||
ADMUX = _BV(MUX5) | _BV(MUX0);
|
||||
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
ADMUX = _BV(MUX3) | _BV(MUX2);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__AVR__)
|
||||
delay(2); // Wait for Vref to settle
|
||||
ADCSRA |= _BV(ADSC); // Convert
|
||||
while (bit_is_set(ADCSRA,ADSC));
|
||||
result = ADCL;
|
||||
result |= ADCH<<8;
|
||||
result = READVCC_CALIBRATION_CONST / result; //1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
|
||||
return result;
|
||||
#elif defined(__arm__)
|
||||
return (3300); //Arduino Due
|
||||
#else
|
||||
return (3300); //Guess that other un-supported architectures will be running a 3.3V!
|
||||
#endif
|
||||
}
|
||||
|
||||
100
libraries/EmonLib/EmonLib.h
Normal file
100
libraries/EmonLib/EmonLib.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Emon.h - Library for openenergymonitor
|
||||
Created by Trystan Lea, April 27 2010
|
||||
GNU GPL
|
||||
modified to use up to 12 bits ADC resolution (ex. Arduino Due)
|
||||
by boredman@boredomprojects.net 26.12.2013
|
||||
Low Pass filter for offset removal replaces HP filter 1/1/2015 - RW
|
||||
*/
|
||||
|
||||
#ifndef EmonLib_h
|
||||
#define EmonLib_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "WProgram.h"
|
||||
|
||||
#endif
|
||||
|
||||
// define theoretical vref calibration constant for use in readvcc()
|
||||
// 1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
|
||||
// override in your code with value for your specific AVR chip
|
||||
// determined by procedure described under "Calibrating the internal reference voltage" at
|
||||
// http://openenergymonitor.org/emon/buildingblocks/calibration
|
||||
#ifndef READVCC_CALIBRATION_CONST
|
||||
#define READVCC_CALIBRATION_CONST 1126400L
|
||||
#endif
|
||||
|
||||
// to enable 12-bit ADC resolution on Arduino Due,
|
||||
// include the following line in main sketch inside setup() function:
|
||||
// analogReadResolution(ADC_BITS);
|
||||
// otherwise will default to 10 bits, as in regular Arduino-based boards.
|
||||
#if defined(__arm__)
|
||||
#define ADC_BITS 12
|
||||
#else
|
||||
#define ADC_BITS 10
|
||||
#endif
|
||||
|
||||
#define ADC_COUNTS (1<<ADC_BITS)
|
||||
|
||||
|
||||
class EnergyMonitor
|
||||
{
|
||||
public:
|
||||
|
||||
void voltage(unsigned int _inPinV, double _VCAL, double _PHASECAL);
|
||||
void current(unsigned int _inPinI, double _ICAL);
|
||||
|
||||
void voltageTX(double _VCAL, double _PHASECAL);
|
||||
void currentTX(unsigned int _channel, double _ICAL);
|
||||
|
||||
void calcVI(unsigned int crossings, unsigned int timeout);
|
||||
double calcIrms(unsigned int NUMBER_OF_SAMPLES);
|
||||
void serialprint();
|
||||
|
||||
long readVcc();
|
||||
//Useful value variables
|
||||
double realPower,
|
||||
apparentPower,
|
||||
powerFactor,
|
||||
Vrms,
|
||||
Irms;
|
||||
|
||||
private:
|
||||
|
||||
//Set Voltage and current input pins
|
||||
unsigned int inPinV;
|
||||
unsigned int inPinI;
|
||||
//Calibration coefficients
|
||||
//These need to be set in order to obtain accurate results
|
||||
double VCAL;
|
||||
double ICAL;
|
||||
double PHASECAL;
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Variable declaration for emon_calc procedure
|
||||
//--------------------------------------------------------------------------------------
|
||||
int sampleV; //sample_ holds the raw analog read value
|
||||
int sampleI;
|
||||
|
||||
double lastFilteredV,filteredV; //Filtered_ is the raw analog value minus the DC offset
|
||||
double filteredI;
|
||||
double offsetV; //Low-pass filter output
|
||||
double offsetI; //Low-pass filter output
|
||||
|
||||
double phaseShiftedV; //Holds the calibrated phase shifted voltage.
|
||||
|
||||
double sqV,sumV,sqI,sumI,instP,sumP; //sq = squared, sum = Sum, inst = instantaneous
|
||||
|
||||
int startV; //Instantaneous voltage at start of sample window.
|
||||
|
||||
boolean lastVCross, checkVCross; //Used to measure number of times threshold is crossed.
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
25
libraries/EmonLib/Readme.txt
Normal file
25
libraries/EmonLib/Readme.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
_ _ _
|
||||
| | (_) |
|
||||
___ _ __ ___ ___ _ __ | | _| |__
|
||||
/ _ \ '_ ` _ \ / _ \| '_ \| | | | '_ \
|
||||
| __/ | | | | | (_) | | | | |____| | |_) |
|
||||
\___|_| |_| |_|\___/|_| |_|______|_|_.__/
|
||||
|
||||
Arduino Energy Monitoring Library - compatible with Arduino 1.0
|
||||
*****************************************************************
|
||||
|
||||
Designed for use with emonTx: http://openenergymonitor.org/emon/Modules
|
||||
|
||||
Download to Arduino IDE 'libraries' folder. Restart of IDE required.
|
||||
|
||||
Git Clone and Git Pull can be easily used to keep the library up-to-date and manage changes.
|
||||
JeeLabs has done a good post on the topic: http://jeelabs.org/2011/12/29/out-with-the-old-in-with-the-new/
|
||||
|
||||
|
||||
|
||||
Update: 5th January 2014: Support Added for Arduino Due (ARM Cortex-M3, 12-bit ADC) by icboredman.
|
||||
|
||||
To enable this feature on Arduino Due, add the following statement to setup() function in main sketch:
|
||||
analogReadResolution(ADC_BITS); This will set ADC_BITS to 12 (Arduino Due), EmonLib will otherwise default to 10 analogReadResolution(ADC_BITS);.
|
||||
See blog post on using Arduino Due as energy monitor: http://boredomprojects.net/index.php/projects/home-energy-monitor
|
||||
|
||||
20
libraries/EmonLib/examples/current_only/current_only.ino
Normal file
20
libraries/EmonLib/examples/current_only/current_only.ino
Normal file
@@ -0,0 +1,20 @@
|
||||
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
|
||||
|
||||
#include "EmonLib.h" // Include Emon Library
|
||||
EnergyMonitor emon1; // Create an instance
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
emon1.current(1, 111.1); // Current: input pin, calibration.
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
double Irms = emon1.calcIrms(1480); // Calculate Irms only
|
||||
|
||||
Serial.print(Irms*230.0); // Apparent power
|
||||
Serial.print(" ");
|
||||
Serial.println(Irms); // Irms
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
|
||||
|
||||
#include "EmonLib.h" // Include Emon Library
|
||||
EnergyMonitor emon1; // Create an instance
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
emon1.voltage(2, 234.26, 1.7); // Voltage: input pin, calibration, phase_shift
|
||||
emon1.current(1, 111.1); // Current: input pin, calibration.
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
emon1.calcVI(20,2000); // Calculate all. No.of half wavelengths (crossings), time-out
|
||||
emon1.serialprint(); // Print out all variables (realpower, apparent power, Vrms, Irms, power factor)
|
||||
|
||||
float realPower = emon1.realPower; //extract Real Power into variable
|
||||
float apparentPower = emon1.apparentPower; //extract Apparent Power into variable
|
||||
float powerFActor = emon1.powerFactor; //extract Power Factor into Variable
|
||||
float supplyVoltage = emon1.Vrms; //extract Vrms into Variable
|
||||
float Irms = emon1.Irms; //extract Irms into Variable
|
||||
}
|
||||
17
libraries/EmonLib/library.json
Normal file
17
libraries/EmonLib/library.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "EmonLib",
|
||||
"keywords": "electricity, energy, monitoring",
|
||||
"description": "Energy Monitoring Library",
|
||||
"version": "1.1.0",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/openenergymonitor/EmonLib.git"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms":
|
||||
[
|
||||
"atmelavr",
|
||||
"atmelsam"
|
||||
]
|
||||
}
|
||||
9
libraries/EmonLib/library.properties
Normal file
9
libraries/EmonLib/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=EmonLib
|
||||
version=1.1.0
|
||||
author=OpenEnergyMonitor
|
||||
maintainer=OpenEnergyMonitor
|
||||
sentence=Energy Monitoring Library
|
||||
paragraph=Energy Monitoring Library
|
||||
category=Sensors
|
||||
url=https://github.com/openenergymonitor/EmonLib.git
|
||||
architectures=*
|
||||
Reference in New Issue
Block a user