Version 6

    Arduino Home

    An Open-Source platform to create digital devices and interactive objects that sense and control physical devices.

    Arduino Tutorials
    Arduino Projects

     

    From now until Arduino Day we'll be going through the element14 community and doing roundup posts on Arduino.

     

    This roundup post visits one of the classic Design Challenges and a personal favorite of mine the Vertical Farming.  

     

    This post focuses on the Arduino portion of the Automated Green House by m.ratcliffe .   You can view this project in its entirety at the following location:

     

    Automated Green House Blog's Home Page [Updated: 01/12/2016 < British Format]

     

    Automated Green House by m.ratcliffe

     

    Automated Green House Blog:7 -  Arduino Temperature Compensating Feeder

     

    m.ratcliffe 's Automated Green House featured an Arduino Temperature Compensating Feeder.   He provides the basics on how you would compensate for temperature changes. Because most species of fish are cold blooded animals, the water temperature they live in has a big effect on how they behave.   Cold water makes fishes slower and less hungry. For engineers, this means you have an input to a system that needs to vary with temperature if you want to use open-loop control. He demonstrates how nearly every aspect of a fish can be represented mathematically or closely approximated.

     

    Below is a table representing the amount to feed fish [Tilapia] as a function of temperature to maximise food productivity[1]:

    132b.GIF

    DFR: Daily Feed Rate, represent as percent of fish mass in the system.

     

    The Wiring diagram:

    AruinoTemp2_bb.jpg

     

    There are no external pull up/down resistors in this circuit. The button is connected to Pin A4, that is set up as an input with the internal pull up set to on, when the button is pressed it will pull A4 to LOW.

    The Temperature sensor usually has an external pull up, but he's using a modified one-wire library that does this using the internal pull ups for the data pin.

     

    Automated Green House Blog:8 -  Water Usage

     

    Another thing he kept an eye on was water flow.  He opted for a hall effect flow meter.

     

    How It works:

     

    >ISR to log number of pulses

    >Convert the Pulses/second for a flow rate

    >Logs Total Pulses for total water usage

    >Checks there isnt a major leak [flow rate is reduced because I use drip irrigation]

     

     

    Pinout.png

     

    Automated Green House Blog:8.2 - Water Meter Calibration

     

    He uses an Arduino Uno and an LCD shield to measure flowrate and total water used.   He provides code to get real world values of number of pulses per L of water Delivered:

     

    Connect the water meter in-line, and prime system

    >Turn tap off

    >Start Arduino

    >Turn tap on to fill up a known volume

    Clicks per L= Volume/Pulse Count   [Volume must be in L]

    We can use this value in our previous code to get really accurate readings

     

    LCD Shiled that it will work with:

     

    LCD

     

    Pinout [Solder onto LCD shiled is preferred ] :

     

    pinout

     

     

     

     

    Automated Green House Blog:9.2 - Updated uptime counter LCD

     

    It is useful to have an uptime counter on the arduino so that you are aware of any recent resets. Mainly because you need to be aware of any problems making it reset and know that any readouts for totals [ie water usage] are not a true representation.  He provides the following code for this:

     

    Michael Ratcliffe  Mike@MichaelRatcliffe.com
    
        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see .
    
    
    */
    
    
    //************************** Just Some basic Definitions used for the Up Time LOgger ************//
    long Day=0;
    int Hour =0;
    int Minute=0;
    int Second=0;
    int HighMillis=0;
    int Rollover=0;
    
    
    
    
    //************** Setup routine - Runs once at power up **************************//
    void setup(){
    Serial.begin(9600); // starting Serial Com's
    
    };
    
    
    //****** Main Loop - Put your Code Here ********************//
    void loop(){
    
    uptime(); //Runs the uptime script located below the main loop and reenters the main loop
    print_Uptime();
    delay(500);
    };
    
    
    
    //************************ Uptime Code - Makes a count of the total up time since last start ****************//
    
    
    void uptime(){
    //** Making Note of an expected rollover *****//
    if(millis()>=3000000000){
    HighMillis=1;
    
    
    }
    //** Making note of actual rollover **//
    if(millis()<=100000&&HighMillis==1){
    Rollover++;
    HighMillis=0;
    }
    
    
    long secsUp = millis()/1000;
    
    
    Second = secsUp%60;
    
    
    Minute = (secsUp/60)%60;
    
    
    Hour = (secsUp/(60*60))%24;
    
    
    Day = (Rollover*50)+(secsUp/(60*60*24));  //First portion takes care of a rollover [around 50 days]
                        
    };
    
    
    //******************* Prints the uptime to serial window **********************//
    void print_Uptime(){
    
      Serial.print(F("Uptime: ")); // The "F" Portion saves your SRam Space
      Serial.print(Day);
      Serial.print(F("  Days  "));
      Serial.print(Hour);
      Serial.print(F("  Hours  "));
      Serial.print(Minute);
      Serial.print(F("  Minutes  "));
      Serial.print(Second);
      Serial.println(F("  Seconds"));
    };

     

     

    Automated Green House Blog:9.2 - Arduino EEPROM [Has it ever been written]

     

    He shows you how to store data on the arduino that will survive a reset such as with calibration settings and set points.  EEPROM is non volatile memory that you can write values to and read in the setup loop to keep the values after a reset.  While many blogs will talk about writing and reading EEPROM, this one talks about checking if the memory slot has ever been written to in the past. He wants be able to use the value of a variable (ie setpoint) from the eeprom if there is one, if not he wants to use a defined value from the sketch.

     

    What this code does, it reads the eeprom to see if there is a value to read, if not it ignores the eeprom and substitutes the one from the top of the code.

     

    Here is a serial screenshot showing it in action, resetting makes it move onto the next memory slot:

     

    g

     

    /*
    Script to test how to check if eprom is written or not
    it will start at memory slot 1 and print value if it has ever been written
    it will then write the next empty slot to the value you put at the top of the code
    
    
       28/8/2015  Michael Ratcliffe  Mike@MichaelRatcliffe.com
    
    
              This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see .
    */
    
    
    #include 
    int backupvalue=512;
    
    
    
    
    int i=1;
    int value=100;
    
    
    void setup() {
      Serial.begin(9600);
    Serial.print("Arduino Reset button pressed");
      while (value>=2) {
         i++;
         value = EEPROM.read(i);
         Serial.print("Memory _Slot:");
         Serial.print(i);
         Serial.print("  has saved value:");
         Serial.println(value*4);
         delay(10);
    
    
         //We will stop at 100, you must have got the point by now and I dont know what happens if you write a eprom memory slot that is out of range
         if(i>=100) return;
      };
    value=backupvalue/4;
        EEPROM.write(i, value);
    
    
      // turn the LED on when we're done
      digitalWrite(13, HIGH);
    }
    
    
    void loop() {
      /** Empty loop. **/
    }

     

     

    Here is a sketch to clear your EEPROM for next project:

     

    /*
    * EEPROM Clear
    *
    * Sets all of the bytes of the EEPROM to 0.
    * Please see eeprom_iteration for a more in depth
    * look at how to traverse the EEPROM.
    *
    * This example code is in the public domain.
    */
    
    
    #include 
    
    
    void setup() {
    
    
      /***
        Iterate through each byte of the EEPROM storage.
    
    
        Larger AVR processors have larger EEPROM sizes, E.g:
        - Arduno Duemilanove: 512b EEPROM storage.
        - Arduino Uno:        1kb EEPROM storage.
        - Arduino Mega:       4kb EEPROM storage.
    
    
        Rather than hard-coding the length, you should use the pre-provided length function.
        This will make your code portable to all AVR processors.
      ***/
    
    
      for (int i = 0 ; i < EEPROM.length() ; i++) {
        EEPROM.write(i, 0);
      }
    
    
      // turn the LED on when we're done
      digitalWrite(13, HIGH);
    }
    
    
    void loop() {
      /** Empty loop. **/
    }

     

     

    Automated Green House Blog:10.1 - Update Code For Three Dollar EC PPM Meter for MCU

     

    This code is a slight update of the last one, updated:

    >Better Uptime Counter

    >LCD Shield

    >New Pin out Diagram

    >Restart Protected Calibration Details

    >EU and US Plug Calibrated Probe

     

    Also a quick update to the code so the calibration value will survive a power cut, we are storing the cell constant K [a float] in EEPROM as a scaled int, so there may be a slight change in the value following a reboot [but that small it wont make much difference].

     

     

    Cell Constants

    I Recommend Calibrating your probe but if that is not an option at this time the following cell constants [K] will give a good estimated readout:

    EU plug: K= 1.76

    US Plug K= 2.88

     

    Calibration

    If it needs instructions to be operated someone engineered it wrong, the lcd should explain itself to you at start up. If you are still stuck watch the youtube video to see how I calibrate it.

    Calibrate with an EC of about 50% your maximum expected reading for best results.

     

    The NEW Pinout:

     

     

    Pinout

    Save some wire and solder the divider onto a pin header

     

    Header

     

    Automated Green House Blog:11.1 - Self Optimising Automated Nutrient Doser - EC Optimisation

     

    This entry covers the theory and implementation of optimizing the EC set-point for the grow system. Instead of the user specifying the EC setpoint he lets the controller optimize for the setpoint itself.

     

    Basic theory:

     

    A plant will only take the nutrients it requires from the growing fluid. The concentration of the growing fluid is dependant on:

    >Temperature

    >Sunlight intensity

    >Plant strain

    >CO2 abundance

     

     

    Here is the code for his ElCheapo Arduino EC-PPM measurements and Nutrient Dowser and EC tuning script:

     

    /*
      ElCheapo Arduino EC-PPM measurments and Nutrient Doser and EC tuning Script
    
    
      ###### Experimental Theory, not yet tested!!!!  Use at your own risk, if in doubt use the previose version with a static EC setpoint
    
      This scrip uses a common USA two prong plug and a 1Kohm Resistor to measure the EC/PPM of a Aquaponics/Hydroponics Sytem.
      Then It Increases the Nutrient content until the set point is reached
      It will Learn the system variables, plug in some rough estimates and the controller will work the rest out for itlself
      The EC will also change to adjust for the perfect EC
    
    
      28/8/2015  Michael Ratcliffe  Mike@MichaelRatcliffe.com
    
    
              This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see .
    
        Parts:
        -Arduino - Uno/Mega
        -Standard American two prong plug
        -1 kohm resistor
        -DS18B20 Waterproof Temperature Sensor
        -FluidPump [Smaller is better];
    
        Limitations:
        -Cell Constant [K] and ECSetpoint must be less than 5.0 or it will Mess with the way we save values in EEPROM
        -A reset will change your set point and kell constant slightly, but not to a great extent
        -EEPROM seems to survive a reflash, so changing values in the code will not change them in the flashed software. you will need to do it via the LCD
    
        See www.MichaelRatcliffe.com/Projects for a Pinout and user guide or consult the Zip you got this code from
    
    */
    
    
    //************************** Libraries Needed To Compile The Script [See Read me In Download] ***************//
    // Both below Library are custom ones [ SEE READ ME In Downloaded Zip If You Dont Know how To install] Use them or add a pull up resistor to the temp probe
    
    
    #include 
    #include 
    #include  //Standard LCD Lbrary
    #include  //Standard EEPROM Library
    
    
    //************************* User Defined Variables ******************************************************//
    // Rememebr to ad .0 after any float definition or it will return to an initiger, ie 1.0 not 1
    
    
    
    
    
    
    //********************** System Information *************************************//
    
    
    float TankSize =10; //SystemVolume  in Liters
    float PumpRate=0.; //Flow rate of dosing pump in L per min
    long DosingInterval =60; //How often you want to dose the tank in minutes, hour intervals will be fine for most systems
    long MixingTime =30; //The time for mixing of nutrients in minutes [I have a lot of water flow so 60 seonds is fine for me, if in doubt increase it to half a hour]
    
    
    
    
    int Pump =14; //Pin Controlling relay for nutrient Pump
    int OFF =0;
    int ON=1;
    
    
    //****************************** System EC Value *******************************//
    //Changes for what plants you are growing, sun intensity and temperature
    
    
    //###If you are using urine in a system and have not yet got a established Bacteria bed set this to ECSetpoint=0.7 for a week to let the bacteria become established##
    
    
    float ECSetpoint =1.0; // How Strong you want the water system to be nutrient wise to begin with
    float MinECSetpoint =0.5;
    float MaxECSetpoint =2.5;
    
    
    
    
    //******************** Nut Tank EC *********************************************//
    //the code will optimise this number after every dosing, so we are selecting the highest end and allowing the arduino to work the rest out its self
    //You are using a nutrient that states the NPK and not a overpriced one that used the words "Boost" "flower" "Super" but hides the important NPK ratios?
    //If not Save yourself a fortune and switch to a cheap one that is honest about its NPK
    
    
    //We need to put in a estimated start point for the controller to start with
    //For an estimate take the EC Estimate= (N*20) + (P*8.8) +(K*16)
    
    
    float ECFluidEstimate =100.0; //if you dont know the value stick with 1000, it will sort itself out
    
    
    
    
    //***********************************EC Meter **********************************//
    
    
    
    
    //##################################################################################
    //-----------  Do not Replace R1 with a resistor lower than 300 ohms    ------------
    //##################################################################################
    
    
    
    
    int R1= 1000; //The resitor we placed in voltage divider
    int Ra=25; //Resistance of Arduino Digital Pins
    //float Rp=0; //Resistance of figure 8 connector
    int ECPin= A8;
    int ECGround=A9;
    int ECPower =A12;
    
    
    //************ Temp Probe Related *********************************************//
    #define ONE_WIRE_BUS 26          // Data wire For Temp Probe is plugged into pin 10 on the Arduino
    const int TempProbePossitive =22;  //Temp Probe power connected to pin 9
    const int TempProbeNegative=24;    //Temp Probe Negative connected to pin 8
    
    
    //************************* User Defined Variables ********************************************************//
    
    
    float CalibrationEC=1.380; //EC value of Calibration solution is s/cm
    
    
    //*********** Converting to ppm [Learn to use EC it is much better**************//
    // Hana      [USA]        PPMconverion:  0.5
    // Eutech    [EU]          PPMconversion:  0.64
    //Tranchen  [Australia]  PPMconversion:  0.7
    // Why didnt anyone standardise this?
    
    
    float PPMconversion=0.5;
    
    
    //********************** Cell Constant For Ec Measurements *********************//
    //Mine was around 2.9 , with plugs being a standard size they should all be the same
    //I Recommend Calibrating your probe but if that is not an option at this time the following cell constants [K] will give a good estimated readout:
    //EU plug: K= 1.76
    //US Plug K= 2.88
    float K=2.88;
    
    
    //*************Compensating for temperature ************************************//
    //The value below will change depending on what chemical solution we are measuring
    //0.019 is generaly considered the standard for plant nutrients [google "Temperature compensation EC" for more info
    float TemperatureCoef = 0.02; //this changes depending on what chemical we are measuring
    
    
    //***************************** END Of Recomended User Inputs *****************************************************************//
    //********************************************************//
    
    
    // select the pins used on the LCD panel
    LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    
    
    // define some values used by the panel and buttons
    int lcd_key    = 0;
    int adc_key_in  = 0;
    int button =0;
    #define btnRIGHT  1
    #define btnUP    2
    #define btnDOWN  3
    #define btnLEFT  4
    #define btnSELECT 5
    #define btnNONE  6
    
    
    int Screen =1;
    
    
    OneWire oneWire(ONE_WIRE_BUS);// Setup a oneWire instance to communicate with any OneWire devices
    DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature.
    
    
    float Temperature=10;
    float EC=0;
    float EC25 =0;
    int ppm =0;
    
    
    float raw= 0;
    float Vin= 5;
    float Vdrop= 0;
    float Rc= 0;
    
    
    
    
    
    
    float PumpTime=0; //Variable for pumping duration
    long MixingInterval=0; //variable for when to check new EC
    float PostDocingEC=0;
    float PreDosingEC =0;
    long StartDosingMillis =0;
    int NutesAdded=0;
    
    
    long time=0;
    
    
    //********************** Some Variables For Loging Min/Max Values ********************************//
    float MinEC=100;
    float MaxEC=0;
    float MinT=100;
    float MaxT=0;
    
    
    //************************** Just Some basic Definitions used for the Up Time LOgger ************//
    long Day=0;
    int Hour =0;
    int Minute=0;
    int Second=0;
    int HighMillis=0;
    int Rollover=0;
    
    //**************************Some Stuff For Calibration ******************************************//
    float TemperatureFinish=0;
    float TemperatureStart=0;
    int i=0;
    float buffer=0;
    float Kt=0;
    
    
    //***********************Some Stuff for Self Learning and Errors********************************//
    float LastGoodEstimate= 0;
    float PumECRateStart=0;
    float PumECRate=0;
    int error=6; // 6 means no error
    long Doses=0;
    long LastRun=0;
    int ECHold=0;
    
    
    
    
    //*********************** EPROM Stuff [So SetPoint and Cal Survive a reboot] ******************//
    int value;
    int addresSetpoint=10;
    int addresCalibration=0;
    
    
    
    
    
    
    //*********************************Setup - runs Once and sets pins etc ******************************************************//
    void setup()
    {
      Serial.begin(9600);
      pinMode(TempProbeNegative , OUTPUT ); //seting ground pin as output for tmp probe
      digitalWrite(TempProbeNegative , LOW );//Seting it to ground so it can sink current
      pinMode(TempProbePossitive , OUTPUT );//ditto but for positive
      digitalWrite(TempProbePossitive , HIGH );
      pinMode(ECPin,INPUT);
      pinMode(ECPower,OUTPUT);//Setting pin for sourcing current
      pinMode(ECGround,OUTPUT);//setting pin for sinking current
    
      pinMode(Pump,OUTPUT);//setting pin for sinking current
      digitalWrite(Pump,OFF); //makes sure we are starting from a stop
      digitalWrite(ECGround,LOW);//We can leave the ground connected permanantly
    
    
      delay(100);// gives sensor time to settle
      sensors.begin();
    
      //****************Converting to milli seconds********************//
      DosingInterval =DosingInterval*60000; //Coveerting to milliseconds
      MixingTime =MixingTime*60000;      // Converting to milliseconds
      MixingInterval=DosingInterval+MixingTime;
      PumpRate=PumpRate/60.0; //converting to L.Second-1
    
      //***************Converting to MCU related units ****************//
      PumECRate=ECFluidEstimate*(PumpRate/TankSize);    //  EC.Second-1
      PumECRate=PumECRate*2.0;//Just incase people overestimated some values
      LastGoodEstimate=PumECRate;
      PumECRateStart=PumECRate;
    
      //************** Restart Protection Stuff ********************//
      //Setpoint
      value = EEPROM.read(addresSetpoint);
      if (value <=254) ECSetpoint=value*0.02;
      //Calibration
      value = EEPROM.read(addresCalibration);
      if (value <=254) K=value*0.02;
    
    
    
    
    
    R1=(R1+Ra); //Taking into acount Digital Pin Resitance
    
    
    lcd.begin(16, 2);              // start the library
    lcd.setCursor(0,0);
    delay(1000);
    lcd.print("Nutrient Doser");
    lcd.setCursor(0,1);
    delay(1000);
    lcd.print("Mike Ratcliffe");
    lcd.setCursor(0,1);
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Free Software  ");
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Mike Ratcliffe");
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Free Software  ");
    delay(1000);
    lcd.setCursor(0,0);
    lcd.print("To Calibrate      ");
      lcd.setCursor(0,1);
    lcd.print("Hold Select      ");
    delay(3000);
      lcd.setCursor(0,0);
    lcd.print("To Navigate        ");
      lcd.setCursor(0,1);
    lcd.print("Use Up-Down    ");
    delay(3000);
    
    
    GetEC(); //gets first reading for LCD and then resets max/min
    MinEC=100.0;
    MaxEC=0.0;
    MinT=100.0;
    MaxT=0.0;
    
    
    
    
    
    
    };
    //******************************************* End of Setup **********************************************************************//
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    //************************************* Main Loop - Runs Forever ***************************************************************//
    //Moved Heavy Work To subroutines so you can call them from main loop without cluttering the main loop
    //Dont Measure the EC more than once every five second "GetEC()" or you will get bad readings and wear your probe out
    
    
    void loop()
    {
    //*********Takes care of millis rolover**************//
    if(millis()<=5000){
      NutesAdded=0;
      digitalWrite(Pump,OFF);
        delay(5000);
    };
    
    
    //*********Check if it is time to dose the system, we wont dose it if the probe is broken or if we are colse to the setppoint ********//
    if( (button==1 || millis()%DosingInterval<=1000) && (error>=4 && EC25<=(ECSetpoint-0.1) && NutesAdded==0) ){
    ECTuning();
    NutrientAddition();
    NutesAdded=1;
    Doses++;
    };
    //********This fine tunes for the perticular system **************//
    if((millis()>=(PumpTime+MixingTime+StartDosingMillis)) && NutesAdded==1){
    EstimateEC();                                        // Goes to the script to estimate the nutrient source EC
    NutesAdded=0;
    };
    
    
    
    
    
    
    //********** Runs the Function to estimate the EC of the hydroponics system **********//
    if (millis()%5000<=1000 && ECHold==0){
    GetEC();
    ECHold=1;
    };
    if (millis()%5000>=1000){
    ECHold=0;
    };
    
    
    //**************** Turns the pump off at the end of the pumping time********************//
    if (millis()>=StartDosingMillis+PumpTime){  //Still need to take care of millis rollover!?
    digitalWrite(Pump,OFF);
    
    
    };
    
    
    read_LCD_buttons();
    Calibration();
    ChangeECSetpoint();
    Error();
    PrintReadings();  // Cals Print routine [below main loop]
    
    
    //************* Stopinf Funky Readings From unmixed solution**********//
    if(NutesAdded==0) LogEC();
    
    
    delay(50);
    
    
    }
    //************************************** End Of Main Loop **********************************************************************//
    
    
    
    
    
    
    
    
    
    
    
    
    //*******************************Turns on Pump To Dose System *********************************//
    
    
                      void NutrientAddition(){
                
                      PreDosingEC =EC25; //Makes note of the initial EC
                      PumpTime=1000*((ECSetpoint-PreDosingEC)/PumECRate);
                      StartDosingMillis=millis();
                      digitalWrite(Pump,ON);
                
                      };
    
    
    
    
    //******************************** System Automatd Learning ************************************//
                    //This Function optimises the dosing volume for the main tank volume and Strength of Nutrient tank
              
              
                    void EstimateEC(){
                
                    PostDocingEC=EC25;  //Makes Note of the EC at the end of the addition
              
                    //*********Rapidly change EC Estimation on startup************//                      
                    if(PostDocingEC>=(PreDosingEC+0.05)){
              
                    PumECRate =(1000.0*((PostDocingEC-PreDosingEC)/PumpTime));
                    LastGoodEstimate=PumECRate;
                    }
                            
                    else  PumECRate=PumECRate/2.0;                        
                    };
    
    
    
    
    
    
    //************ This Loop Is called From Main Loop************************//
    void GetEC(){
    
    
    //*********Reading Temperature Of Solution *******************//
    
    
    
    
    sensors.requestTemperatures();// Send the command to get temperatures
    Temperature=sensors.getTempCByIndex(0); //Stores Value in Variable
    raw= analogRead(ECPin);
    
    
    //************Estimates Resistance of Liquid ****************//
    digitalWrite(ECPower,HIGH);
    //raw= analogRead(ECPin);
    raw= analogRead(ECPin);// This is not a mistake, First reading will be low beause if charged a capacitor
    digitalWrite(ECPower,LOW);
    
    
    
    
    //***************** Converts to EC **************************//
    Vdrop= (Vin*raw)/1024.0;
    Rc=(Vdrop*R1)/(Vin-Vdrop);
    Rc=Rc-Ra;
    EC = 1000/(Rc*K);
    LogEC();
    //*************Compensating For Temperaure********************//
    EC25  =  EC/ (1.0+ TemperatureCoef*(Temperature-25.0));
    ppm=(EC25)*(PPMconversion*1000);
    
    
    ;}
    
    
    
    
    
    
    
    
    //***********This Loop Is called From  Else Where- Prints to serial usefull info **************//
                    void PrintReadings(){
              
                    Serial.print("EC: ");
                    Serial.print(EC25);
                    Serial.print(" Simens  ");
                    Serial.print(ppm);
                    Serial.print(" ppm  ");
                    Serial.print(Temperature);
                    Serial.print(" *C  ");
                    Serial.print("PumpRate EC/s: ");
                    Serial.println( PumECRate);
              
          
                                    
                                    
                                          //** First Screen Shows Temp and EC **//
                                          if(Screen==1){
                                          lcd.setCursor(0,0);
                                          lcd.print("Arduino EC-PPM  ");
                                          lcd.setCursor(0,1);
                                          lcd.print("EC:              ");
                                          lcd.setCursor(3,1);
                                          lcd.print(EC25);
                                          lcd.setCursor(9,1);
                                          lcd.print(Temperature);
                                          lcd.print("'C");
                                          }
                                          //** Second Screen Shows PPM **//
                                          else if(Screen==2){
                                          lcd.setCursor(0,0);
                                          lcd.print("Arduino EC-PPM  ");
                                          lcd.setCursor(0,1);
                                          lcd.print("PPM:        ");
                                          lcd.setCursor(4,1);
                                          lcd.print(ppm);
                                          lcd.setCursor(9,1);
                                          lcd.print(Temperature);
                                          lcd.print("'C");
                                          }
                                    
                                          //**Third Screen Shows Min and Max **//
                                          else if(Screen==3){
                                          lcd.setCursor(0,0);
                                          lcd.print("Min:              ");
                                          lcd.setCursor(4,0);
                                          lcd.print(MinEC);
                                          lcd.setCursor(9,0);
                                          lcd.print(MinT);
                                          lcd.print("'C");
                                          lcd.setCursor(0,1);
                                          lcd.print("Max:              ");
                                          lcd.setCursor(4,1);
                                          lcd.print(MaxEC);
                                          lcd.setCursor(9,1);
                                          lcd.print(MaxT);
                                          lcd.print("'C");
                                          }
                                    
                                    
                                          else if(Screen==4){
                                  
                                          lcd.setCursor(0,0);
                                          lcd.print("Uptime Counter:              ");
                                    
                                          lcd.setCursor(0,1);
                                          lcd.print("                                    ");//Clearing LCD
                                          lcd.setCursor(0,1);
                                          lcd.print(Day);
                                          lcd.setCursor(3,1);
                                          lcd.print("Day");
                                          lcd.setCursor(8,1);
                                          lcd.print(Hour);
                                          lcd.setCursor(10,1);
                                          lcd.print(":");
                                          lcd.setCursor(11,1);
                                          lcd.print(Minute);
                                          lcd.setCursor(13,1);
                                          lcd.print(":");
                                          lcd.setCursor(14,1);
                                          lcd.print(Second);
                                    
                                    
                                          }
                      
                                    
                                          else if(Screen==5){
                                      
                                          lcd.setCursor(0,0);
                                          lcd.print("Factors          ");
                                          lcd.setCursor(8,0);
                                          lcd.print("PPMC:");
                                          lcd.setCursor(13,0);
                                          lcd.print(PPMconversion);
                                    
                                          lcd.setCursor(0,1);
                                          lcd.print("K:              ");
                                          lcd.setCursor(2,1);
                                          lcd.print(K);
                                          lcd.setCursor(9,1);
                                          lcd.print("a:");
                                          lcd.setCursor(11,1);
                                          lcd.print(TemperatureCoef);
                                          }
                                          else if(Screen==6){
                                      
                                          lcd.setCursor(0,0);
                                          lcd.print("EC.Sec-1:                  ");
                                          lcd.setCursor(10,0);
                                          lcd.print(PumECRate,5);
                                    
                                          lcd.setCursor(0,1);
                                          lcd.print("Doses:                          ");
                                          lcd.setCursor(10,1);
                                          lcd.print(Doses);
                                          }
                                          else if(Screen==7){
                                      
                                          lcd.setCursor(0,0);
                                          lcd.print("EC Setpoint:        ");
                                          lcd.setCursor(12,0);
                                          lcd.print(ECSetpoint,3);
                                    
                                          lcd.setCursor(0,1);
                                          lcd.print("Hold Select Change                        ");
                                    
                                          }
              
            
                  if((millis()%6000)<=3000){
              
                    //************************* Printing any errors we have ***********//
                    if  (error==1) {lcd.setCursor(0,0);
                                          lcd.print("Error:          ");
                                          lcd.setCursor(8,0);
                                          lcd.print(error);
                                          lcd.setCursor(0,1);
                                          lcd.print("Probe Problem              "); }
                                    
                    else if (error==2) {lcd.setCursor(0,0);
                                          lcd.print("Error:          ");
                                          lcd.setCursor(8,0);
                                          lcd.print(error);
                                          lcd.setCursor(0,1);
                                          lcd.print("Large Overshoot              "); }
                                    
                    else if (error==3) {lcd.setCursor(0,0);
                                          lcd.print("Error:          ");
                                          lcd.setCursor(8,0);
                                          lcd.print(error);
                                          lcd.setCursor(0,1);
                                          lcd.print("Temp Problem              "); }
                                    
                    else if (error==4) {lcd.setCursor(0,0);
                                          lcd.print("Error:          ");
                                          lcd.setCursor(8,0);
                                          lcd.print(error);
                                          lcd.setCursor(0,1);
                                          lcd.print("Pump Problem              "); }
                                    
                    else if (error==5  ) {lcd.setCursor(0,0);
                                          lcd.print("Error:          ");
                                          lcd.setCursor(8,0);
                                          lcd.print(error);
                                          lcd.setCursor(0,1);
                                          lcd.print("System Learning              "); }
                    else;
                
                
                
                  };
                                
                  
                    /*
                    //********** Usued for Debugging ************
                    Serial.print("Vdrop: ");
                    Serial.println(Vdrop);
                    Serial.print("Rc: ");
                    Serial.println(Rc);
                    Serial.print(EC);
                    Serial.println("Siemens");
                    //********** end of Debugging Prints *********
                    */
    };
    
    
    
    
    void read_LCD_buttons(){
      adc_key_in = analogRead(0);      // read the value from the sensor
    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    if (adc_key_in > 1000)  button =0;
    
    
    else if (adc_key_in < 50)  button =1;
    else if (adc_key_in < 250)  button =2;
    else  if (adc_key_in < 450)  button =3;
    else if (adc_key_in < 650)  button =4;
    else if (adc_key_in < 850)  button =5;
    
    
    if(button==2){
    Screen++;
    
    
    }
    else if (button==3){
    Screen--;
    };
    
    
    if (Screen>=7) Screen=7;
    if(Screen<=1) Screen=1;
    };
    
    
    //******************************* LOGS Min/MAX Values and Uptime Counter*******************************//
                              void LogEC(){
                          
                          
                                //**********So We dont Get First Few Readings**********//
                                                              
                                                                    if( Doses==5){
                                                                      MinEC=100.0;
                                                                      MaxEC=0.0;
                                                                      MinT=100.0;
                                                                      MaxT=0.0;
                                                                    };
                                                              
                        
                                if(EC25>=MaxEC)  MaxEC=EC25;
                                if(EC25<=MinEC)  MinEC=EC25;
                          
                                if(Temperature>=MaxT) MaxT=Temperature;
                                if(Temperature<=MinT) MinT=Temperature;
                        
                              //** Making Note of an expected rollover *****//
                              if(millis()>=3000000000){
                              HighMillis=1;
                        
                              }
                              //** Making note of actual rollover **//
                              if(millis()<=100000&&HighMillis==1){
                              Rollover++;
                              HighMillis=0;
                              }
                        
                              long secsUp = millis()/1000;
                        
                              Second = secsUp%60;
                        
                              Minute = (secsUp/60)%60;
                        
                              Hour = (secsUp/(60*60))%24;
                        
                              Day = (Rollover*50)+(secsUp/(60*60*24));  //First portion takes care of a rollover [around 50 days]
                                                
                                                
                              };
    
    
    //******************************* Checks if Select button is held down and enters Calibration routine if it is ************************************//
    void Calibration(){
    
    
    
    
    if(Screen!=5) return;
    if(button!=5) return;
    else delay(1000);
    read_LCD_buttons();
    if(button!=5) return;
    
    
    
    
    
    while(1){
    read_LCD_buttons();
    lcd.setCursor(0,0);
    lcd.print("Set Calibration EC  ");
    lcd.setCursor(0,1);
    lcd.print("EC:                ");
    lcd.setCursor(3,1);
    lcd.print(CalibrationEC);
    
    
    if (button==2) CalibrationEC=CalibrationEC+0.01 ;
    if(button==3)  CalibrationEC=CalibrationEC-0.01;
    if(button==1) break;
    delay(100);
          };
    
    
    lcd.setCursor(0,0);
    lcd.print("Calibrating        ");
    lcd.setCursor(0,1);
    lcd.print("EC:                ");
    lcd.setCursor(3,1);
    lcd.print(CalibrationEC);
    
    
    i=1;
    buffer=0;
    sensors.requestTemperatures();// Send the command to get temperatures
    TemperatureStart=sensors.getTempCByIndex(0); //Stores Value in Variable
    
    
    //************Estimates Resistance of Liquid ****************//
                while(i<=10){
          
              
                digitalWrite(ECPower,HIGH);
                raw= analogRead(ECPin);
        
                digitalWrite(ECPower,LOW);
                buffer=buffer+raw;
                i++;
                delay(5000);
                };
          
          
    raw=(buffer/10.0);
    sensors.requestTemperatures();// Send the command to get temperatures
    TemperatureFinish=sensors.getTempCByIndex(0); //Stores Value in Variable
    
    
    //*************Compensating For Temperaure********************//
    EC =CalibrationEC*(1+(TemperatureCoef*(TemperatureFinish-25.0))) ;
    
    //***************** Calculates R relating to Calibration fluid **************************//
    Vdrop= (((Vin)*(raw))/1024.0);
    Rc=(Vdrop*R1)/(Vin-Vdrop);
    Rc=Rc-Ra; //Taking into account pin resistance
    Kt= 1000/(Rc*EC);
    
    
    
    
    
    
    
    
                        if (TemperatureStart==TemperatureFinish ){
                          Serial.println("  Results are Trustworthy");
                          Serial.print("Calibration Fluid EC: ");
                          Serial.print(CalibrationEC);
                          Serial.print(" S  ");  //add units here
                          Serial.print("Cell Constant K");
                          Serial.print(K);
                    
                    
                          lcd.setCursor(0,0);
                          lcd.print("GoodResults        ");
                    
                    
                          lcd.setCursor(0,1);
                          lcd.print("EC:                    ");
                          lcd.setCursor(3,1);
                          lcd.print(CalibrationEC);
                          lcd.setCursor(9,1);
                          lcd.print("K:");
                          lcd.setCursor(11,1);
                          lcd.print(Kt);
                    
                                  while (1) { // wee need to keep this function running until user opts out with return function
                            
                                  read_LCD_buttons();
                                  if(button==4) return; //exits the loop without saving becauser user asked so
                                  if (button==5){
                              
                              
                                  K=Kt; //saving the new cell constant
                            
                            
                              //******8*Saving the new value to EEprom**********//
                                value=K/0.02;
                                EEPROM.write(addresCalibration, value);
    
    
    
    
                            
                                  lcd.setCursor(0,0);
                                  lcd.print("Saved Calibration        ");
                                                          
                                  lcd.setCursor(0,1);
                                  lcd.print("K:                        ");
                                  lcd.setCursor(3,1);
                                  lcd.print(Kt);
                                  delay(2000);
                                  return;
                                  }
                            
                                  if(millis()%4000>=2000){
                                  lcd.setCursor(0,0);
                                  lcd.print("GoodResults        ");
                            
                            
                                  lcd.setCursor(0,1);
                                  lcd.print("EC:                  ");
                                  lcd.setCursor(2,1);
                                  lcd.print(CalibrationEC);
                                  lcd.setCursor(9,1);
                                  lcd.print("K:");
                                  lcd.setCursor(11,1);
                                  lcd.print(Kt);
                            
                                  }
                                  else{
                            
                                  lcd.setCursor(0,0);
                                  lcd.print("Select To Save      ");
                            
                                  lcd.setCursor(0,1);
                                  lcd.print("Down to Exit          ");
                                  };
                            
                              
                                  }
                    
                          }
                      
                                  else{
                                  Serial.println("  Error Wait For Temperature To settle");
                            
                                            while (1) {
                                            read_LCD_buttons();
                                            if(button==2) Calibration();
                                            if(button==3) return;
                                      
                                            lcd.setCursor(0,0);
                                            lcd.print("Bad Results        ");
                                            lcd.setCursor(0,1);
                                            lcd.print("Press DWN Exit          ");
                                      
                                      }
                    
                                }
    
    
    };
    //**************************************** End OF CALIBRATION ROUTINE ******************************//
    
    
    //**************************************Start OF Function To Change EC Setpoint*********************//
    
    
    void ChangeECSetpoint(){
    if(Screen!=7) return;
    if(button!=5) return;
    
    else delay(1000);
    read_LCD_buttons();
    if(button!=5) return;
    
    
    
    while(1){
    read_LCD_buttons();
    lcd.setCursor(0,0);
    lcd.print("Set EC SetPoint  ");
    lcd.setCursor(0,1);
    lcd.print("R:exit EC:                ");
    lcd.setCursor(11,1);
    lcd.print(ECSetpoint);
    
    
    if (button==2) ECSetpoint=ECSetpoint+0.01 ;
    if(button==3)  ECSetpoint=ECSetpoint-0.01;
    if(button==1) {
      value=ECSetpoint/0.02;
      EEPROM.write(addresSetpoint, value);
    break;
    }
    delay(100);
          };
    
    
    
    
    
    
                    
                      
                          
    
    
    };
    
    
    //*******************************End OF Change EC Setpoint *********************************************//
    
    
    
    
    
    
    
    //*********************************Function to Check for any errors**************************************//
    void Error(){
    error=6; //For Some Reason the Errors are not refreshing like they shoud, this fixes it
    //*********Checking if the Probe is in the Solution********//
      if(EC25<=0.05){
      Serial.println("Probe Problem: Check it is in the liquid and not shorted ");
      error=1;
    
      }
    
    
    
    //***********Checking if we seriosly overshot the setpoint**//
      else if((EC25>=(ECSetpoint*1.3))&& NutesAdded==0){
      Serial.println("Dosing Problem: We overshot the setpoint, Will attempt to fix its self ");
      error=2;
    
      }
    
    
    
    //******** Checking Temp Probe is In range ****************//
    else if((Temperature>=50.0) || (Temperature<=0.5)){
      Serial.println("Temperature Problem: Check Wiring [Also Check Probe has pull up] ");
      error=3;
    }
    
    //****** Checking Dosing Pump Is working******************//
    else if( (PostDocingEC<=(PreDosingEC+0.05) ) && (NutesAdded==0 && EC25<=ECSetpoint-0.2) ){
    Serial.println("Dosing Problem: Check Nute Tank is full and pump is not broken ");
    
                  if(Doses<=10){
                  //Still Geting a good estimate for the EC
                  //error=5;
            
                  };
                  if(Doses>=11) {
                  //Proberbly a pump problem
                    error=4;
                  };
                                    }
    else error=6;
    
    };
    
    
    
    
    
    
    //***************** EC Optimisation ***************************//
    void ECTuning(){
    
    
    //stops us changing to early on [may not be needed
    if(Doses<=10) return;
    
    
    if(PostDocingEC>=EC25)ECSetpoint=ECSetpoint+0.1;
    if(PostDocingEC<=EC25)ECSetpoint=ECSetpoint-0.1;
    
    
    
    
    //Stoping the system getting a bit giddy
    if (ECSetpoint>=MaxECSetpoint) ECSetpoint=MaxECSetpoint;
    if(ECSetpoint<=MinECSetpoint) ECSetpoint=MinECSetpoint;
    
    
    
    
    };

     

     

    Automated Green House Blog:13.2 - PH Control: Measurement Portion

     

    Automated Green House Blog:13.3 - PH Control: PH Probe LCD Readout + Gui

     

    This tutorial and code will work for any analog pH MCU meter and he recommends calibrating often. He put the probe in some pH4 buffer solution over night and the LCD printout gave a   min:3.92   max:4.02   this was probably caused by a temperature change. But it is good enough for his application without compensating for temperature.

     

     

    The pH Probe

     

    k

     

    What else you will need:

    >pH calibration fluid [4 and 7]

    >Arduino mega/uno

     

    Wiring diagram

    pinout

     

    Calibration

    pH probes need to calibrated routinely [one a month is a good idea] so we better have a code that lets us easily calibrate the thing.

     

    Wire the probe up like the diagram above, upload the code below and then:

     

    1:Place Probe into pH7 calibration fluid, open serial

    k

     

    2:Take Recommended cell constant and change it in the top of code

    k

     

     

     

    3:Rinse Probe and place in pH4 calibration fluid

    4:Adjust potentiometer on pH meter shield until ph reading in serial is 4

    k

     

     

    That's it, you are now calibrated and ready to use the pH reading from serial.

     

    This reads the ph probes shield [its an analog value] averages ten readings to reduce any noise and converts the ADC reading into a ph value. outputting the reading to serial:

     

    /*
      Script to print PH to serial
    
    
      28/8/2015  Michael Ratcliffe  Mike@MichaelRatcliffe.com
    
    
              This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see .
    
        Parts:
        -Arduino - Uno/Mega
      -df Robot Ph Probe Kit [SKU:SEN0169] This is a great PH sensor compared to the ones ive had in the past
    
    
    
        See www.MichaelRatcliffe.com/Projects for a Pinout and user guide or consult the Zip you got this code from
    
    */
    
    
    //************************** Libraries Needed To Compile The Script [See Read me In Download] ***************//
    // Both below Library are custom ones [ SEE READ ME In Downloaded Zip If You Dont Know how To install] Use them or add a pull up resistor to the temp probe
    
    
    #include 
    #include 
    #include  //Standard LCD Lbrary
    #include  //Standard EEPROM Library
    
    
    //*********************** User defined variables ****************************//
    //pH meter Analog output to Arduino Analog Input 0
    int PHPin =A15;
    //The calibration constant for the PH probe
    float K_PH=3.64;       
    //used for min/max logs
    float MinPH=10;
    float MaxPH=0;
    
    
    
    
    //************ Temp Probe Related *********************************************//
    #define ONE_WIRE_BUS 26          // Data wire For Temp Probe is plugged into pin 10 on the Arduino
    const int TempProbePossitive =22;  //Temp Probe power connected to pin 9
    const int TempProbeNegative=24;    //Temp Probe Negative connected to pin 8
    float Temperature=0.0;
    float MinT=100;
    float MaxT=0;
    
    
    
    
    //********************** End Of Recomended User Variables ******************//
    
    
    
    
    //************** Some values for working out the ph*****************//
    float Kn=0;
    float phValue=0;
    int i=0;
    long reading=0;
    unsigned long sum=0;
    float average=0;
    
    
    // select the pins used on the LCD panel
    LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    
    
    // define some values used by the panel and buttons
    int lcd_key    = 0;
    int adc_key_in  = 0;
    int button =0;
    #define btnRIGHT  1
    #define btnUP    2
    #define btnDOWN  3
    #define btnLEFT  4
    #define btnSELECT 5
    #define btnNONE  6
    
    
    int Screen =1;
    //Max number of screens on lcd
    const int Last_Screen_no =4;
    //used to debounce input button
    int buttonLast=0;
    
    
    OneWire oneWire(ONE_WIRE_BUS);// Setup a oneWire instance to communicate with any OneWire devices
    DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature.
    
    
    //************************** Just Some basic Definitions used for the Up Time LOgger ************//
    long Day=0;
    int Hour =0;
    int Minute=0;
    int Second=0;
    int HighMillis=0;
    int Rollover=0;
    
    
    //***************** Specifying where to sotre the calibration value [non volatile memory **//
    int value; //we use this to check if memory has been writen or not
    int addresCalibrationPH=50;
    
    
    //************************************** Setup Loop Runs Once ****************//
    void setup()
    {
      Serial.begin(9600);
      pinMode(TempProbeNegative , OUTPUT ); //seting ground pin as output for tmp probe
      digitalWrite(TempProbeNegative , LOW );//Seting it to ground so it can sink current
      pinMode(TempProbePossitive , OUTPUT );//ditto but for positive
      digitalWrite(TempProbePossitive , HIGH );
      read_Temp();// getting rid of the first bad reading
      Read_Eprom();
      Splash_Screen();
    
    
    }
    //******************************** End Of Setup **********************************//
    
    
    //******************** Main Loops runs Forver ************************************//
    void loop()
    {
    
    
    //All these functions are put below the main loop, keeps the loop logic easy to see
    read_LCD_buttons();
    read_Temp();
    Log_Min_MaxTemp();
    ReadPH();
    Log_Min_MaxPH();
    uptime();
    CalibratePH();
    PrintReadings();
    delay(100);
    };
    
    
    //************************** End Of Main Loop ***********************************//
    
    
    
    
    //*************************Print Some useful startup info **************************//
    void startupinfo(){
    Serial.println("pH Probe Script for arduino");
    Serial.println("Released under GNU by Michael Ratcliffe");
    Serial.println("www.MichaelRatcliffe.com");
    Serial.println("Element14 'Adapted_Greenhouse'");
    Serial.println("Using DFRobot PH Probe Pro ");
    Serial.println("How to Use:");
    Serial.println("1:Place Probe into pH7 calibration fluid, open serial ");
    Serial.println("2:Take Recomened cell constand and change it in the top of code");
    Serial.println("3:Rinse Probe and place in pH4 calibration fluid");
    Serial.println("4:Adjust potentiometer on pH meter shield until ph reading in serial is 4");
    Serial.println("    ");
    Serial.println("Thats it your calibrated and your readings are accurate!");
    
    }
    
    
    //***************************** Function to read temperature ********************************//
    void read_Temp(){
    sensors.requestTemperatures();// Send the command to get temperatures
    Temperature=sensors.getTempCByIndex(0); //Stores Value in Variable
    
    
    
    
    }
    
    
    
    
    
    
    //*************************Take Ten Readings And Average ****************************//
    void ReadPH(){
      i=1;
      sum=0;
      while(i<=100){
      reading=analogRead(PHPin);
      sum=sum+reading;
        delay(20);
        i++;
      }
    average=sum/i;
    //converting the average to PH 3.5 part convers mv to ph
    phValue=average*K_PH*5/1024;
    
    }
    
    
    
    
    
    
    
    
    
    
    //****************************** Reading LCd Buttons ****************************//
    void read_LCD_buttons(){
      adc_key_in = analogRead(0);      // read the value from the sensor
    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    if (adc_key_in > 1000)  button =0;
    
    
    else if (adc_key_in < 50)  button =1;
    else if (adc_key_in < 250)  button =2;
    else  if (adc_key_in < 450)  button =3;
    else if (adc_key_in < 650)  button =4;
    else if (adc_key_in < 850)  button =5;
    
    
    
    
    //Second bit stops us changing screen multiple times per input
    if(button==2&&buttonLast!=button){
    Screen++;
    
    
    }
    else if (button==3&&buttonLast!=button){
    Screen--;
    };
    
    
    if (Screen>=Last_Screen_no) Screen=Last_Screen_no;
    if(Screen<=1) Screen=1;
    
    
    buttonLast=button;
    };
    
    
    
    
    
    
    //************************ Uptime Code - Makes a count of the total up time since last start ****************//
    
    
    void uptime(){
    //** Making Note of an expected rollover *****//
    if(millis()>=3000000000){
    HighMillis=1;
    
    
    }
    //** Making note of actual rollover **//
    if(millis()<=100000&&HighMillis==1){
    Rollover++;
    HighMillis=0;
    }
    
    
    long secsUp = millis()/1000;
    
    
    Second = secsUp%60;
    
    
    Minute = (secsUp/60)%60;
    
    
    Hour = (secsUp/(60*60))%24;
    
    
    Day = (Rollover*50)+(secsUp/(60*60*24));  //First portion takes care of a rollover [around 50 days]
                     
    };
    
    
    
    
    //************************** Printing somthing useful to LCd on start up **************************//
    void Splash_Screen(){
    
    
    lcd.begin(16, 2);              // start the library
    lcd.setCursor(0,0);
    delay(1000);
    lcd.print("PH meter      ");
    lcd.setCursor(0,1);
    delay(1000);
    lcd.print("Mike Ratcliffe");
    lcd.setCursor(0,1);
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Free Software  ");
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Mike Ratcliffe");
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Free Software  ");
    delay(1000);
      lcd.setCursor(0,0);
    lcd.print("To Navigate        ");
      lcd.setCursor(0,1);
    lcd.print("Use Up-Down    ");
    delay(3000);
      lcd.setCursor(0,0);
    lcd.print("To Calibrate      ");
      lcd.setCursor(0,1);
    lcd.print("Hold Select      ");
    delay(3000);
    
    
    
    
    };
    
    
    void Read_Eprom(){
    
    
    //************** Restart Protection Stuff ********************//
      //the 254 bit checks that the adress has something stored to read [we dont want noise do we?]
      value = EEPROM.read(addresCalibrationPH);
      if (value <=254) K_PH=value*0.02;
    
    
    };
    
    
    //******************************* Checks if Select button is held down and enters Calibration routine if it is ************************************//
    void CalibratePH(){
    
    
    
    //we check if we are on ph screen and the select button is held
    if(Screen!=4) return;
    if(button!=5) return;
    else delay(1000);
    read_LCD_buttons();
    if(button!=5) return;
    
    
    //we need to stop in this loop while the user calibrates
    while(1){
    read_LCD_buttons();
    lcd.setCursor(0,0);
    lcd.print("Ph Probe in pH7  ");
    lcd.setCursor(0,1);
    lcd.print("Press Right            ");
    //user pressed right?
    if(button==1) break;
    delay(100);
          };
    
    lcd.setCursor(0,0);
    lcd.print("Calibrating              ");
    lcd.setCursor(0,1);
    lcd.print("pH Probe                ");
    
    
    //let probe settle
    delay(2000);
    
    
    //read the ph probe
    ReadPH();
    Kn=((7*1024)/(average*5));
    
    
    
    
    while (1) { // wee need to keep this function running until user opts out with return function
                             
      read_LCD_buttons();
      if(button==4) return; //exits the loop without saving becauser user asked so
      if (button==5){
                               
                               
      K_PH=Kn; //saving the new cell constant
                             
                             
      //*******Saving the new value to EEprom**********//
      value=Kn/0.02;
      EEPROM.write(addresCalibrationPH, value);
      lcd.setCursor(0,0);
      lcd.print("Saved Calibration        ");
                                                           
      lcd.setCursor(0,1);
      lcd.print("K:                        ");
      lcd.setCursor(3,1);
      lcd.print(Kn);
      delay(2000);
    
      lcd.setCursor(0,0);
      lcd.print("Now pH4 and          ");
                                                           
      lcd.setCursor(0,1);
      lcd.print("Adjust Pot                      ");
    
      delay(4000);
      //Put back to main screen and exit calibration
        Screen=1;
      return;
    
    
    
    
    
    
    
                                  }
                             
    if(millis()%4000>=2000){
          ReadPH();
        lcd.setCursor(0,0);
        lcd.print("Calibrated        ");
                             
                             
          lcd.setCursor(0,1);
          lcd.print("PH:                      ");
          lcd.setCursor(3,1);
          lcd.print(phValue);
          lcd.setCursor(8,1);
          lcd.print("K:");
          lcd.setCursor(11,1);
          lcd.print(Kn);
                             
                                  }
    else{
                             
          lcd.setCursor(0,0);
          lcd.print("Select To Save      ");                 
          lcd.setCursor(0,1);
          lcd.print("Down to Exit          ");
                                  };
                             
                               
                                  }
    
    
    };
    
    
    //******************************* LOGS Min/MAX Values*******************************//
                              void Log_Min_MaxTemp(){
                           
                         
                                if(Temperature>=MaxT) MaxT=Temperature;
                                if(Temperature<=MinT) MinT=Temperature;
                                               
                                                 
                              };
    
    
    //******************************* LOGS Min/MAX Values*******************************//
                              void Log_Min_MaxPH(){
                           
                         
                                if(phValue>=MaxPH) MaxPH=phValue;
                                if(phValue<=MinPH) MinPH=phValue;
                                               
                                                 
                              };
    
    
    
    
    
    
    void PrintReadings(){
               
                    Serial.print("pH: ");
                    Serial.print(phValue);
                    Serial.print(Temperature);
                    Serial.print(" *C  ");
    
                                          //** First Screen Shows Temp and EC **//
                                          if(Screen==1){
                                          lcd.setCursor(0,0);
                                          lcd.print("Arduino pH  ");
                                          lcd.setCursor(0,1);
                                          lcd.print("pH:              ");
                                          lcd.setCursor(3,1);
                                          lcd.print(phValue);
                                          lcd.setCursor(9,1);
                                          lcd.print(Temperature);
                                          lcd.print("'C");
                                          }
                                     
                                     
                                          //**Third Screen Shows Min and Max **//
                                          else if(Screen==2){
                                          lcd.setCursor(0,0);
                                          lcd.print("Min:              ");
                                          lcd.setCursor(4,0);
                                          lcd.print(MinPH);
                                          lcd.setCursor(9,0);
                                          lcd.print(MinT);
                                          lcd.print("'C");
                                          lcd.setCursor(0,1);
                                          lcd.print("Max:              ");
                                          lcd.setCursor(4,1);
                                          lcd.print(MaxPH);
                                          lcd.setCursor(9,1);
                                          lcd.print(MaxT);
                                          lcd.print("'C");
                                          }
                                     
                                     
                                          else if(Screen==3){
                                   
                                          lcd.setCursor(0,0);
                                          lcd.print("Uptime Counter:              ");
                                     
                                          lcd.setCursor(0,1);
                                          lcd.print("                                    ");//Clearing LCD
                                          lcd.setCursor(0,1);
                                          lcd.print(Day);
                                          lcd.setCursor(3,1);
                                          lcd.print("Day");
                                          lcd.setCursor(8,1);
                                          lcd.print(Hour);
                                          lcd.setCursor(10,1);
                                          lcd.print(":");
                                          lcd.setCursor(11,1);
                                          lcd.print(Minute);
                                          lcd.setCursor(13,1);
                                          lcd.print(":");
                                          lcd.setCursor(14,1);
                                          lcd.print(Second);
                                     
                                     
                                          }
                       
                                          else if(Screen==4){
                                       
                                          lcd.setCursor(0,0);
                                          lcd.print("Calibrate pH          ");
                                     
                                     
                                          lcd.setCursor(0,1);
                                          lcd.print("Hold Select            ");
                                   
                                          }
           
    
    
    };

     

     

    Automated Green House Blog:14 - CO2: Measurement

     

     

    /*
       CO2 Sensor Gas:
    
    This script allows you to use a analog c02 gas sensor [like the one in the link below]:
    
    
    http://www.dfrobot.com/index.php?route=product/product&product_id=1023&search=co2&description=true#.VjeKyXzhDVM
    
    
    
    
    Procedure:
    >warm sensor up and take a reading of two known c02 solutions  [note down ADC readout and c02 ppm]
    >plug the numbers into the top of the code [Lines 28-31]
    >see if it works with a amonia solution between the min and max you calibrated with.
    
    
    
    
    other info:
    >Burn Sensor in for a hour or so before stable readings will be had
    >Sensor needs time to warm up after being powered up
    
    
    
    
    
    
    
       25/10/2015  Michael   Ratcliffe
       
       
              This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    Sensors and useful info:
    >Gas Sensor needs burning in before first use
    >
    
    
    */
    
    
    int GasPin=A0;
    float CO2MinADC=0;
    float CO2MaxADC=0;
    float CO2MinPPM=0;
    float CO2MaxPPM=0;
    
    
    //We will proberbly have to correct for temperature in the long run [not used yet]
    float Temperature=0;
    float Temp_Coef=0;
    float Offset=0;
    
    
    //[Im guessing it will be liner with a offset]
    
    
    int i=0;
    int SensorBuffer=0;
    float CO2PPM=0;
    float Gas_Readout=0; //Float incase we attempt to change ADC to PPM
    // ************************ Setup Routine ********************************//
    void setup() {
    
    
      Serial.begin(9600);// turn serial coms on for sending data to pc
      Setup_Info();
    
    }
    
    
    //************************** Main Loop ***********************************//
    //************************************************************************//
    void loop() {
          //Taking ten readings and averaging for accuracy
          i=1;
          SensorBuffer=0;
          while(i<=10){
          Gas_Readout= analogRead(GasPin);
          SensorBuffer=SensorBuffer+Gas_Readout;
          delay(50);
          i++;
          };
          Gas_Readout=SensorBuffer/i;  // cheack that my maths is correct her, I usssualy cock up this bit by one iteration
        
    Map_Results();
    Print_Results();
    
    
    
    
    }
    
    
    //*************** Printing dome useful info to seerial on boot up *********//
    void Setup_Info(){
    Serial.println("This script is a proof of concept that we can get useful representation of amonia in water by measuring its gas off");
    Serial.println("Gas Sensor needs burning in before first use [30 mins minimum]");
    Serial.println("Calibrate, take ADC read out at MAX CO2 and Min and put them in the top od code");
    
    
    
    }
    
    
    
    
    
    
    //****************Maps Results after we have Calibration values************//
    void Map_Results(){
    
    
    // Map only gives integers, we will need to modify to get better readings  [thats what all the *100 are about
    CO2PPM = map(Gas_Readout*100, CO2MinADC*100, CO2MaxADC*100, CO2MinPPM*100, CO2MaxPPM*100);
    CO2PPM=CO2PPM/100;
    
    }
    
    
    //********************Print something useful to Serial here****************//
    void Print_Results(){
    Serial.println("NEW RESULTS ");
    Serial.print("ADC Gas Sensor: ");
    Serial.println(Gas_Readout);
    Serial.print("Amonia PPM: ");
    Serial.println(CO2PPM);
    
    };
    

     

     

    Automated Green House Blog:17 - Automated Soil Moisture Measurement

     

    Automated Green House Blog:17.2 - Prolonging Probe Life

     

    Probe Choices:

    There are two main types of probes on the market for a reasonable price:

    >Capacitive sensors [long lasting]

    >Resistive Sensors [Cheap, but degrade]

     

    This script will work for both types of probes.

    [My probe draws a max of 35ma, that is very close to the arduino 40ma max rating, check yours does not exceed this on the spec sheet]

     

    The pinout:

     

    pinout

    [note mistake on pinout for probe, Should be Analog:A8 Ground:A9  Power A12]

     

    How to use:

    >Wire up following pinout as a guide [moisture sensor can change, so use the pin descriptions on the board. you want to use analog output not digital]

    >Place soil and temperature sensor in very dry soil [very dry!] click up on the lvd buttons and make a note of the ADC readout

    >On same ADC readout, soak the soil with water and make a not of the ADC readout

    >Plug these ADC values into the top of the code and reload to the board

    >Thats it, leave the probe in the soil for as long as you like to log data about the soil [min/max temperature and moisture levels]

     

    we are using a modified onewire and dallas library, [can be downloaded from www.michaelratcliffe.com] if your temperature does not read well, use a 10K pull up on temp data line.

    Take the calibration values you got from the last blog and use them in this script

     

    This script will only take one reading every 5 minutes, or when you press the right button on the LCd shield.

     

    /*
       Soil Moisture Measurment
    
       28/8/2015  Michael Ratcliffe  Mike@MichaelRatcliffe.com
       
       
              This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
        Parts:
        -Arduino - Uno/Mega
        -5v Relay
        -Water Solenoid
        -Soil moisture probe [Capacitive or resitive, doesnt matter]
        -LCD shield with buttons [DFRobot is pretty cheap]
    
    
        See www.MichaelRatcliffe.com/Projects for a Pinout and user guide or consult the Zip you got this code from
        or Search Element14 for Adapted_Greenhouse home page [lots of info here]
    
    */
    //************************ Libraries needed **************************************************************//
    
    
    // Both below Library are custom ones [ SEE READ ME In Downloaded Zip If You Dont Know how To install] Use them or add a pull up resistor to the temp probe
    
    
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <LiquidCrystal.h> //Standard LCD Lbrary
    
    //************************* User Defined Variables ********************************************************//
    
    
    
    
    //************* Moisture Probe Related *****************************************//
    #define Soil_Pin A8
    #define Soil_PWR A12
    #define Soil_GND A9
    
    
    //Power up the script and take note of ADC readings related to probe places in dry soil and watter logged soil
    int Dry_Soil=100;
    int Wet_Soil=600;
    
    
    
    
    
    
    //************ Temp Probe Related *********************************************//
    #define ONE_WIRE_BUS 26           // Data wire For Temp Probe is plugged into pin 10 on the Arduino
    const int TempProbePossitive =22;  //Temp Probe power connected to pin 9
    const int TempProbeNegative=24;    //Temp Probe Negative connected to pin 8
    OneWire oneWire(ONE_WIRE_BUS);// Setup a oneWire instance to communicate with any OneWire devices
    DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature.
    
    
    
    
    //***************************** END Of Recomended User Inputs *****************************************************************//
    float Soil_T=0;
    float Soil_M=0;
    int ADC_Reading=0;
    int Reading=0;
    
    
    //********************** Some Variables For Loging Min/Max Values ********************************//
    float MinM=100;
    float MaxM=0;
    float MinT=100;
    float MaxT=0;
    
    
    
    
    // select the pins used on the LCD panel
    LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    
    
    // define some values used by the panel and buttons
    int lcd_key     = 0;
    int adc_key_in  = 0;
    int button =0;
    #define btnRIGHT  1
    #define btnUP     2
    #define btnDOWN   3
    #define btnLEFT   4
    #define btnSELECT 5
    #define btnNONE   6
    
    
    
    
    //**********************Some Stuff For Uptime **************************************************//
    
    
    //************************** Just Some basic Definitions used for the Up Time LOgger ************//
    long Day=0;
    int Hour =0;
    int Minute=0;
    int Second=0;
    long Rollover=0;
    int HighMillis=0;
    int Readings=0;
    int Screen=0;
    int buttonLast=0;
    
    
    //*********************************Setup - runs Once and sets pins etc ******************************************************//
    void setup()
    {
      Serial.begin(9600);
      pinMode(TempProbeNegative , OUTPUT ); //seting ground pin as output for tmp probe
      digitalWrite(TempProbeNegative , LOW );//Seting it to ground so it can sink current
      pinMode(TempProbePossitive , OUTPUT );//ditto but for positive
      digitalWrite(TempProbePossitive , HIGH );
    
      //********Setting Soil Probe Pins ************//
      pinMode(Soil_Pin,INPUT);
      pinMode(Soil_PWR,OUTPUT);
      pinMode(Soil_GND, OUTPUT);
      digitalWrite(Soil_PWR , LOW );
      digitalWrite(Soil_GND , LOW );
    
    
      delay(100);// gives sensor time to settle
      sensors.begin();    //Temperature Probe
      delay(100);
    
    
      Serial.println("Soiul Moisture Measurment");
      Serial.println("By: Michael Ratcliffe  Mike@MichaelRatcliffe.com");
      Serial.println("Free software: you can redistribute it and/or modify it under GNU ");
      Serial.println("");
      Serial.println("Make sure Probe and Temp Sensor are in Ssoil");
      Serial.println("");
      Serial.println("Adjust Dry and wet values in code");
    
    lcd.begin(16, 2);              // start the library
    lcd.setCursor(0,0);
    delay(1000);
    lcd.print("Arduino Soil");
    lcd.setCursor(0,1);
    delay(1000);
    lcd.print("Mike Ratcliffe");
    lcd.setCursor(0,1);
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Free Software   ");
    delay(1000);
    lcd.setCursor(0,1);
    lcd.print("Mike Ratcliffe");
    delay(1000);
      lcd.setCursor(0,0);
    lcd.print("To Navigate         ");
      lcd.setCursor(0,1);
    lcd.print("Use Up-Down     ");
    delay(3000);
    
    
    
    };
    
    
    //******************************************* End of Setup **********************************************************************//
    
    
    
    
    //************************************* Main Loop - Runs Forever ***************************************************************//
    //Moved Heavy Work To subroutines so you can call them from main loop without cluttering the main loop
    void loop()
    {
    //Runs every 5 minutes [thats what 300000 millis means]
    if((millis()%300000<=10000 && Reading==0)|| button==1){
    Reading=1;
    GetMoisture();
    };
    if(millis()%300000>=20000){
    Reading=0;
    };
    
    
    
    
    GetTemp();         
    Log();
    read_LCD_buttons();
    Uptime();
    PrintReadings();   // Cals Print routine [below main loop]
    delay(100);
    
    
    }
    //************************************** End Of Main Loop **********************************************************************//
    
    
    
    
    
    
    //************ This Loop Is called From Main Loop to get Soil Temperature************************//
    void GetTemp(){
    
    
    
    
    sensors.requestTemperatures();// Send the command to get temperatures
    Soil_T=sensors.getTempCByIndex(0); //Stores Value in Variable
    
    
    
    
    ;}
    //************************** End OF Tmperature Function ***************************//
    
    
    
    
    
    
    //************ This Loop Is called From Main Loop to get Soil Moisture************************//
    void GetMoisture(){
    
    
    //Turning probe on for measurment and delaying a little to get stable reading
    digitalWrite(Soil_PWR , HIGH );
    delay(200);
    
    ADC_Reading=analogRead(Soil_Pin);
    // Map only gives integers, we will need to modify to get better readings  [thats what all the *100 are about
    Soil_M = map(ADC_Reading*100, Dry_Soil*100, Wet_Soil*100, 0, 100*100);
    Soil_M=Soil_M/100;
    Readings=1;
    
    
    //Turning Probe back off
    digitalWrite(Soil_PWR , LOW );
    
    
    ;}
    //************************** End OF Moisture Function ***************************//
    
    
    
    
    
    
    
    
    
    
    //***This Loop Is called From Main Loop- Prints to serial usefull info ***//
    void PrintReadings(){
    
    
    if (button>=1||Readings==1) {
      Readings=0;
                        
                          if(Screen==1){
                          lcd.setCursor(0,0);
                          lcd.print("Arduino EC-PPM   ");
                          lcd.setCursor(0,1);
                          lcd.print("M:               ");
                          lcd.setCursor(2,1);
                          lcd.print(Soil_M);
                          lcd.setCursor(9,1);
                          lcd.print(Soil_T);
                          lcd.print("'C");
                          }
                        
                          else if(Screen==2){
                          lcd.setCursor(0,0);
                          lcd.print("ADC Readout            ");
                          lcd.setCursor(0,1);
                          lcd.print("                    ");
                          lcd.setCursor(0,1);
                          lcd.print(ADC_Reading);
                        
                       
                            
                          }
                           else if(Screen==3){
                          lcd.setCursor(0,0);
                          lcd.print("Mn:              ");
                           lcd.setCursor(3,0);
                           lcd.print(MinM,0);
                           lcd.setCursor(9,0);
                          lcd.print(MinT);
                          lcd.print("'C");
                          lcd.setCursor(0,1);
                          lcd.print("Mx:               ");
                          lcd.setCursor(3,1);
                          lcd.print(MaxM,0);
                          lcd.setCursor(9,1);
                          lcd.print(MaxT);
                          lcd.print("'C");
                        
                           }
                            else if(Screen==4){
                       
                          lcd.setCursor(0,0);
                          lcd.print("Uptime Counter:              ");
                        
                          lcd.setCursor(0,1);
                          lcd.print("                                     ");//Clearing LCD
                          lcd.setCursor(0,1);
                          lcd.print(Day);
                          lcd.setCursor(3,1);
                          lcd.print("Day");
                          lcd.setCursor(8,1);
                          lcd.print(Hour);
                          lcd.setCursor(10,1);
                          lcd.print(":");
                          lcd.setCursor(11,1);
                          lcd.print(Minute);
                          lcd.setCursor(13,1);
                          lcd.print(":");
                          lcd.setCursor(14,1);
                          lcd.print(Second);
                        
                        
                           }
    
    
      
    };
    
    
    
    
    };
    
    
    
    
    void read_LCD_buttons(){
      adc_key_in = analogRead(0);      // read the value from the sensor
    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    if (adc_key_in > 1000)  button =0;
    
    
    else if (adc_key_in < 50)   button =1;
    else if (adc_key_in < 250)  button =2;
    else  if (adc_key_in < 450)  button =3;
    else if (adc_key_in < 650)  button =4;
    else if (adc_key_in < 850)  button =5;
    
    
    if(button==2&&buttonLast!=button){
    Screen++;
    }
    else if (button==3&&buttonLast!=button){
    Screen--;
    };
    if (Screen>=4) Screen=4;
    if(Screen<=1) Screen=1;
    
    
    buttonLast=button;
    };
    
    
    //******************************* LOGS Min/MAX Values *******************************//
    void Log(){
    
      if(Soil_M>=MaxM)  MaxM=Soil_M;
      if(Soil_M<=MinM)  MinM=Soil_M;
    
      if(Soil_T>=MaxT) MaxT=Soil_T;
      if(Soil_T<=MinT) MinT=Soil_T;
    }
    
    
    //**************************** Uptime Counter ********************************************//
    void Uptime(){
    //** Checks For a Second Change *****//
    //** Making Note of an expected rollover *****// 
    if(millis()>=3000000000){
    HighMillis=1;
    
    
    }
    //** Making note of actual rollover **//
    if(millis()<=100000&&HighMillis==1){
    Rollover++;
    HighMillis=0;
    }
                            
    long secsUp = millis()/1000;                     
    Second = secsUp%60;
    Minute = (secsUp/60)%60;
    Hour = (secsUp/(60*60))%24;
    Day = (Rollover*50)+(secsUp/(60*60*24));  //First portion takes care of a rollover [around 50 days]
                      
    };