Hey everyone,
I have a simple sketch for an energy monitor using a variation of openenergymonitor.org/emon on a CC3200 LaunchPad. This sketch works successfully, as do the WiFiWebClient and WiFiWebClientRepeating sample projects.
However, if I simply add this line of code to my sketch, it uploads successfully but does not run. Serial returns nothing and the board is inactive.
#include <WiFi.h>
It works fine if I simply remove this line. The WiFi sample sketches on their own work fine too.
If I do the opposite and add the EmonLib.h library include to the Wifi sketch, the same problem occurs.
Code added to WifiLibClientRepeating.ino:
#include <EmonLib.h>
Maybe this is a library conflict? I'm confused because the compilation and upload are successful - so it must be a runtime issue. But as I mentioned above - both sketches work on their own - just not together.
I'm using the latest version of Energia on windows (energia-0101E0014), board is Rev 4.1.
I really appreciate any help as I'm really stuck. Hope you have a great afternoon!
Cheers, Rich
Sketch Code:
#include <WiFi.h> // Sketch works if this line is removed #include <EmonLib.h> EnergyMonitor emon1; // CT1 EnergyMonitor emon2; // CT2 struct POWERDATA { double w; double va; double v; double a; double f; double kwh; double kwhday; } pwr; const int ct1Pin = A0; const int ct2Pin = A1; const int acBiasPin = A2; void setup() { Serial.begin(115200); Serial.println("starting..."); // <-- never displayed if this line exists: #include <WiFi.h> pinMode(RED_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); pinMode(ct1Pin, INPUT); // CT1 pinMode(ct2Pin, INPUT); // CT2 pinMode(acBiasPin, INPUT); // AC Bias emon1.current(ct1Pin, 60.6); // Current: input pin, calibration. emon1.voltage(acBiasPin, 123.5, 1.7); // Voltage: input pin, calibration, phase_shift emon2.current(ct2Pin, 60.6); // Current: input pin, calibration. emon2.voltage(acBiasPin, 123.5, 1.7); // Voltage: input pin, calibration, phase_shift } void loop() { digitalWrite(RED_LED, HIGH); emon1.calcVI(20, 2000); // Calculate all. No.of wavelengths, time-out digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, HIGH); emon2.calcVI(20, 2000); // Calculate all. No.of wavelengths, time-out digitalWrite(GREEN_LED, LOW); pwr.w = emon1.realPower + emon2.realPower; pwr.va = emon1.apparentPower + emon2.apparentPower; pwr.v = (emon1.Vrms + emon2.Vrms) / 2.0; pwr.a = emon1.Irms + emon2.Irms; pwr.f = (emon1.powerFactor + emon2.powerFactor) / 2.0; pwr.kwh += (pwr.w / 3600000.0); // 1000W/kW / 3600s/h pwr.kwhday += (pwr.w / 3600000.0); Serial.print(pwr.w); Serial.println(" w"); }
Here is the EmonLib.h library for reference as the issue must be related to this:
/* 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 */ #ifndef EmonLib_h #define EmonLib_h #if defined(ARDUINO) && ARDUINO >= 100 #include "Energia.h" #else #include "WProgram.h" #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(int _inPinV, double _VCAL, double _PHASECAL); void current(int _inPinI, double _ICAL); void voltageTX(double _VCAL, double _PHASECAL); void currentTX(int _channel, double _ICAL); void calcVI(int crossings, int timeout); double calcIrms(int NUMBER_OF_SAMPLES); void serialprint(); long readVcc(); //Useful value variables double realPower, apparentPower, powerFactor, Vrms, Irms; private: //Set Voltage and current input pins int inPinV; int inPinI; //Calibration coeficients //These need to be set in order to obtain accurate results double VCAL; double ICAL; double PHASECAL; //-------------------------------------------------------------------------------------- // Variable declaration for emon_calc procedure //-------------------------------------------------------------------------------------- int lastSampleV,sampleV; //sample_ holds the raw analog read value, lastSample_ holds the last sample int lastSampleI,sampleI; double lastFilteredV,filteredV; //Filtered_ is the raw analog value minus the DC offset double lastFilteredI, filteredI; 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. int crossCount; // '' }; #endif
And EmonLib.cpp:
/* 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 */ //#include "WProgram.h" un-comment for use on older versions of Arduino IDE #include "EmonLib.h" #if defined(ARDUINO) && ARDUINO >= 100 #include "Energia.h" #else #include "WProgram.h" #endif //-------------------------------------------------------------------------------------- // Sets the pins to be used for voltage and current sensors //-------------------------------------------------------------------------------------- void EnergyMonitor::voltage(int _inPinV, double _VCAL, double _PHASECAL) { inPinV = _inPinV; VCAL = _VCAL; PHASECAL = _PHASECAL; } void EnergyMonitor::current(int _inPinI, double _ICAL) { inPinI = _inPinI; ICAL = _ICAL; } //-------------------------------------------------------------------------------------- // 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; } void EnergyMonitor::currentTX(int _channel, double _ICAL) { if (_channel == 1) inPinI = 3; if (_channel == 2) inPinI = 0; if (_channel == 3) inPinI = 1; ICAL = _ICAL; } //-------------------------------------------------------------------------------------- // 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(int crossings, int timeout) { #if defined emonTxV3 int SUPPLYVOLTAGE=3300; #else int SUPPLYVOLTAGE = readVcc(); #endif int crossCount = 0; //Used to measure number of times threshold is crossed. int numberOfSamples = 0; //This is now incremented //------------------------------------------------------------------------------------------------------------------------- // 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) //the while loop... { startV = analogRead(inPinV); //using the voltage waveform if ((startV < (ADC_COUNTS/2+50)) && (startV > (ADC_COUNTS/2-50))) st=true; //check its within range if ((millis()-start)>timeout) st = true; } //------------------------------------------------------------------------------------------------------------------------- // 2) Main measurment loop //------------------------------------------------------------------------------------------------------------------------- start = millis(); while ((crossCount < crossings) && ((millis()-start)<timeout)) { numberOfSamples++; //Count number of times looped. lastSampleV=sampleV; //Used for digital high pass filter lastSampleI=sampleI; //Used for digital high pass filter lastFilteredV = filteredV; //Used for offset removal lastFilteredI = filteredI; //Used for offset removal //----------------------------------------------------------------------------- // 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 high pass filters to remove 2.5V DC offset (centered on 0V). //----------------------------------------------------------------------------- filteredV = 0.996*(lastFilteredV+(sampleV-lastSampleV)); filteredI = 0.996*(lastFilteredI+(sampleI-lastSampleI)); //----------------------------------------------------------------------------- // 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 coeficients 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(int NUMBER_OF_SAMPLES) { #if defined emonTxV3 int SUPPLYVOLTAGE=3300; #else int SUPPLYVOLTAGE = readVcc(); #endif for (int n = 0; n < NUMBER_OF_SAMPLES; n++) { lastSampleI = sampleI; sampleI = analogRead(inPinI); lastFilteredI = filteredI; filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI); // 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); //Reset accumulators sumI = 0; //-------------------------------------------------------------------------------------- return Irms; } void EnergyMonitor::serialprint() { 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 hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino //and Jérôme who alerted us to provideyourown.com/.../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 harizanov.com/.../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_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 openenergymonitor.org/.../2253 #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 = 1126400L / result; //1100mV*1024 ADC steps openenergymonitor.org/.../1186 return result; //Arduino Due #else return (1400); //Changed from 3300 to 1400 for the TI CC3200 vref (note some users said its 1.46V to get full 4095 range) #endif }