Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« on: July 16, 2012, 04:16:47 am » |
Hello everybody, I'm currently building a Hydroponics Controller which measures/controls pH, Temp, Humidity, water-level on the Arduino Mega 2560.  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...Thanks in advance, Billie
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #1 on: July 16, 2012, 04:17:05 am » |
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; }
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35535
Seattle, WA USA
|
 |
« Reply #2 on: July 16, 2012, 04:38:45 am » |
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. So, where is the code that attempts to do this?
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #3 on: July 16, 2012, 05:09:50 am » |
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... 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  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  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. Thanks again 
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35535
Seattle, WA USA
|
 |
« Reply #4 on: July 16, 2012, 05:12:00 am » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #5 on: July 16, 2012, 05:34:13 am » |
...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.
I hope this makes sense 
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #6 on: July 16, 2012, 05:35:56 am » |
What is to replace the pot meter?
I thought one could do it within code? Or am i presuming it wrong?
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35535
Seattle, WA USA
|
 |
« Reply #7 on: July 16, 2012, 05:37:47 am » |
I thought one could do it within code? Or am i presuming it wrong? Maybe you are. 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 How does one adjust/set the value to 4.5?
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #8 on: July 16, 2012, 05:45:25 am » |
Well, i have a pH pen  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)
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35535
Seattle, WA USA
|
 |
« Reply #9 on: July 16, 2012, 05:58:14 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Norfolk UK
Offline
Edison Member
Karma: 23
Posts: 1319
|
 |
« Reply #10 on: July 16, 2012, 06:06:53 am » |
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/MapFor 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)
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #11 on: July 16, 2012, 06:41:25 am » |
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... 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/MapFor 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. 
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35535
Seattle, WA USA
|
 |
« Reply #12 on: July 16, 2012, 07:10:35 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Norfolk UK
Offline
Edison Member
Karma: 23
Posts: 1319
|
 |
« Reply #13 on: July 16, 2012, 07:17:47 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Belgium
Offline
Jr. Member
Karma: 4
Posts: 61
|
 |
« Reply #14 on: July 16, 2012, 07:31:43 am » |
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);
}
|
|
|
|
|
Logged
|
|
|
|
|
|