For now the basic code has been written.
I can measure pH and when the value gets below of above a certain value one of two relays is activated so a peristaltic pump can add a base of acid to the nutrient tank. The pH sensor is a Phidgets 1130 (Analog sensor)
I can also measure Temp/Humidity and when both get above a certain value another relay is activated so a fan is activated. The Temp/Humid sensor is a DHT11, which is accurate enough for testing purposes, but probably will get the DHT22 for more accurate reading...
Also the code for a float switch is written. When the water-level gets below a certain value a solenoid valve opens up and fills the nutrient tank.
Now my question... I'm currently using a pot meter to calibrate the pH sensor, but would like to have it completely digital. The objective is to use a 3.2" tft screen with menu's and one of the menu's will be pH calibration. Calibration of a pH meter is a two-point calibration, measuring the value for 4.5pH and one for 8pH. What seems to be fairly easily done with a pot meter is a pain in the @ss getting it into code.
Could some help me out with my problem? Just pushing me in the wright direction would be very appreciated
I'll post the code in a new reply because of max. length of message...
Here is the code I've written so far...Oh, if i forgot some information that you need please tell and i'll present it.
/*
Arduino Mega 2560 Hydroponic Controller V.1
Purpose:
-Monitor pH level of nutrient tank with pH probe and dose (pH-/pH+) wit two
peristaltic pumps.
-Monitor fluidlevel in the nutrient tank with float switch. In case it gets
to low a solenoid valve opens up and fils the tank.
-Measure temperature and humidity. If both get to high a fan removes hot and
humid air.
)
Todo's:
-Measure amount of light received during the day. (Primairely used for
loggin purposes
-Use second float switch to close off solenoid valve so i don't have to use
a timerfunction.
-Monitor and control EC value's. ie, When waterlevel & EC are low the
solenoid valve opens up while fertilizer is added.
Code found on the WWW. Thanks to everybody who contributed. You know who you are ;)
*/
//Define PIN's
#define dht_dpin 69 //Analog PIN 15
#define pHPin 62 //Analog PIN 8
#define pHPlusPin 10
#define pHMinPin 11
#define ventilatorPin 9
#define floatPin 7
#define solenoidPin 8
#define DHTTYPE DHT11
byte compFunc; //for passing error code back from complex functions.
byte dht_dat[4]; //Array to hold the bytes sent from sensor.
void setup()
{
pinMode(pHPlusPin, OUTPUT); //setting PIN's as output
pinMode(pHMinPin, OUTPUT);
pinMode(ventilatorPin, OUTPUT);
pinMode(solenoidPin, OUTPUT);
InitDHT(); //Initializing for reading DHT
Serial.begin(9600);
delay(300); //Must wait one second for DHT chip to stabilize. This is
//the first part 0.3 seconds.
Serial.println("Luchtvochtigheid, temperatuur & pH");
Serial.println("__________________________________\n\n");
delay(700); //rest of 1 second. Second part 0.7 seconds/
}
void loop()
{
//measuring pH level...
float sensorValue = 0;
sensorValue = analogRead(pHPin); //Read analog pin
float pH(0.0178 * sensorValue - 1.889); //Conversionformula for pH
if (pH >= 6.00) //If pH gets below 5 or above 6 a
{ //corresponding pump gets activated.
digitalWrite(pHMinPin, HIGH);
digitalWrite(pHPlusPin, LOW);
}
else if (pH <= 5.00)
{
digitalWrite(pHPlusPin, HIGH);
digitalWrite(pHMinPin, LOW);
}
else if (pH > 5.00 || pH < 6.00)
{
digitalWrite(pHMinPin, LOW);
digitalWrite(pHPlusPin, LOW);
}
//measuring temperature & humidity.
ReadDHT(); //Read from DHT chip
switch (compFunc){
case 0:
Serial.print("Luchtvochtigheid = ");
Serial.print(dht_dat[0], DEC);
Serial.println("% ");
Serial.print("Temperatuur = ");
Serial.print(dht_dat[2], DEC);
Serial.println(" *C ");
break;
case 1:
Serial.println("Error 1: DHT start condition 1 not met.");
break;
case 2:
Serial.println("Error 2: DHT start condition 2 not met.");
break;
case 3:
Serial.println("Error 3: DHT checksum error.");
break;
default:
Serial.println("Error: Unrecognized code encountered.");
break;
} //End of switch
Serial.print("pH = : "); //adding pH to screen
Serial.println(pH);
if(dht_dat[0] >= 80 && dht_dat[2] >= 35)
{
digitalWrite(ventilatorPin, HIGH);
Serial.println("Ventilator geactiveerd");
}
else
{
digitalWrite(ventilatorPin, LOW);
}
//measuring waterlevel...
int levelValue = LOW;
levelValue = digitalRead(floatPin);
if (levelValue == HIGH)
{
digitalWrite(solenoidPin, HIGH);
Serial.println("Solenoid klep geactiveerd");
}
else
{
digitalWrite(solenoidPin, LOW);
}
Serial.println(" \n\n");
delay(2000); //Delay can be adjusted to 800ms but better to
//set it to 2000ms for more stable reading.
Serial.flush(); //flush all other data.
}
void InitDHT()
{
pinMode(dht_dpin,OUTPUT);
digitalWrite(dht_dpin,HIGH);
}
void ReadDHT()
{
/*Uses global variables dht_dat[0-4], and compFunc to pass
"answer" back. compFunc=0 if read went okay.
Depends on global dht_dpin for where to look for sensor.*/
compFunc=0;
byte dht_in;
byte i;
// Send "start read and report" command to sensor....
// First: pull-down I/O pin for 23000us
digitalWrite(dht_dpin,LOW);
delay(50); //standard is 23
//Next line: Brings line high again,
//second step in giving "start read..." command
digitalWrite(dht_dpin,HIGH);
delayMicroseconds(40); //DHT22 datasheet says host should
//keep line high 20-40us, then watch for sensor taking
//line low. That low should last 80us. Acknowledges
//"start read and report" command.
//Next: Change Arduino pin to an input, to
//watch for the 80us low explained a moment ago.
pinMode(dht_dpin,INPUT);
dht_in=digitalRead(dht_dpin);
if(dht_in){
compFunc=1; //dht start condition 1 not met
return;
} //end if
delayMicroseconds(80);
dht_in=digitalRead(dht_dpin);
if(!dht_in){
compFunc=2; //dht start condition 2 not met
return;
} //end if
/*After 80us low, the line should be taken high for 80us by the
sensor. The low following that high is the start of the first
bit of the forty to come. The routine "read_dht_dat()"
expects to be called with the system already into this low.*/
delayMicroseconds(80);
//now ready for data reception... pick up the 5 bytes coming from
// the sensor
for (i=0; i<5; i++)
dht_dat[i] = read_dht_dat();
//Next: restore pin to output duties
pinMode(dht_dpin,OUTPUT);
//Next: Make data line high again, as output from Arduino
digitalWrite(dht_dpin,HIGH);
//Next see if data received consistent with checksum received
byte dht_check_sum =
dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
/*Condition in following "if" says "if fifth byte from sensor
not the same as the sum of the first four..."*/
if(dht_dat[4]!= dht_check_sum)
{compFunc=3;}//DHT checksum error
}
byte read_dht_dat()
{
//Collect 8 bits from datastream, return them interpreted
//as a byte. I.e. if 0000.0101 is sent, return decimal 5.
//Code expects the system to have recently entered the
//dataline low condition at the start of every data bit's
//transmission BEFORE this function is called.
byte i = 0;
byte result=0;
for(i=0; i< 8; i++){
//We enter this during the first start bit (low for 50uS) of the byte
//Next: wait until pin goes high
while(digitalRead(dht_dpin)==LOW);
//signalling end of start of bit's transmission.
//Dataline will now stay high for 27 or 70 uS, depending on
//whether a 0 or a 1 is being sent, respectively.
delayMicroseconds(45);//AFTER pin is high, wait further period, to be
//into the part of the timing diagram where a 0 or a 1 denotes
//the datum being send. The "further period" was 30uS in the software
//that this has been created from. I believe that a higher number
//(45?) might be more appropriate.
//Next: Wait while pin still high
if (digitalRead(dht_dpin)==HIGH)
result |=(1<<(7-i));// "add" (not just addition) the 1
//to the growing byte
//Next wait until pin goes low again, which signals the START
//of the NEXT bit's transmission.
while (digitalRead(dht_dpin)==HIGH);
} //end for
return result;
}
if (pH >= 6.00) //If pH gets below 5 or above 6 a
{ //corresponding pump gets activated.
}
else if (pH <= 5.00)
{
}
else if (pH > 5.00 || pH < 6.00)
{
}
Horrid indenting style aside, if the pH is not above 6 and not below 5, how can it be anything other then greater than 5 AND less than 6?
The last if test is both wrong and unnecessary.
Serial.flush(); //flush all other data.
Absolutely, unequivocally not needed. GET RID OF THIS!
dht_in=digitalRead(dht_dpin);
if(!dht_in){
The digitalRead() function does not return true or false. Do not write code that assumes that it does.
Calibration of a pH meter is a two-point calibration, measuring the value for 4.5pH and one for 8pH. What seems to be fairly easily done with a pot meter is a pain in the @ss getting it into code.
PaulS:
Horrid indenting style aside, if the pH is not above 6 and not below 5, how can it be anything other then greater than 5 AND less than 6?
The last if test is both wrong and unnecessary.
Did i mention i'm a complete noob and collected the code of the Internet. I'm trying to build my first project, so please bear with me...
PaulS:
Serial.flush(); //flush all other data.
Absolutely, unequivocally not needed. GET RID OF THIS!
Ok, thought that i had to clear the serial cache before i re-use... I'll remove it then
PaulS:
dht_in=digitalRead(dht_dpin);
if(!dht_in){
The digitalRead() function does not return true or false. Do not write code that assumes that it does.
Removed it
PaulS:
Calibration of a pH meter is a two-point calibration, measuring the value for 4.5pH and one for 8pH. What seems to be fairly easily done with a pot meter is a pain in the @ss getting it into code.
So, where is the code that attempts to do this?
That's where i need the help. I don't know where to start. I searched this forum and Google, but didn't find what i was looking for. Most likely someone posted it, but since my knowledge of programming is very basic i don't know where to start looking... I'm not asking to write the code for me, but to point me in the right direction.
I'm not asking to write the code for me, but to point me in the right direction.
It's hard to point you in the right direction when your requirements are so vague. When do you want to perform this calibration? What is to replace the pot meter?
BillieBricks:
...The objective is to use a 3.2" tft screen with menu's and one of the menu selection buttons will be pH calibration...
I'll explain a little further... A pH probe has to be calibrated when the value is off. When that happens depends on the quality of the probe. Mine is very cheap so i think i'll have to do it once a week. I would like to start the calibration process whenever i want to, by pressing a button in a graphical menu, (the code for the graphical menu has to be written/researched) but for now i'd be glad if it happens every time i cycle/reset the arduino. This way i have the code and then afterwards i can implement it in to the graphical menu.
The calibration process of a pH probe goes as follows...
1ste put the probe in a pH 4.5 solution and adjust/set value to 4.5
2nd put the probe in a pH 8 solution and adjust value/set to 8
From now on the probe is calibrated for measuring between 4.5 and 8 pH until it start to deviate from the know values and has to be calibrated again.
And on the back there is a small screw so one can adjust the pH reading. This works the same as what i did with the pot meter...
But i thought that if i change the analogRead value in code (ie, by pressing a '+' of '-' button in the graphical interface) i can 'calibrate' the probe without the use of a analog device (ie, pot meter)
So, that device contains a voltage divider. The pH measurer is a variable resistor (R1). The trim pot is also a variable resistor (R2).
+V --> R1 --+--> R2 --> Gnd
The + is connected to the analog pin. The voltage drop across the pH measurer is converted to a value between 0 and 1023. Actually, the value will never be 1023, since that would imply that R2 is 0 ohms.
Whether you could just create an offset for the analog value at 4.5 and another for the analog value at 8, and interpolate to determine the offset at some intermediate reading, or not, I don't know. You could try it and see. Whether the resulting interpolated offset + actual reading would be accurate enough could only be determined experimentally.
I don't know what the analogue range you pH probe returns (I think the arduino analogue input read 0@zero volts and 1023@five volts) but I wonder if this could be calibrated using the map() function. http://arduino.cc/en/Reference/Map
For simplicity say (the perfect meter would read) pH of 4.5 analogue reads 450 and pH 8.0 analogue reads 800, a difference of 350.
Now you calibrate you imperfect pH meter and 4.5=430 and 8.0=803, a difference of 373.
Using the map() function you should be able to map the readings to the correct range.
map(value, fromLow, fromHigh, toLow, toHigh)
map(value, 430, 803, 450, 800)
PaulS:
So, that device contains a voltage divider. The pH measurer is a variable resistor (R1). The trim pot is also a variable resistor (R2).
+V --> R1 --+--> R2 --> Gnd
The + is connected to the analog pin. The voltage drop across the pH measurer is converted to a value between 0 and 1023. Actually, the value will never be 1023, since that would imply that R2 is 0 ohms.
Whether you could just create an offset for the analog value at 4.5 and another for the analog value at 8, and interpolate to determine the offset at some intermediate reading, or not, I don't know. You could try it and see. Whether the resulting interpolated offset + actual reading would be accurate enough could only be determined experimentally.
Thanks for taking the time to help me...
Riva:
I don't know what the analogue range you pH probe returns (I think the arduino analogue input read 0@zero volts and 1023@five volts) but I wonder if this could be calibrated using the map() function. http://arduino.cc/en/Reference/Map
For simplicity say (the perfect meter would read) pH of 4.5 analogue reads 450 and pH 8.0 analogue reads 800, a difference of 350.
Now you calibrate you imperfect pH meter and 4.5=430 and 8.0=803, a difference of 373.
Using the map() function you should be able to map the readings to the correct range.
map(value, fromLow, fromHigh, toLow, toHigh)
map(value, 430, 803, 450, 800)
I tried the map() function and it worked until the pH probe deviated from the known values. Is it possible to make the values 'fromLow & fromHigh' editable? Then i could write something from where to edit those values and then i have my calibration.
I tried the map() function and it worked until the pH probe deviated from the known values. Is it possible to make the values 'fromLow & fromHigh' editable? Then i could write something from where to edit those values and then i have my calibration.
The fromLow & fromHigh values would be the readings you obtain when calibrating the 4.5 & 8.0 pH values so every time you calibrate these values would change. The toLow & toHigh are the ranges you want the values to fall between so would be fixed.
When you read the pH device if 'value' falls outside fromLow to fromHigh then you know it needs re-calibrating. To improve accuracy of pH readings it might be worth taking several reading and returning the average.
Ok, i'll be following a couple of variable tutorials this evening
In the meantime i also took it another way. Tried something else. Don't shoot me if it's completely wrong, but this seemed logical to me for a reason unknown
#define pHPin 62 //Analog PIN 8
#define pHPlusPin 10
#define pHMinPin 11
float calibratedValue =0; //value needs to be inputted trough 'monitor'
void setup()
{
pinMode(pHPlusPin, OUTPUT); //setting PIN's as output
pinMode(pHMinPin, OUTPUT);
Serial.begin(9600);
Serial.println ("Begin calibration");
while(Serial.available() == 0){}
calibratedValue=Serial.read(); // i'm going from the idea that i'm only entering positive or negative values in the monitor, so no fault check if i enter a letter or something ;)
}
void loop()
{
//measuring pH level...
float sensorValue = 0;
sensorValue = analogRead(pHPin); //Read analog pin
float pH(0.0178 * sensorValue + calibratedValue - 1.889); //Conversionformula for pH
if (pH >= 6.00) //If pH gets below 5 or above 6 a
{ //corresponding pump gets activated.
digitalWrite(pHMinPin, HIGH);
digitalWrite(pHPlusPin, LOW);
}
else if (pH <= 5.00)
{
digitalWrite(pHPlusPin, HIGH);
digitalWrite(pHMinPin, LOW);
}
else if (pH > 5.00 || pH < 6.00)
{
digitalWrite(pHMinPin, LOW);
digitalWrite(pHPlusPin, LOW);
}
Serial.print("pH = : "); //adding pH to screen
Serial.println(pH);
}
else sensorValue gets multiplied by 0.0178 before applying the calibration offset.
pseudo code to do the mapping way would be something like
int fromLow = 0
int fromHigh = 0
Serial.println("Place probe in 4.5pH solution, wait for reading to stabilize then press button")
While (buttonNotPressed){}
fromLow = analogRead(pHPin)
Serial.println("Place probe in 8.0pH solution, wait for reading to stabilize then press button")
While (buttonNotPressed){}
fromHigh = analogRead(pHPin)
calibratedValue=Serial.read(); // i'm going from the idea that i'm only entering positive or negative values in the monitor, so no fault check if i enter a letter or something ;)
It's a good thing you said this:
Ok, i'll be following a couple of variable tutorials this evening
While you are at it, look at the Serial.read() function, and how serial data is sent (just like people type - one character at a time).
while(Serial.available() == 0){}
calibratedValue=Serial.read(); // i'm going from the idea that i'm only entering positive or negative values in the monitor, so no fault check if i enter a letter or something ;)
}
Serial.available() returns the number of characters available to read.
So, while no characters are available to read, call Serial.read()?
And, as PaulS already mentioned, that Serial.read() isn't going to do what you think it's going to do even if it does read an actual character.
So, while no characters are available to read, call Serial.read()?
Although the indentation in the quoted code may make it look like that is happening, the braces after the "while (Serial.available() == 0) {}"
say it is a busy-wait.
Is it possible to make the values 'fromLow & fromHigh' editable?
You can use variables. When you figure out how to alter the value stored in the variable (it is possible), the mapping will change.
Ok, figured out what variables actually are. Very basic if you ask me. Sho shame on me...
But in my defence i'm only programming with Arduino for about 4 days. Just received my tinkertoys and wanted to make something cooler than 'blink'. But, one doesn't say for nothing...first you must crawl before you can walk...
The serial.read function is for another day, but again thanks for taking the time to help me out.
I'm a chillipepper enthousiast and this year i'm growing on hydro, so i have an entire fall and winter to get my program op and running. I don't give up very fast, so you'll be hearing from me soon
else sensorValue gets multiplied by 0.0178 before applying the calibration offset.
pseudo code to do the mapping way would be something like
int fromLow = 0
int fromHigh = 0
Serial.println("Place probe in 4.5pH solution, wait for reading to stabilize then press button")
While (buttonNotPressed){}
fromLow = analogRead(pHPin)
Serial.println("Place probe in 8.0pH solution, wait for reading to stabilize then press button")
While (buttonNotPressed){}
fromHigh = analogRead(pHPin)
Riva,
Thank you to most of all. Your answer gave me the insight how to solve my problem. The mathematical error was kinda...
The tutorial on arduino.cc about While Loops was very interesting! I did the lab and got the led dimming when i put the pH probe in an acid en light up when i put it in a base. Now i just need to figure out what the analog value for pH4.003 and pH6.864. These are the actual buffer solutions i need for calibrating the probe. In my earlier reply i mentioned 4.5 and 8, but that was because i was at work and didn't have the bottles with me.
Now I'm going to learn what the code actually does and then rewrite/change it for my needs.
Off course I'll be posting my results here. So other people can learn from my mistakes and looking at some peoples reactions... I've made a few
As mentioned before, I'm thankful for all of your help & you guys will hear from me again. I promise ]