Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //--------------------------------------------------------------------------------------
- // Mains AC Non-Invasive Energy Monitor (2 channel)
- // Last revision 27th Oct 2010
- // Licence: GNU GPL
- // By Trystan Lea (updated to support two channel energy monitoring by Glyn Hudson)
- //--------------------------------------------------------------------------------------
- //--------------------------------------------------------------------------------------
- // VARIABLE DECLERATION
- //--------------------------------------------------------------------------------------
- //--ENERGY MEASURMENT VARIABLES------------------------------
- //Power measurement/time variables
- unsigned long t_now, t_diff, t_last, t_culm, ethsend;
- //Heater power culmative totals
- unsigned long timeH = 0, timeL = 0, heaterH = 0, heaterL = 0;
- float KWH_H = 0, KWH_L = 0;
- //kwhTotal is cumulative kwh today.
- double Solarkwh =0.0;
- double Mainskwh =0.0;
- //Variable for calculating heater power
- double htr ;
- //--------------------------------------------------------------------------------------
- // EMON
- //--------------------------------------------------------------------------------------
- // include the library code:
- #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins
- LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
- int menuState = 0;
- int menu = 0;
- int menuintro = 0;
- int wavelengths = 3000; //number of wavelengths to sample
- int inPinV = 1; //Analog input pin number that voltage signal is connected to
- int inPinI_1 = 3; //Analog input pin number that current signal is connected to. Channel 1
- int inPinI_2 = 2; //Analog input pin number that current signal is connected to. Channel 2
- int menupin = 2; //Arduino pin 1 goes to pushbutton for menu
- int RelayOn = 4; //Arduino pin 4 goes to the opto isolator (full power)
- int HRelayOn = 3; //Arduino pin 3 goes to opto isolator (half power)
- int led_on = 6; //Arduino pin 6 goes to panel LED
- //channel 1
- double VCAL = 1.28348; //Voltage calibration scaler
- double ICAL_1 = 0.05815; //Current calibration scaler
- double ICAL_2 = 0.05806;
- double PHASECAL = 2.3; //Shifts voltage relative to current,
- //subtracting any phase shifting caused by components
- int emon_timeout = 2000; //how long to wait ms if something goes wrong.
- class Channel
- {
- public:
- void emon_calc(int,double); //create pulse function
- double realPower, //Output variables
- apparentPower,
- powerFactor,
- Vrms,
- Irms,
- whInc,
- wh;
- private: // 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; // ''
- unsigned long lwhtime, whtime; //used to calculate energy used.
- };
- Channel ch1,ch2; //create two incidence of class channel for the two channels
- //--------------------------------------------------------------------------------------
- // SETUP
- //--------------------------------------------------------------------------------------
- void setup()
- {
- lcd.begin(16, 2); // set up the LCD's number of columns and rows:
- Serial.begin(9600);
- pinMode(RelayOn,OUTPUT); // this sets the pin named RelayOn to be an output
- pinMode(HRelayOn,OUTPUT); // this sets the pin named RelayOn to be an output
- pinMode(menupin, INPUT); // this sets the pin named menupin to be an input
- pinMode (led_on, OUTPUT); //this sets the pin named led_on to be an output
- t_culm = (3600000 * 12); //On first run, advances the 24hr timer by 12hrs (so can restart at midday!)
- //t_culm = (3600000 * 23.75); //FOR TESTING ONLY
- digitalWrite(RelayOn,HIGH); //Switches relay off
- digitalWrite(HRelayOn,HIGH); //Switches relay off
- //Introduces 20 second delay to allow caps to charge up
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print(" Please Wait ");
- lcd.setCursor(0, 1);
- lcd.print("Initialising....");
- delay (20000);
- }
- unsigned long wtime;
- //--------------------------------------------------------------------------------------
- // MAIN LOOP
- //--------------------------------------------------------------------------------------
- void loop()
- {
- //-------------------------------------------------------------------------------------------
- // 1) Calculate energy monitor values
- //-------------------------------------------------------------------------------------------
- ch1.emon_calc(inPinI_1,ICAL_1); //Energy Monitor calc function for channel 1, pass Arduino analog in pin nummber and calibration coefficient
- ch2.emon_calc(inPinI_2,ICAL_2); //Energy Monitor calc function, for channel 2, pass Arduino analog in pin nummber and calibration coefficient
- if (ch1.realPower < 0) { //Stops the solar channel reading negative (invertor anomaly)
- (ch1.realPower = 0); }
- //--ENERGY MEASURMENT CALCULATION----------------
- //Power measurement
- t_now = millis();
- if ( t_now > t_last ) { //check to see if millis has overflowed back to zero (after approx 49 days)
- t_diff = t_now - t_last; } //if not, the time each emon cycle takes
- else { //if millis has reset...
- t_diff = 4127; } //t_diff = (the amount of time each average emon cycle takes), again dealing with the millis reset.
- t_culm += t_diff;
- t_last = t_now;
- if ( t_culm > (3600000 * 24)){ //check to see if 24hrs has elapsed
- Solarkwh = 0; // RESET
- Mainskwh = 0; // RESET
- t_culm = 0; // RESET
- heaterH = 0; // RESET
- timeH = 0; // RESET
- heaterL = 0; // RESET
- timeL = 0; // RESET
- ethsend = 0; // RESET
- menu = 0; // Return menu back to start
- }
- //Calculate kW's diverted to heater per 24hrs
- if (digitalRead(RelayOn) == LOW) timeH += t_diff;
- if (digitalRead(HRelayOn) == LOW) timeL += t_diff;
- heaterH = (1.09 * timeH); // units Ws; (long math)
- heaterL = (0.545 * timeL);
- KWH_H = heaterH / 3600.0; // units KWH 3.6e6 = (3600.0 * 1000.0)
- KWH_L = heaterL / 3600.0;
- //checks to see if can run at full power
- if (ch1.realPower > (ch2.realPower +1090)) {
- digitalWrite(HRelayOn,HIGH); //turn the half power output off
- delay (200);
- digitalWrite(RelayOn,LOW); //turn the full output on
- }
- else{
- digitalWrite(RelayOn,HIGH); //turn the output off
- //checks to see if can run at half power
- if (ch1.realPower > (ch2.realPower +545)) {
- delay (200);
- digitalWrite(HRelayOn,LOW); }//turn the output on
- else {
- digitalWrite(HRelayOn,HIGH); //turn the output off
- }
- }
- //LED control
- if (digitalRead(RelayOn) == LOW) {
- analogWrite(led_on, 200); }
- else if (digitalRead(HRelayOn) == LOW) {
- analogWrite(led_on, 20); } //low brightness
- else {
- digitalWrite (led_on,HIGH);
- delay (100);
- digitalWrite (led_on,LOW);
- }
- //Calculate number of kwh generated.
- Solarkwh += ((ch1.realPower)* t_diff) / 3600000 ;
- Mainskwh += ((ch2.realPower)* t_diff) / 3600000 ;
- //------------Data Output-------------
- //Read menupin to see what menu to display
- menuState = digitalRead(menupin);
- if ( menuState == LOW) {
- menu = menu+1;
- menuintro = 0; } //because the button has been pressed, sets menuintro to 0, so intro screen is displayed
- if (menu > 4){
- menu = 0;
- }
- //MENU 0
- if (menu == 0) {
- // clear the lcd screen
- lcd.clear();
- //if-else statement to alter LCD print format depending upon power reading
- lcd.setCursor(0, 0);
- if (ch1.realPower >= 1000) {
- lcd.print("Solar "); lcd.print(ch1.realPower / 1000.0, 3); lcd.print(" kW"); }
- else {
- lcd.print("Solar "); lcd.print(ch1.realPower, 0); lcd.print(" Watts"); }
- lcd.setCursor(0, 1);
- if (ch2.realPower >= 5000) {
- lcd.print("M/Power over 5kW"); }
- else
- if (ch2.realPower >= 1000) {
- lcd.print("Mains "); lcd.print(ch2.realPower / 1000.0, 3); lcd.print(" kW"); }
- else {
- lcd.print("Mains "); lcd.print(ch2.realPower, 0); lcd.print(" Watts"); }
- }
- //MENU 1 - Displays kWh's per 24hrs
- if (menu == 1) {
- if (menuintro == 0) { //if menu button has been pressed, displays intro screen
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print ("Power Stats for");
- lcd.setCursor(0, 1);
- lcd.print("today");
- delay (2500); }
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print("Solar "); lcd.print(Solarkwh / 1000); lcd.print(" kWh");
- lcd.setCursor(0, 1);
- lcd.print("Mains "); lcd.print(Mainskwh / 1000); lcd.print(" kWh");
- menuintro = 1; } //sets menu intro to 1 so that intro screen is not repeated
- //MENU 2 - Displays kWh's diverted to heater per 24hrs
- if (menu == 2) {
- if (menuintro == 0) {
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print ("kWh diverted to");
- lcd.setCursor(0, 1);
- lcd.print("imm heater today");
- delay (2500); }
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print(KWH_H / 1000); lcd.print("H + "); lcd.print(KWH_L / 1000); lcd.print("L");
- lcd.setCursor(0, 1);
- lcd.print("Total= "); lcd.print((KWH_H + KWH_L)/1000); lcd.print(" kWh");
- menuintro = 1; }
- //MENU 3 - Displays Voltage & Power Factor calibration
- if (menu == 3) {
- if (menuintro == 0) {
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print ("Voltage and");
- lcd.setCursor(0, 1);
- lcd.print("power factor");
- delay (2500); }
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print("PowerF "); lcd.print(ch1.powerFactor, 2);
- lcd.setCursor(0, 1);
- lcd.print("Voltage "); lcd.print(ch1.Vrms, 0); lcd.print(" V");
- menuintro = 1; }
- //MENU 4 - DEMO MODE
- if (menu == 4) {
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print ("Press button for");
- lcd.setCursor(0, 1);
- lcd.print("2 secs for demo");
- delay (2000);
- if (digitalRead(menupin)== LOW) { //check to see if button is still pressed
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print ("DEMO MODE");
- delay (2000);
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print("Solar 1.326 kW");
- lcd.setCursor(0, 1);
- lcd.print("Mains 298 Watts");
- digitalWrite (led_on,HIGH);
- delay (4000);
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print("Solar 18.36 kWh");
- lcd.setCursor(0, 1);
- lcd.print("Mains 4.29 kWh");
- digitalWrite (led_on,HIGH);
- delay (4000);
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print("2.44H + 1.80L");
- lcd.setCursor(0, 1);
- lcd.print("Total= 4.24 kWh");
- delay (4000);
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print("PowerF 0.98");
- lcd.setCursor(0, 1);
- lcd.print("Voltage 247 V");
- digitalWrite (led_on,HIGH);
- delay (4000);
- menu = 0; }
- else {
- menu = 0; }
- }
- //----------------Serial Data to Ethernet unit------------------//
- if (digitalRead(RelayOn) == LOW) {
- htr = 1090 ; }
- else if (digitalRead(HRelayOn) == LOW) {
- htr = 545 ; }
- else {
- htr = 0 ;}
- //timer to control ethernet send rate
- if (t_culm > (ethsend + 20000)) { //will execute a serial UART send 'after' 30 seconds
- ethsend = t_culm;
- //ethernet send code goes here
- Serial.print ("4,");
- Serial.print (ch1.realPower, 0);
- Serial.print (",");
- Serial.print (ch2.realPower, 0);
- Serial.print (",");
- Serial.print (Solarkwh, 0);
- Serial.print (",");
- Serial.print (Mainskwh, 0);
- Serial.print (",");
- Serial.print (KWH_H + KWH_L, 0);
- Serial.print (",");
- Serial.print (htr, 0);
- Serial.print (",");
- Serial.print (ch1.Vrms, 0);
- Serial.println (";");
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement