Advertisement
rossoreed

Solar Power Manager

Aug 6th, 2011
2,382
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.10 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;
  14.    
  15.   //kwhTotal is cumulative kwh today.
  16.   double Solarkwh =0.0;
  17.   double Mainskwh =0.0;
  18. //--------------------------------------------------------------------------------------
  19. // EMON
  20. //--------------------------------------------------------------------------------------
  21.  
  22. // include the library code:
  23. #include <LiquidCrystal.h>  // initialize the library with the numbers of the interface pins
  24. LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
  25. int menuState = 0;
  26. int menu = 0;
  27.  
  28. int wavelengths = 3000;   //number of wavelengths to sample
  29. int inPinV = 1;           //Analog input pin number that voltage signal is connected to
  30. int inPinI_1 = 3;         //Analog input pin number that current signal is connected to. Channel 1
  31. int inPinI_2 = 2;         //Analog input pin number that current signal is connected to. Channel 2
  32. int menupin = 1;          //Arduino pin 1 goes to pushbutton for menu
  33. int RelayOn = 4;          //Arduino pin 4 goes to the opto isolator (full power)
  34. int HRelayOn = 3;         //Arduino pin 3 goes to opto isolator (half power)
  35. int led_on = 6;           //Arduino pin 6 goes to panel LED
  36.  
  37.  
  38. //channel 1
  39. double VCAL = 1.28348;              //Voltage calibration scaler
  40. double ICAL_1 = 0.05815;            //Current calibration scaler
  41. double ICAL_2 = 0.05806;
  42.  
  43. double PHASECAL = 2.3;                        //Shifts voltage relative to current,
  44.                                               //subtracting any phase shifting caused by components
  45.    
  46. int emon_timeout = 2000;                       //how long to wait ms if something goes wrong.
  47.  
  48.  
  49. class Channel
  50. {
  51.   public:
  52.     void emon_calc(int,double);                //create pulse function
  53.     double realPower,                          //Output variables
  54.        apparentPower,
  55.        powerFactor,
  56.        Vrms,
  57.        Irms,
  58.        whInc,
  59.        wh;
  60.  
  61.   private: // Variable declaration for emon_calc procedure
  62.    int lastSampleV,sampleV;                          //sample_ holds the raw analog read value, lastSample_ holds the last sample_
  63.     int lastSampleI,sampleI;                      
  64.  
  65.     double lastFilteredV,filteredV;                   //Filtered_ is the raw analog value minus the DC offset
  66.     double lastFilteredI, filteredI;                  
  67.    
  68.     double phaseShiftedV;                             //Holds the calibrated phase shifted voltage.
  69.    
  70.     double sqV,sumV,sqI,sumI,instP,sumP;              //sq = squared, sum = Sum, inst = instantaneous
  71.    
  72.     int startV;                                       //Instantaneous voltage at start of sample window.
  73.    
  74.     boolean lastVCross, checkVCross;                  //Used to measure number of times threshold is crossed.
  75.     int crossCount;                                   // ''
  76.    
  77.     unsigned long lwhtime, whtime;                    //used to calculate energy used.
  78.  
  79. };
  80.  
  81. Channel ch1,ch2;    //create two incidence of class channel for the two channels
  82.  
  83. //--------------------------------------------------------------------------------------
  84. // SETUP
  85. //--------------------------------------------------------------------------------------
  86. void setup()
  87. {
  88.    lcd.begin(16, 2); // set up the LCD's number of columns and rows:
  89.  
  90.    Serial.begin(9600);
  91.    pinMode(RelayOn,OUTPUT); // this sets the pin named RelayOn to be an output
  92.    pinMode(HRelayOn,OUTPUT); // this sets the pin named RelayOn to be an output
  93.    pinMode(menupin, INPUT); // this sets the pin named menupin to be an input
  94.    pinMode (led_on, OUTPUT); //this sets the pin named led_on to be an output
  95.  
  96.    t_culm = (3600000 * 12);       //On first run, advances the 24hr timer by 12hrs (so can restart at midday!)  
  97.    //t_culm = (3600000 * 23.75);  //FOR TESTING ONLY
  98.    
  99.    digitalWrite(RelayOn,HIGH);   //Switches relay off
  100.    digitalWrite(HRelayOn,HIGH);  //Switches relay off
  101.    
  102.    //Introduces 15 second delay to allow caps to charge up
  103.     lcd.clear();
  104.     lcd.setCursor(0, 0);
  105.     lcd.print("  Please Wait  ");
  106.     lcd.setCursor(0, 1);
  107.     lcd.print("Initialising....");
  108.     delay (15000);
  109. }
  110.  
  111. unsigned long wtime;
  112.  
  113. //--------------------------------------------------------------------------------------
  114. // MAIN LOOP
  115. //--------------------------------------------------------------------------------------
  116. void loop()
  117. {
  118.   //-------------------------------------------------------------------------------------------
  119.   // 1) Calculate energy monitor values
  120.   //-------------------------------------------------------------------------------------------
  121.   ch1.emon_calc(inPinI_1,ICAL_1);  //Energy Monitor calc function for channel 1, pass Arduino analog in pin nummber and calibration coefficient
  122.   ch2.emon_calc(inPinI_2,ICAL_2);  //Energy Monitor calc function, for channel 2, pass Arduino analog in pin nummber and calibration coefficient
  123.  
  124.   //--ENERGY MEASURMENT CALCULATION----------------  
  125.  
  126.  //Power measurement
  127.   t_now = millis();
  128.     if ( t_now > t_last ) {   //check to see if millis has overflowed back to zero (after approx 49 days)
  129.       t_diff = t_now - t_last; } //if not, the time each emon cycle takes
  130.         else {  //if millis has reset...
  131.           t_diff = 4127; }   //t_diff = (the amount of time each average emon cycle takes), again dealing with the millis reset.
  132.   t_culm += t_diff;
  133.   t_last = t_now;
  134.  
  135.   if ( t_culm > (3600000 * 24)){ //check to see if 24hrs has elapsed
  136.   Solarkwh = 0; // RESET
  137.   Mainskwh = 0; // RESET
  138.   t_culm = 0;   // RESET
  139.   }
  140.  
  141.   //ch1.realPower = 2534;  //FOR TESTING ONLY
  142.   //ch2.realPower = 1522;  //FOR TESTING ONLY
  143.  
  144.   //Calculate number of kwh generated.
  145.   Solarkwh = Solarkwh + ((ch1.realPower/1000.0) * 1.0/3600.0 * (t_diff/1000.0));
  146.   Mainskwh = Mainskwh + ((ch2.realPower/1000.0) * 1.0/3600.0 * (t_diff/1000.0));  
  147.  
  148.     //------------Data Output-------------
  149.      
  150.     //Read menupin to see what menu to display
  151.     menuState = digitalRead(menupin);
  152.     if ( menuState == LOW) {
  153.     menu = menu+1; }
  154.     if (menu > 4){
  155.     menu = 0;
  156.     }  
  157.    
  158.     //MENU 0  
  159.     if (menu == 0) {
  160.     // clear the lcd screen
  161.     lcd.clear();
  162.     //if-else statement to alter LCD print format depending upon power reading
  163.     lcd.setCursor(0, 0);
  164.         if (ch1.realPower >= 1000)  {
  165.       lcd.print("Solar "); lcd.print(ch1.realPower / 1000.0, 3); lcd.print(" kW");  }
  166.     else  {
  167.       lcd.print("Solar "); lcd.print(ch1.realPower, 0); lcd.print(" Watts");  }
  168.    
  169.     lcd.setCursor(0, 1);
  170.         if (ch2.realPower >= 5000)  {
  171.       lcd.print("M/Power over 5kW"); }
  172.     else
  173.       if (ch2.realPower >= 1000)  {
  174.       lcd.print("Mains "); lcd.print(ch2.realPower / 1000.0, 3); lcd.print(" kW");  }
  175.     else  {
  176.       lcd.print("Mains "); lcd.print(ch2.realPower, 0); lcd.print(" Watts");  }
  177.     }
  178.  
  179.     //MENU 1 - to enable detailed readings for calibration
  180.     if (menu == 1) {
  181.     lcd.clear();
  182.     lcd.setCursor(0, 0);
  183.     lcd.print("Solar "); lcd.print(Solarkwh); lcd.print(" kWh");
  184.     lcd.setCursor(0, 1);
  185.     lcd.print("Mains "); lcd.print(Mainskwh); lcd.print(" kWh");  }
  186.  
  187.     //MENU 2 - to enable detailed readings for calibration
  188.     if (menu == 2) {
  189.     lcd.clear();
  190.     lcd.setCursor(0, 0);
  191.     lcd.print("PowerF "); lcd.print(ch1.powerFactor, 2);
  192.     lcd.setCursor(0, 1);
  193.     lcd.print("Voltage "); lcd.print(ch1.Vrms, 0); lcd.print(" V");  }
  194.    
  195.     //MENU 3 - to enable detailed readings for calibration
  196.     if (menu == 3) {
  197.     lcd.clear();
  198.     lcd.setCursor(0, 0);
  199.     lcd.print("Solar "); lcd.print(ch1.realPower, 0); lcd.print(" W");
  200.     lcd.setCursor(0, 1);
  201.     lcd.print("Mains "); lcd.print(ch2.realPower, 0); lcd.print(" W");  }
  202.    
  203.     //MENU 4 - DEMO MODE
  204.     if (menu == 4) {
  205.     lcd.clear();
  206.     lcd.setCursor(0, 0);
  207.     lcd.print ("Press button for");
  208.     lcd.setCursor(0, 1);
  209.     lcd.print("3 secs for demo");
  210.     delay (3000);
  211.     if (digitalRead(menupin)== LOW) {  //check to see if button is still pressed
  212.     lcd.clear();
  213.     lcd.setCursor(0, 0);
  214.     lcd.print ("DEMO MODE");
  215.     delay (2000);
  216.     lcd.clear();
  217.     lcd.setCursor(0, 0);
  218.     lcd.print("Solar 1.326 kW");
  219.     lcd.setCursor(0, 1);
  220.     lcd.print("Mains 298 Watts");
  221.     digitalWrite (led_on,HIGH);
  222.     delay (10000);
  223.     lcd.clear();
  224.     lcd.setCursor(0, 0);
  225.     lcd.print("Solar 18.36 kWh");
  226.     lcd.setCursor(0, 1);
  227.     lcd.print("Mains 4.29 kWh");
  228.     digitalWrite (led_on,HIGH);
  229.     delay (10000);
  230.     lcd.clear();
  231.     lcd.setCursor(0, 0);
  232.     lcd.print("PowerF 0.98");
  233.     lcd.setCursor(0, 1);
  234.     lcd.print("Voltage 247 V");
  235.     digitalWrite (led_on,HIGH);
  236.     delay (10000);
  237.     menu = 0; }
  238.     else {
  239.       menu = 0; }
  240.     }
  241.        
  242.  //checks to see if can run at full power
  243.   if (ch1.realPower > (ch2.realPower +1090)) {
  244.       digitalWrite(HRelayOn,HIGH); //turn the half power output off
  245.       digitalWrite(RelayOn,LOW); //turn the full output on
  246.        }
  247.   else{
  248.       digitalWrite(RelayOn,HIGH); //turn the output off
  249.        //checks to see if can run at half power
  250.        if (ch1.realPower > (ch2.realPower +545)) {
  251.         digitalWrite(HRelayOn,LOW); }//turn the output on
  252.           else  {
  253.            digitalWrite(HRelayOn,HIGH); //turn the output off
  254.      }
  255.    }
  256.  //LED control
  257.    if (digitalRead(RelayOn) == LOW) {
  258.      analogWrite(led_on, 200);  }
  259.    else if (digitalRead(HRelayOn) == LOW) {
  260.      analogWrite(led_on, 30);   } //quarter brightness
  261.    else {
  262.          digitalWrite (led_on,HIGH);
  263.          delay (100);
  264.          digitalWrite (led_on,LOW);
  265.         }
  266.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement