Advertisement
rossoreed

Arduino Solar Manager 1st Sept

Sep 2nd, 2011
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.78 KB | None | 0 0
  1. //--------------------------------------------------------------------------------------
  2. // Mains AC Non-Invasive Energy Monitor (2 channel)
  3. // Last revision 27th Oct 2010
  4. // Licence: GNU GPL
  5. // By Trystan Lea (updated to support two channel energy monitoring by Glyn Hudson)
  6. //--------------------------------------------------------------------------------------
  7. //--------------------------------------------------------------------------------------
  8. // VARIABLE DECLERATION
  9. //--------------------------------------------------------------------------------------
  10.   //--ENERGY MEASURMENT VARIABLES------------------------------
  11.  
  12.   //Power measurement/time variables
  13.   unsigned long t_now, t_diff, t_last, t_culm, ethsend;
  14.  
  15.   //Heater power culmative totals
  16.   unsigned long timeH = 0, timeL = 0, heaterH = 0, heaterL = 0;
  17.   float KWH_H = 0, KWH_L = 0;
  18.    
  19.   //kwhTotal is cumulative kwh today.
  20.   double Solarkwh =0.0;
  21.   double Mainskwh =0.0;
  22.  
  23.  //Variable for calculating heater power
  24.   double htr ;
  25. //--------------------------------------------------------------------------------------
  26. // EMON
  27. //--------------------------------------------------------------------------------------
  28.  
  29. // include the library code:
  30. #include <LiquidCrystal.h>  // initialize the library with the numbers of the interface pins
  31. LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
  32. int menuState = 0;
  33. int menu = 0;
  34. int menuintro = 0;
  35.  
  36. int wavelengths = 3000;   //number of wavelengths to sample
  37. int inPinV = 1;           //Analog input pin number that voltage signal is connected to
  38. int inPinI_1 = 3;         //Analog input pin number that current signal is connected to. Channel 1
  39. int inPinI_2 = 2;         //Analog input pin number that current signal is connected to. Channel 2
  40. int menupin = 2;          //Arduino pin 1 goes to pushbutton for menu
  41. int RelayOn = 4;          //Arduino pin 4 goes to the opto isolator (full power)
  42. int HRelayOn = 3;         //Arduino pin 3 goes to opto isolator (half power)
  43. int led_on = 6;           //Arduino pin 6 goes to panel LED
  44.  
  45.  
  46. //channel 1
  47. double VCAL = 1.28348;              //Voltage calibration scaler
  48. double ICAL_1 = 0.05815;            //Current calibration scaler
  49. double ICAL_2 = 0.05806;
  50.  
  51. double PHASECAL = 2.3;                        //Shifts voltage relative to current,
  52.                                               //subtracting any phase shifting caused by components
  53.    
  54. int emon_timeout = 2000;                       //how long to wait ms if something goes wrong.
  55.  
  56.  
  57. class Channel
  58. {
  59.   public:
  60.     void emon_calc(int,double);                //create pulse function
  61.     double realPower,                          //Output variables
  62.        apparentPower,
  63.        powerFactor,
  64.        Vrms,
  65.        Irms,
  66.        whInc,
  67.        wh;
  68.  
  69.   private: // Variable declaration for emon_calc procedure
  70.    int lastSampleV,sampleV;                          //sample_ holds the raw analog read value, lastSample_ holds the last sample_
  71.     int lastSampleI,sampleI;                      
  72.  
  73.     double lastFilteredV,filteredV;                   //Filtered_ is the raw analog value minus the DC offset
  74.     double lastFilteredI, filteredI;                  
  75.    
  76.     double phaseShiftedV;                             //Holds the calibrated phase shifted voltage.
  77.    
  78.     double sqV,sumV,sqI,sumI,instP,sumP;              //sq = squared, sum = Sum, inst = instantaneous
  79.    
  80.     int startV;                                       //Instantaneous voltage at start of sample window.
  81.    
  82.     boolean lastVCross, checkVCross;                  //Used to measure number of times threshold is crossed.
  83.     int crossCount;                                   // ''
  84.    
  85.     unsigned long lwhtime, whtime;                    //used to calculate energy used.
  86.  
  87. };
  88.  
  89. Channel ch1,ch2;    //create two incidence of class channel for the two channels
  90.  
  91. //--------------------------------------------------------------------------------------
  92. // SETUP
  93. //--------------------------------------------------------------------------------------
  94. void setup()
  95. {
  96.    lcd.begin(16, 2); // set up the LCD's number of columns and rows:
  97.  
  98.    Serial.begin(9600);
  99.    pinMode(RelayOn,OUTPUT); // this sets the pin named RelayOn to be an output
  100.    pinMode(HRelayOn,OUTPUT); // this sets the pin named RelayOn to be an output
  101.    pinMode(menupin, INPUT); // this sets the pin named menupin to be an input
  102.    pinMode (led_on, OUTPUT); //this sets the pin named led_on to be an output
  103.  
  104.    t_culm = (3600000 * 12);       //On first run, advances the 24hr timer by 12hrs (so can restart at midday!)  
  105.    //t_culm = (3600000 * 23.75);  //FOR TESTING ONLY
  106.    
  107.    digitalWrite(RelayOn,HIGH);   //Switches relay off
  108.    digitalWrite(HRelayOn,HIGH);  //Switches relay off
  109.    
  110.    //Introduces 20 second delay to allow caps to charge up
  111.     lcd.clear();
  112.     lcd.setCursor(0, 0);
  113.     lcd.print("  Please Wait  ");
  114.     lcd.setCursor(0, 1);
  115.     lcd.print("Initialising....");
  116.     delay (20000);
  117. }
  118.  
  119. unsigned long wtime;
  120.  
  121. //--------------------------------------------------------------------------------------
  122. // MAIN LOOP
  123. //--------------------------------------------------------------------------------------
  124. void loop()
  125. {
  126.   //-------------------------------------------------------------------------------------------
  127.   // 1) Calculate energy monitor values
  128.   //-------------------------------------------------------------------------------------------
  129.   ch1.emon_calc(inPinI_1,ICAL_1);  //Energy Monitor calc function for channel 1, pass Arduino analog in pin nummber and calibration coefficient
  130.   ch2.emon_calc(inPinI_2,ICAL_2);  //Energy Monitor calc function, for channel 2, pass Arduino analog in pin nummber and calibration coefficient
  131.  
  132. if (ch1.realPower < 0)  {   //Stops the solar channel reading negative (invertor anomaly)
  133.    (ch1.realPower = 0);  }
  134.  
  135.   //--ENERGY MEASURMENT CALCULATION----------------  
  136.  
  137.  //Power measurement
  138.   t_now = millis();
  139.     if ( t_now > t_last ) {   //check to see if millis has overflowed back to zero (after approx 49 days)
  140.       t_diff = t_now - t_last; } //if not, the time each emon cycle takes
  141.         else {  //if millis has reset...
  142.           t_diff = 4127; }   //t_diff = (the amount of time each average emon cycle takes), again dealing with the millis reset.
  143.   t_culm += t_diff;
  144.   t_last = t_now;
  145.  
  146.   if ( t_culm > (3600000 * 24)){ //check to see if 24hrs has elapsed
  147.   Solarkwh = 0; // RESET
  148.   Mainskwh = 0; // RESET
  149.   t_culm = 0;   // RESET
  150.   heaterH = 0;  // RESET
  151.   timeH = 0;    // RESET
  152.   heaterL = 0;  // RESET
  153.   timeL = 0;    // RESET
  154.   ethsend = 0;  // RESET
  155.   menu = 0;     // Return menu back to start
  156.   }
  157.  
  158.  //Calculate kW's diverted to heater per 24hrs
  159.    if (digitalRead(RelayOn) == LOW) timeH += t_diff;
  160.    if (digitalRead(HRelayOn) == LOW) timeL += t_diff;
  161.    heaterH = (1.09 * timeH);    // units Ws;  (long math)
  162.    heaterL = (0.545 * timeL);      
  163.    KWH_H = heaterH / 3600.0;     // units KWH    3.6e6 = (3600.0 * 1000.0)
  164.    KWH_L = heaterL / 3600.0;
  165.  
  166.  //checks to see if can run at full power
  167.       if (ch1.realPower > (ch2.realPower +1090)) {
  168.       digitalWrite(HRelayOn,HIGH); //turn the half power output off
  169.       delay (200);
  170.       digitalWrite(RelayOn,LOW); //turn the full output on
  171.        }
  172.   else{
  173.       digitalWrite(RelayOn,HIGH); //turn the output off
  174.        //checks to see if can run at half power
  175.        if (ch1.realPower > (ch2.realPower +545)) {
  176.         delay (200);
  177.         digitalWrite(HRelayOn,LOW); }//turn the output on
  178.           else  {
  179.            digitalWrite(HRelayOn,HIGH); //turn the output off
  180.      }
  181.    }
  182.  
  183.  //LED control
  184.    if (digitalRead(RelayOn) == LOW) {
  185.      analogWrite(led_on, 200);  }
  186.    else if (digitalRead(HRelayOn) == LOW) {
  187.      analogWrite(led_on, 20);   } //low brightness
  188.    else {
  189.          digitalWrite (led_on,HIGH);
  190.          delay (100);
  191.          digitalWrite (led_on,LOW);
  192.         }
  193.        
  194.   //Calculate number of kwh generated.
  195.   Solarkwh += ((ch1.realPower)* t_diff) / 3600000 ;
  196.   Mainskwh += ((ch2.realPower)* t_diff) / 3600000 ;  
  197.  
  198.     //------------Data Output-------------
  199.      
  200.     //Read menupin to see what menu to display
  201.     menuState = digitalRead(menupin);
  202.     if ( menuState == LOW) {
  203.     menu = menu+1;
  204.     menuintro = 0;  } //because the button has been pressed, sets menuintro to 0, so intro screen is displayed
  205.     if (menu > 4){
  206.     menu = 0;
  207.     }  
  208.    
  209.     //MENU 0  
  210.     if (menu == 0) {
  211.     // clear the lcd screen
  212.     lcd.clear();
  213.     //if-else statement to alter LCD print format depending upon power reading
  214.     lcd.setCursor(0, 0);
  215.         if (ch1.realPower >= 1000)  {
  216.       lcd.print("Solar "); lcd.print(ch1.realPower / 1000.0, 3); lcd.print(" kW");  }
  217.     else  {
  218.       lcd.print("Solar "); lcd.print(ch1.realPower, 0); lcd.print(" Watts");  }
  219.    
  220.     lcd.setCursor(0, 1);
  221.         if (ch2.realPower >= 5000)  {
  222.       lcd.print("M/Power over 5kW"); }
  223.     else
  224.       if (ch2.realPower >= 1000)  {
  225.       lcd.print("Mains "); lcd.print(ch2.realPower / 1000.0, 3); lcd.print(" kW");  }
  226.     else  {
  227.       lcd.print("Mains "); lcd.print(ch2.realPower, 0); lcd.print(" Watts");  }
  228.     }
  229.  
  230.     //MENU 1 - Displays kWh's per 24hrs
  231.     if (menu == 1) {
  232.       if (menuintro == 0) {  //if menu button has been pressed, displays intro screen
  233.       lcd.clear();
  234.       lcd.setCursor(0, 0);
  235.       lcd.print ("Power Stats for");
  236.       lcd.setCursor(0, 1);
  237.       lcd.print("today");
  238.       delay (2500); }
  239.     lcd.clear();
  240.     lcd.setCursor(0, 0);
  241.     lcd.print("Solar "); lcd.print(Solarkwh / 1000); lcd.print(" kWh");
  242.     lcd.setCursor(0, 1);
  243.     lcd.print("Mains "); lcd.print(Mainskwh / 1000); lcd.print(" kWh");
  244.     menuintro = 1;  }  //sets menu intro to 1 so that intro screen is not repeated
  245.    
  246.     //MENU 2 - Displays kWh's diverted to heater per 24hrs
  247.     if (menu == 2) {
  248.     if (menuintro == 0) {
  249.     lcd.clear();
  250.     lcd.setCursor(0, 0);
  251.     lcd.print ("kWh diverted to");
  252.     lcd.setCursor(0, 1);
  253.     lcd.print("imm heater today");
  254.     delay (2500);  }
  255.       lcd.clear();
  256.       lcd.setCursor(0, 0);
  257.       lcd.print(KWH_H / 1000); lcd.print("H + "); lcd.print(KWH_L / 1000); lcd.print("L");
  258.       lcd.setCursor(0, 1);
  259.       lcd.print("Total= "); lcd.print((KWH_H + KWH_L)/1000); lcd.print(" kWh");  
  260.       menuintro = 1; }
  261.    
  262.     //MENU 3 - Displays Voltage & Power Factor calibration
  263.     if (menu == 3) {
  264.       if (menuintro == 0) {
  265.       lcd.clear();
  266.       lcd.setCursor(0, 0);
  267.       lcd.print ("Voltage and");
  268.       lcd.setCursor(0, 1);
  269.       lcd.print("power factor");
  270.       delay (2500);  }
  271.     lcd.clear();
  272.     lcd.setCursor(0, 0);
  273.     lcd.print("PowerF "); lcd.print(ch1.powerFactor, 2);
  274.     lcd.setCursor(0, 1);
  275.     lcd.print("Voltage "); lcd.print(ch1.Vrms, 0); lcd.print(" V");
  276.     menuintro = 1;  }
  277.    
  278.     //MENU 4 - DEMO MODE
  279.     if (menu == 4) {
  280.     lcd.clear();
  281.     lcd.setCursor(0, 0);
  282.     lcd.print ("Press button for");
  283.     lcd.setCursor(0, 1);
  284.     lcd.print("2 secs for demo");
  285.     delay (2000);
  286.     if (digitalRead(menupin)== LOW) {  //check to see if button is still pressed
  287.     lcd.clear();
  288.     lcd.setCursor(0, 0);
  289.     lcd.print ("DEMO MODE");
  290.     delay (2000);
  291.     lcd.clear();
  292.     lcd.setCursor(0, 0);
  293.     lcd.print("Solar 1.326 kW");
  294.     lcd.setCursor(0, 1);
  295.     lcd.print("Mains 298 Watts");
  296.     digitalWrite (led_on,HIGH);
  297.     delay (4000);
  298.     lcd.clear();
  299.     lcd.setCursor(0, 0);
  300.     lcd.print("Solar 18.36 kWh");
  301.     lcd.setCursor(0, 1);
  302.     lcd.print("Mains 4.29 kWh");
  303.     digitalWrite (led_on,HIGH);
  304.     delay (4000);
  305.     lcd.clear();
  306.     lcd.setCursor(0, 0);
  307.     lcd.print("2.44H + 1.80L");
  308.     lcd.setCursor(0, 1);
  309.     lcd.print("Total= 4.24 kWh");
  310.     delay (4000);
  311.     lcd.clear();
  312.     lcd.setCursor(0, 0);
  313.     lcd.print("PowerF 0.98");
  314.     lcd.setCursor(0, 1);
  315.     lcd.print("Voltage 247 V");
  316.     digitalWrite (led_on,HIGH);
  317.     delay (4000);
  318.     menu = 0; }
  319.     else {
  320.       menu = 0; }
  321.     }
  322.    
  323. //----------------Serial Data to Ethernet unit------------------//
  324.    
  325.     if (digitalRead(RelayOn) == LOW) {
  326.       htr = 1090 ;  }
  327.        else if (digitalRead(HRelayOn) == LOW) {
  328.          htr = 545 ;  }
  329.           else {
  330.             htr = 0  ;}
  331.            
  332.   //timer to control ethernet send rate
  333.     if (t_culm > (ethsend + 20000)) {  //will execute a serial UART send 'after' 30 seconds
  334.       ethsend = t_culm;
  335.       //ethernet  send code goes here
  336.  
  337.   Serial.print ("4,");
  338.   Serial.print (ch1.realPower, 0);
  339.   Serial.print (",");
  340.   Serial.print (ch2.realPower, 0);
  341.   Serial.print (",");
  342.   Serial.print (Solarkwh, 0);
  343.   Serial.print (",");
  344.   Serial.print (Mainskwh, 0);
  345.   Serial.print (",");  
  346.   Serial.print (KWH_H + KWH_L, 0);
  347.   Serial.print (",");
  348.   Serial.print (htr, 0);
  349.   Serial.print (",");
  350.   Serial.print (ch1.Vrms, 0);
  351.   Serial.println (";");
  352.     }        
  353.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement