element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Vertical Farming
  • Challenges & Projects
  • Design Challenges
  • Vertical Farming
  • More
  • Cancel
Vertical Farming
Blog Automated Green House Blog:13.4 - PH Control: PH Probe LCD Readout + Gui + Probe Health Readout
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: m.ratcliffe
  • Date Created: 8 Jan 2016 7:16 PM Date Created
  • Views 4049 views
  • Likes 5 likes
  • Comments 12 comments
  • adapted_greenhouse
  • fault
  • gui
  • ph
  • arduino
Related
Recommended

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

m.ratcliffe
m.ratcliffe
8 Jan 2016

A Updated PH Probe, Now gives A Readout For Probe Life and a time alarm for when to Calibrate.

 

DFRobot were nice enough to send me one of their pH pro MCU probes [Longer lasting] but this tutorial and code will work for any analog pH MCU meter [ebay special etc] these are coming down in price rapidly but I recommend calibrating often.

 

The Analog pH breakout boards often have a little pot for adjusting during calibration, this is a pain in the ass at calibration time. This new code uses a different method and is all code based.

 

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

 

image

[Turn Pot on PH meter fully  anticlockwise, we are now using a better Calibration method]

 

GUI

The LCD has a few useful Screens

image

 

 

How It works:

 

pH Measurement and Calibration

pH probes output a small voltage change [from-170mv to 170mv, for ph 4-10], the breakout board is essentially a op amp with an offset. So it now outputs a 0-5v signal.

These boards are made with a potentiometer to change the gain of the amplifier to calibrate, good idea but very awkward, we instead will be giving it a set gain and calibrating in the code.

So what are the steps if you have a different board:

>Turn Pot fully clockwise

>Short BNC connector together and read mv [from serial] This is your Ideal pH reading, the DF robot is 1.96v

>Connect probe and read mv [from serial] when in pH4 and pH7, The probe change will be 170mv, you now have a way to work out the gain of the amp.

 

pH = 7 -(Ph_Calibration_mv - measured_mv)*gain   // Simple?

 

Doing it this way we can read pH and calibrate without messing with that pot ever again, by taking three readings  1:Ideal pH 7 mv  , 2:Actual pH7 mv ,  3: pH4mv

 

The LCD GUI will guide you thru a Calibration process:

 

image

 

Probe Life

The LCD screen with Probe life should have all readings above 50% to be considered a probe in good health, if ones lower I recommend cleaning it or ordering a replacement [It will fail soon].

 

There are three indicators of probe life when we calibrate.

http://reagecon.com/pdf/technicalpapers/Electrode_CM_v5_TSP-02_Issue_4.pdf

In the Code these are showed as:

H1: pH7 offset [pH7 should output the ideal voltage of 1.96, as they age they get an offset

H2 Slope,  change in mv between pH4 calibration and pH7 

H3:Drift , Healthy probes should have reached a s.s value after 60 seconds, this one checks for a difference between a reading at 60 seconds and 120

 

A more Technical Explanation of the health checks:

//there are three ways we can measure a proble life during calibration:

//1:Asymmetry potential (Eo), the Millivoltes at pH7 [mV reading in pH 7.00 buffer ± 25 mV]

//2:Slope, mv per Ph change [mV reading in pH 7.00 buffer - mV reading in pH 4.00 buffer 160 – 180 mV]

//3:Drift mV reading in pH 4.00 buffer (1 min) – mV reading in pH 4.00 buffer (2 min) ± 1.5 mV  [we are checking for stable readings]

 

 

I have tested this code with good probes, failed probes and aged b probes and it works very well at identifying them.

Got a probe with a low Health indicator one or three? check out the blog on reviving a probe:

Blog:13.9 - PH Probe Revival: Ultrasonic Cleaning

 

 

The Code

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.

 

The code works and it works great, I did however group into one variable the gain and slope, this means the health check values are only valid for analog probes, there will be an updated I2C version soon.

 

Header 1

/*

   Script to print PH to serial

 

 

 

   * Turn Pot fully counter clockwise[All the way it should take multiple turns], we arnt ussing it anymore for calibration

 

 

   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

   -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 "OneWire.h"

#include "DallasTemperature.h"

#include "LiquidCrystal.h" //Standard LCD Lbrary

#include "EEPROM.h" //Standard EEPROM Library

 

 

//*********************** User defined variables ****************************//

//The Number of Days before the LCD will tell you its time to Calibrate

int Cal_Period_Warining=30;

//pH meter Analog output to Arduino Analog Input 0

int PHPin =A15;  

//I got this from shorting the nbc's cnetre pin to outer pin [simulated the perfect probe] open serial and its the mv reading that you want to put here

float Healthy1_mv=1.96;    

 

 

 

 

 

 

//************ 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 mvReading=0;

float Vs=5;

float phValue=0;

int i=0;

long reading=0;

unsigned long sum=0;

float average=0;

//used for min/max logs

float MinPH=10;

float MaxPH=0;

 

 

//************** Variables used to determin probe health **********//

//there are three ways we can measure a proble life during calibration:

//1:Asymmetry potential (Eo), the Millivoltes at pH7 [mV reading in pH 7.00 buffer ± 25 mV]

//2:Slope, mv per Ph change [mV reading in pH 7.00 buffer - mV reading in pH 4.00 buffer 160 – 180 mV]

//3:Drift mV reading in pH 4.00 buffer (1 min) – mV reading in pH 4.00 buffer (2 min) ± 1.5 mV  [we are checking for stable readings]

int ProbeLife1=0;

float mvReading_7=0;

 

 

//Some major brands will have this set at 35mv, we have a gain of around 8 in our op amp

float Health1_range =0.28;

float Healthy1_mv2=1.96;

 

 

 

 

//I got these from a healthy probe and extrapolating the slope deviation

int ProbeLife2=0;

float Slope=0;

float mvReading_4=0;

float Healthy2_Slope=2.15;

float Healthy2_range=0.25;

 

 

int ProbeLife3=0;

float Drift=0;

float mvReading_4_Delayed=0;

float Healthy3_Drift=0;

float Healthy3_range=0.02;

 

 

//some Variables for Probe Calibration Time

int Last_Day=0;

int Days_Since_Calibration=0;

int CalibrationWarning=0;

 

 

float offset=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 =6;

//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;

 

 

//Used For Calibration timing

unsigned long StartCalibration1=0;

 

 

//***************** Specifying where to sotre the calibration value [non volatile memory **//

int value=0; //we use this to check if memory has been writen or not

int addresCalibrationPH4=0;

int addresCalibrationPH7=50;

int addresProbleLife1=100;

int addresProbleLife2=150;

int addresProbleLife3=200;

int addresseCalibrationDays=250;

 

 

//************************************** 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();

  Slope_calc();

  Splash_Screen();

 

if(Days_Since_Calibration>=Cal_Period_Warining) CalibrationWarning=1;

 

//Adjusting some values for use later in map function

Healthy1_mv2=Healthy1_mv*1000;

Health1_range =Health1_range*1000;

 

 

Healthy2_Slope=Healthy2_Slope*1000;

Healthy2_range=Healthy2_range*1000;

 

 

Healthy3_Drift=Healthy3_Drift*1000;

Healthy3_range=Healthy3_range*1000;

 

 

}

//******************************** 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();

//Used to see hoe many days ago the probe was calibrated

Day_Change();

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=0;

  sum=0;

  while(i<=20){

  reading=analogRead(PHPin);

  sum=sum+reading;

    delay(10);

    i++;

  }

average=sum/i;

 

 

//Converting to mV reading and then to pH

mvReading=average*Vs/1024;

//phValue=mvReading*K_PH;  

phValue=(7-((mvReading_7-mvReading)*Slope));

 

 

}

 

 

 

 

 

 

 

 

 

 

//****************************** 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(Day>=30){

HighMillis=1;

 

 

}

//** Making note of actual rollover **//

if(millis()<=100000&&HighMillis==1){

Rollover++;

HighMillis=0;

}

//Calculating the uptime

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);

 

 

 

 

};

 

 

//******************** calculating the PhMeter Parameters ***************************************//

void Slope_calc(){

 

 

offset=Healthy1_mv-mvReading_7;

Slope=3/(Healthy1_mv-mvReading_4-offset);

 

}

 

 

//*************************** Checking what we stored in non volatile memory last time ************//

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(addresCalibrationPH7);

   mvReading_7=value*Vs/256;

   delay(10);

 

value = EEPROM.read(addresCalibrationPH4);

   mvReading_4=value*Vs/256;

   delay(10);

//Checking for Probe Life 1 Indicator

value = EEPROM.read(addresProbleLife1);

   ProbeLife1=value;

   delay(10);

//Probe:ife 2 saved

   value = EEPROM.read(addresProbleLife2);

   ProbeLife2=value;

   delay(10);

//Probe:ife 3 saved

   value = EEPROM.read(addresProbleLife3);

   ProbeLife3=value;

   delay(10);

 

 

  //Checking memory slot for probe calibration time

  Days_Since_Calibration = EEPROM.read(addresseCalibrationDays);

 

 

 

 

};

 

 

//******************************* 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);

       };

StartCalibration1=millis();

 

 

//We are giving the probe 1 minute to settle

while(millis()<StartCalibration1+60000){

lcd.setCursor(0,0);

lcd.print("Calibrating              ");

lcd.setCursor(0,1);

lcd.print("                      ");

lcd.setCursor(0,1);

lcd.print(StartCalibration1+60000-millis());

lcd.setCursor(7,1);

lcd.print(":mSeconds");

delay(1000);

};

ReadPH();

delay(100);

ReadPH();

               

   //*******Saving the new value to EEprom**********//  

   mvReading_7=mvReading;

 

 

 

 

 

 

while (1) { // wee need to keep this function running until user opts out with return function

                            

  read_LCD_buttons();

  if(button==3) return; //exits the loop without saving becauser user asked so

                            

if(millis()%4000>=2000){

   

     lcd.setCursor(0,0);

     lcd.print("Calibrated         ");

       lcd.setCursor(0,1);

      lcd.print("Select To Save       ");                            

 

 

                              }

else{

                             

                   

      lcd.setCursor(0,1);

      lcd.print("Down to Exit           ");

                              };

                            

   if (button==5) break;

}                              

//read the ph probe

 

 

   //Saving the value steight from ADC, removes conversion errors                              

   value= average/4;

   EEPROM.write(addresCalibrationPH7,value);

   //Resetting the days sinc calibration

   Days_Since_Calibration=0;

   CalibrationWarning=0;

   Slope_calc();

   ProbeLife_Check_1();

   EEPROM.write(addresseCalibrationDays,Days_Since_Calibration);

 

 

   //Displaying the new offset

   lcd.setCursor(0,0);

   lcd.print("Saved Calibration        ");

                                                          

   lcd.setCursor(0,1);

   lcd.print("Offset                        ");

   lcd.setCursor(3,1);

   lcd.print(offset);

   delay(2000);

   //move onto pH4 Calibration

 

                               

 

 

   lcd.setCursor(0,0);

   lcd.print("Rinse and           ");

                                                          

   lcd.setCursor(0,1);

   lcd.print("Placein pH4                      ");

 

   delay(4000);

 

   while(1){

   lcd.setCursor(0,0);

   lcd.print("Press Right          ");

                                                          

   lcd.setCursor(0,1);

   lcd.print("If Probe in 4                       ");

   //move onto next stage if select is held

   read_LCD_buttons();

   if (button==1) break;

   }

StartCalibration1=millis();

 

 

//We are giving the probe 1 minute to settle

while(millis()<StartCalibration1+60000){

lcd.setCursor(0,0);

lcd.print("Calibrating              ");

lcd.setCursor(0,1);

lcd.print("                      ");

lcd.setCursor(0,1);

lcd.print(StartCalibration1+60000-millis());

lcd.setCursor(7,1);

lcd.print(":mSeconds");

delay(1000);

};

ReadPH();

delay(100);

ReadPH();

 

 

mvReading_4=mvReading;

 

 

 

 

   //We are giving the probe 1 minute to settle

   StartCalibration1=millis();

  while(millis()<=StartCalibration1+60000){

  lcd.setCursor(0,0);

  lcd.print("Health Check              ");

  lcd.setCursor(0,1);

  lcd.print("                      ");

  lcd.setCursor(0,1);

  lcd.print(StartCalibration1+60000-millis());

lcd.setCursor(7,1);

lcd.print(":mSeconds");

  delay(1000);

};

ReadPH();

delay(100);

   ReadPH();

   mvReading_4_Delayed=mvReading;

   //Saving ADc readout, to remove conversion errors

   value= average/4;

EEPROM.write(addresCalibrationPH4,value);

   Slope_calc();

   ProbeLife_Check_2();

   ProbeLife_Check_3();

 

   //Put back to main screen and exit calibration

   lcd.setCursor(0,0);

   lcd.print("Saved Calibration        ");

 

   delay(1000);

  //Informing the use about the probe life

while(1){

read_LCD_buttons();

 

 

 

 

if(ProbeLife2>=50 && ProbeLife2>=50 &&ProbeLife3>=50){

lcd.setCursor(0,0);

lcd.print("Probe Condition  ");

lcd.setCursor(0,1);

lcd.print("Good            "); }

 

 

if(ProbeLife2<50 || ProbeLife2<50 || ProbeLife3<50){

lcd.setCursor(0,0);

lcd.print("Probe Condition   ");

lcd.setCursor(0,1);

lcd.print("Faulty           "); }

 

 

if(millis()%6000 <=3000){

lcd.setCursor(0,0);

lcd.print("Press Right          ");

                                                          

lcd.setCursor(0,1);

lcd.print("To exit               ");

};

 

 

//user pressed right?

if(button==1) break;

delay(100);

       };

   Screen=1;

   return;                                                       

 

 

};

 

 

//******************************* 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.println(" *C  ");

                Serial.print("mv: "); 

                Serial.print(mvReading);

                Serial.print("   mvPh7: ");

                Serial.print(mvReading_7);

                 Serial.print("   mvPh4: ");

                Serial.println(mvReading_4);

                Serial.print("H1: "); 

                Serial.print(ProbeLife1);

                Serial.print("   H2: ");

                Serial.print(ProbeLife2);

                 Serial.print("H3: "); 

                Serial.println(ProbeLife3);

             

                Serial.print("Slope ");

                Serial.print(Slope);

           

             

                        

                                      //** 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==6){

                                   

                                      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            ");

                                   

                                      }

                                      else if(Screen==3){

                                      

                                      lcd.setCursor(0,0);

                                      lcd.print("Probe Health %          ");

                                    

                                    

                                      lcd.setCursor(0,1);

                                      lcd.print("H1:                     ");

                                      lcd.setCursor(3,1);

                                      lcd.print(ProbeLife1);

                                      lcd.setCursor(9,1);

                                      lcd.print("H2:");

                                      lcd.setCursor(12,1);

                                      lcd.print(ProbeLife2);

                                      if(millis()%6000<3000){

                                      lcd.setCursor(0,1);

                                      lcd.print("H3:                "); 

                                      lcd.setCursor(3,1);

                                      lcd.print(ProbeLife3);

                                      }

                                      }

                                    

                                      else if(Screen==5){

                                      

                                      lcd.setCursor(0,0);

                                      lcd.print("Days Since Cal         ");

 

 

                                      lcd.setCursor(0,1);

                                      lcd.print("                       ");

                                      lcd.setCursor(0,1);

                                      lcd.print(Days_Since_Calibration);

                                    

                                      }

                                    

   if((millis()%10000<=2000) && (CalibrationWarning==1)){

 

 

                                      lcd.setCursor(0,0);

                                      lcd.print("Calibrate the          ");

                                      lcd.setCursor(0,1);

                                      lcd.print("Probe                   ");

                                                                

                           };         

 

};

 

 

//************************************* Used For Probe time Since Last Calibration *************************************//

//This wont keep counting if unit has been powered off, so it is only really useful for use when in permanant use

void Day_Change(){

if(Day!=Last_Day){

    Last_Day=Day;

    Days_Since_Calibration++;

    EEPROM.write(addresseCalibrationDays,Days_Since_Calibration);

    if(Days_Since_Calibration>=Cal_Period_Warining) CalibrationWarning=1;

};

 

};

 

 

 

 

//********************** The Section Below will give you a read out of probe Life ****************************************//

//there are three ways we can measure a proble life during calibration:

//1:Asymmetry potential (Eo), the Millivoltes at pH7 [mV reading in pH 7.00 buffer ± 25 mV]

//2:Slope, mv per Ph change [mV reading in pH 7.00 buffer - mV reading in pH 4.00 buffer 160 – 180 mV]

//3:Drift mV reading in pH 4.00 buffer (1 min) – mV reading in pH 4.00 buffer (2 min) ± 1.5 mV  [we are checking for stable readings]

 

 

void ProbeLife_Check_1(){

//Structure, get pH7 mv reading and map life vs mv reading , variables Good value, band for bad reading

//We already just got the mvReading int he calibration function

//map(value, fromLow, fromHigh, toLow, toHigh);

 

 

value=mvReading_7*1000;

if (value>=Healthy1_mv2) ProbeLife1=map(value, Healthy1_mv2, (Healthy1_mv2+Health1_range), 100, 0);

if (value<Healthy1_mv2) ProbeLife1=map(value, Healthy1_mv2, (Healthy1_mv2-Health1_range), 100, 0);

if (ProbeLife1<=1) ProbeLife1=0;

EEPROM.write(addresProbleLife1,ProbeLife1);

};

 

 

void ProbeLife_Check_2(){

//structure compare ph7 mv to ph4 mv , variables  Good value  Band for bad reading

 

 

value=Slope*1000;

if (value>=Healthy2_Slope) ProbeLife2=map(value, Healthy2_Slope,(Healthy2_Slope+ Healthy2_range), 100, 0);

if (value<Healthy2_Slope) ProbeLife2=map(value, Healthy2_Slope,(Healthy2_Slope-Healthy2_range), 100, 0);

if (ProbeLife2<=1) ProbeLife2=0;

EEPROM.write(addresProbleLife2,ProbeLife2);

};

 

 

 

 

void ProbeLife_Check_3(){

//structure, leave probe in ph 4 for 1 minute and then take another average at 2 mins map from 0 drift to 5mv for probe life

Drift=(mvReading_4-mvReading_4_Delayed);

value=Drift*1000;

if (value>=Healthy3_Drift) ProbeLife3=map(value, Healthy3_Drift,(Healthy3_Drift+ Healthy3_range), 100, 0);

if (value<Healthy3_Drift) ProbeLife3=map(value, Healthy3_Drift,(Healthy3_Drift- Healthy3_range), 100, 0);

if (ProbeLife3<=1) ProbeLife3=0;

EEPROM.write(addresProbleLife3,ProbeLife3);

};

  • Sign in to reply

Top Comments

  • DAB
    DAB over 9 years ago +1
    Great update. Are you keeping a log of the PH levels of the fluid. I am curious how much do they change over time? Or is one batch stable enough to use for a while? DAB
  • Torkialareed
    Torkialareed over 3 years ago

    I'm a user and trying to find someone to put the system together. However, I'm starting with 40-20mA analog sensor to avoid noise. Interfaced with a current-to-voltage converter, then output is the input to 1024 positions digipot, included for calibration, then to 16 bit ADC and to esp32.

    With the code above, will we not need the digipot?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • cbeisal
    cbeisal over 6 years ago in reply to bmyrand

    I am also looking to add parastalic pumps for ph down lol just don’t know how to add it to this fine code

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • bmyrand
    bmyrand over 6 years ago

    is this project still active ?

    wish i could download that .zip file somewhere for the libraries.

    i would like to add 2 dozing pumps to that to add ph up or ph down as required.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • robned
    robned over 8 years ago

    Hello Michael,

    Thanks for this very good project. (

    I have got it partially working but the temperature read out stays 0 degrees

    TEmp Sensor is ok (tested in other project)

    I am just starting with Arduino so forgive me if I ask a very stupid question:

    The sensor connections are : 22,24 and 26. However in the program lines you mention as comment :  Arduino 9,8 and 10

    Do I have to connect the DS18B20 wires to 22,24 and 26? If yes, do you have any tip for me to get the temp sensor working?

     

    Best Regards,

     

    Rob

     

    By the way , to get my LCD keypad switches working I had to modify the program lines:

    else if (adc_key_in < 50)   button =1; // was 50

    else if (adc_key_in < 150)  button =2; //was 250

    else  if (adc_key_in < 350)  button =3; //was 450

    else if (adc_key_in < 550)  button =4; // was 650

    else if (adc_key_in < 750)  button =5; //was 850

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • m.ratcliffe
    m.ratcliffe over 9 years ago in reply to Former Member

    Glad to hear it is working for you, do you mind if I ask what project your doing?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube