Last active
March 21, 2023 17:32
-
-
Save pingud98/34dc39a738bcd736dd396c6d1f9e5504 to your computer and use it in GitHub Desktop.
Hydroponics measurement system for Arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Hydroponics system monitor | |
* J. Devine | |
* Runs on Arduino Pro 5V | |
* Sensors: | |
* DFRobot pHmeter V1.1 | |
* Waterproof DS18B20 water temperature sensor | |
* TMP36 air temperature sensor | |
* HC-SR04 distance sensor (for water level..) | |
* A european two pin plug for EC measurements | |
* Output in CSV; no error handling yet | |
* write out all the results in the following format: | |
* uptime (ms),water level (cm), pH, pH Voltage, water temp (degrees C), air temp (degrees C), RC, EC, PPM | |
* | |
* This code is entirely based on some awesome examples, re-worked for this application | |
* The internal pullup library is needed to avoid an external 4.7k resistor on the DS18B20 | |
* Great blog entry by josh levine @bigjoshlevine - Thanks! I was thinking EXACTLY the same thing | |
* https://wp.josh.com/2014/06/23/no-external-pull-up-needed-for-ds18b20-temp-sensor/ | |
* | |
* PPM code | |
* Modified from ElCheapo Arduino EC-PPM measurments | |
* 28/8/2015 Michael Ratcliffe [email protected] | |
* | |
* Pinouts: | |
* | |
* Pin 10 - DS18B20 data pin | |
* Pin 12 - HC-SR04 Trig | |
* Pin 13 - HC-SR04 Echo | |
* Pin A2 - pH Meter V1.1 data (DF Robot breakout) | |
* Pin A3 - TMP36 data pin | |
* Pin D4 - EC/PPM Power | |
* Pin A1 - EC/PPM Pin | |
* Pin A3 - EC/PPM Ground | |
* | |
* Licensed under GPL V3. Read the license here: | |
* https://www.gnu.org/licenses/gpl-3.0.en.html | |
* | |
*/ | |
#define SensorPin A2 //pH meter Analog output to Arduino Analog Input 2 | |
#define Offset 0.00 //deviation compensate | |
//#define LED 13 | |
#define samplingInterval 20 | |
#define printInterval 800 | |
#define ArrayLenth 40 //times of collection | |
int pHArray[ArrayLenth]; //Store the average value of the sensor feedback | |
int pHArrayIndex=0; | |
//PPM code | |
// Modified from ElCheapo Arduino EC-PPM measurments | |
// 28/8/2015 Michael Ratcliffe [email protected] | |
int R1= 400; | |
int Ra=25; //Resistance of powering Pins | |
int ECPin= A1; | |
int ECGround=A3; | |
int ECPower = 4; | |
//User variales for the PPM/EC measurement | |
float PPMconversion=0.7; | |
float TemperatureCoef = 0.019; //this changes depending on what chemical we are measuring | |
float K=2.85; | |
//Fixed variables | |
//float Temperature=10; variable substituted for Ftemp in this code | |
float EC=0; | |
float EC25 =0; | |
int ppm =0; | |
float raw= 0; | |
float Vin= 5; | |
float Vdrop= 0; | |
float Rc= 0; | |
float buffer=0; | |
//water temperature | |
float Ftemp=10; | |
// DS18S20 Temperature chip i/o | |
#include <OneWire.h> //this is the onewire version with the pullup high. | |
OneWire ds(10); // on pin 10 | |
int echopin = 13; | |
int trigpin = 12; | |
int vcc = 11; | |
long duration, distance; | |
//tmp36 readout | |
int sensorPin = 0; | |
void setup(void) | |
{ | |
//PPM Measurement setup code | |
pinMode(ECPin,INPUT); | |
pinMode(ECPower,OUTPUT);//Setting pin for sourcing current | |
pinMode(ECGround,OUTPUT);//setting pin for sinking current | |
digitalWrite(ECGround,LOW);//We can leave the ground connected permanantly | |
delay(100);// gives sensor time to settle | |
delay(100); | |
//** Adding Digital Pin Resistance to [25 ohm] to the static Resistor *********// | |
// Consule Read-Me for Why, or just accept it as true | |
R1=(R1+Ra);// Taking into acount Powering Pin Resitance | |
pinMode(echopin, INPUT); | |
pinMode(trigpin, OUTPUT); | |
// pinMode(LED,OUTPUT); | |
Serial.begin(9600); | |
// Serial.println("pH meter experiment!"); //Test the serial monitor | |
} | |
void loop(void) | |
{ | |
static unsigned long samplingTime = millis(); | |
static unsigned long printTime = millis(); | |
static float pHValue,voltage; | |
if(millis()-samplingTime > samplingInterval) | |
{ | |
pHArray[pHArrayIndex++]=analogRead(SensorPin); | |
if(pHArrayIndex==ArrayLenth)pHArrayIndex=0; | |
voltage = avergearray(pHArray, ArrayLenth)*5.0/1024; | |
pHValue = 3.5*voltage+Offset; | |
samplingTime=millis(); | |
} | |
if(millis() - printTime > printInterval) //Every 800 milliseconds, print a numerical, convert the state of the LED indicator | |
{ | |
// Serial.print("Voltage:"); | |
// Serial.print(voltage,2); | |
// Serial.print(" pH value: "); | |
// Serial.println(pHValue,2); | |
// digitalWrite(LED,digitalRead(LED)^1); | |
printTime=millis(); | |
} | |
byte i; | |
byte present = 0; | |
byte data[12]; | |
byte addr[8]; | |
int Temp; | |
ds.reset_search(); | |
if ( !ds.search(addr)) { | |
// Serial.print("No more addresses.\n"); | |
ds.reset_search(); | |
return; | |
} | |
// Serial.print("R="); | |
for( i = 0; i < 8; i++) { | |
// Serial.print(addr[i], HEX); | |
// Serial.print(" "); | |
} | |
if ( OneWire::crc8( addr, 7) != addr[7]) { | |
// Serial.print("CRC is not valid!\n"); | |
return; | |
} | |
if ( addr[0] == 0x10) { | |
// Serial.print("Device is a DS18S20 family device.\n"); | |
} | |
else if ( addr[0] == 0x28) { | |
// Serial.print("Device is a DS18B20 family device.\n"); | |
} | |
else { | |
// Serial.print("Device family is not recognized: 0x"); | |
// Serial.println(addr[0],HEX); | |
return; | |
} | |
ds.reset(); | |
ds.select(addr); | |
ds.write(0x44,1); // start conversion, with parasite power on at the end | |
delay(1000); // maybe 750ms is enough, maybe not | |
// we might do a ds.depower() here, but the reset will take care of it. | |
present = ds.reset(); | |
ds.select(addr); | |
ds.write(0xBE); // Read Scratchpad | |
// Serial.print("P="); | |
// Serial.print(present,HEX); | |
// Serial.print(" "); | |
for ( i = 0; i < 9; i++) { // we need 9 bytes | |
data[i] = ds.read(); | |
// Serial.print(data[i], HEX); | |
// Serial.print(" "); | |
} | |
Temp=(data[1]<<8)+data[0];//take the two bytes from the response relating to temperature | |
// Serial.println("One, then 0"); | |
// Serial.println(data[1]); //msb | |
// Serial.println(data[0]); //lsb | |
//Temp=Temp>>4;//divide by 16 to get pure celcius readout | |
Ftemp =(Temp * 0.0625); | |
//next line is Fahrenheit conversion | |
//Temp=Temp*1.8+32; // comment this line out to get celcius | |
// Serial.print("T=");//output the temperature to serial port | |
// Serial.print(Temp); | |
// Serial.print(" "); | |
//Serial.print(" fT=");//output the temperature to serial port | |
// Serial.print(Ftemp); | |
// Serial.print(" "); | |
// Serial.print(" CRC="); | |
// Serial.print( OneWire::crc8( data, 8), HEX); | |
// Serial.println(); | |
//getting the voltage reading from the temperature sensor | |
int reading = analogRead(sensorPin); | |
// converting that reading to voltage, for 3.3v arduino use 3.3 | |
float ATvoltage = reading * 5.0; | |
ATvoltage /= 1024.0; | |
// print out the voltage | |
//Serial.print(ATvoltage); Serial.println(" volts"); | |
// now print out the temperature | |
float temperatureC = (ATvoltage - 0.5) * 100 ; //converting from 10 mv per degree wit 500 mV offset | |
//to degrees ((voltage - 500mV) times 100) | |
//Serial.print(temperatureC); Serial.println(" degrees C"); | |
// now convert to Fahrenheit | |
//float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0; | |
//Serial.print(temperatureF); Serial.println(" degrees F"); | |
//delay(1000); | |
digitalWrite(trigpin, LOW); // Added this line | |
delayMicroseconds(4); // Added this line | |
digitalWrite(trigpin, HIGH); | |
delayMicroseconds(20); // Added this line | |
digitalWrite(trigpin, LOW); | |
duration = pulseIn(echopin, HIGH); | |
distance = (duration/2) / 29.1; | |
Serial.print(millis()); | |
Serial.print(';'); | |
Serial.print(distance); | |
// if (distance >= 200 || distance <= 0){ | |
// Serial.println("Out of range"); | |
//} | |
//else { | |
//Serial.print(distance); | |
//Serial.println(" cm"); | |
// } | |
//delay(500); | |
//write out all the results in the following format | |
// uptime (ms),water level (cm), pH, pH Voltage, water temp (degrees C), air temp (degrees C), RC, EC, PPM | |
Serial.print(';'); | |
Serial.print(pHValue,2); | |
Serial.print(';'); | |
Serial.print(voltage,2); | |
Serial.print(';'); | |
Serial.print(Ftemp); | |
Serial.print(';'); | |
Serial.print(temperatureC); | |
Serial.print(';'); | |
GetEC(); | |
PrintReadings(); | |
delay(5000); | |
} | |
double avergearray(int* arr, int number){ | |
int i; | |
int max,min; | |
double avg; | |
long amount=0; | |
if(number<=0){ | |
Serial.println("Error number for the array to avraging!/n"); | |
return 0; | |
} | |
if(number<5){ //less than 5, calculated directly statistics | |
for(i=0;i<number;i++){ | |
amount+=arr[i]; | |
} | |
avg = amount/number; | |
return avg; | |
}else{ | |
if(arr[0]<arr[1]){ | |
min = arr[0];max=arr[1]; | |
} | |
else{ | |
min=arr[1];max=arr[0]; | |
} | |
for(i=2;i<number;i++){ | |
if(arr[i]<min){ | |
amount+=min; //arr<min | |
min=arr[i]; | |
}else { | |
if(arr[i]>max){ | |
amount+=max; //arr>max | |
max=arr[i]; | |
}else{ | |
amount+=arr[i]; //min<=arr<=max | |
} | |
}//if | |
}//for | |
avg = (double)amount/(number-2); | |
}//if | |
return avg; | |
} | |
void GetEC(){ | |
//************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; //acounting for Digital Pin Resitance | |
EC = 1000/(Rc*K); | |
//*************Compensating For Temperaure********************// | |
EC25 = EC/ (1+ TemperatureCoef*(Ftemp-25.0)); | |
ppm=(EC25)*(PPMconversion*1000); | |
;} | |
//************************** End OF EC Function ***************************// | |
//***This Loop Is called From Main Loop- Prints to serial usefull info ***// | |
void PrintReadings(){ | |
//Serial.print("Rc: "); | |
Serial.print(Rc); | |
Serial.print(';'); | |
//Serial.print(" EC: "); | |
Serial.print(EC25); | |
Serial.print(';'); | |
//Serial.print(" Simens "); | |
Serial.print(ppm); | |
//Serial.print(" ppm "); | |
Serial.println(';'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment