Introduction: Arduino Soil Probe Using DS18B20 and DIY Moisture Hardware
As a fanatical gardener or a professional farmer, knowing the environmental conditions of our soil is invaluable. Obviously, we can't measure the number of worms or pieces of organic humus, but we can measure temperature and moisture content really easily.
This is not a difficult project and what you end up with is a very swanky looking bit of kit that will impress most people until you put it in the soil and it gets completely covered in dirty, sticky mud!
Step 1: Parts
- Resin that is used for pasting onto glass fibre
- Resin hardener.
- 6mm 316 grade stainless steel rod.
- DS18B20 temperature probe with water proof cable attached.
- 4.7 K Ohm resistor (yellow, purple, red, gold)
- 10 K Ohm resistor (brown, black, orange, gold)
- 35 mm OD stainless steel tube
- 3mm bolts and nuts x 2
- 3mm wire terminals x 2
- Twin core cable
- Arduino uno
Step 2: Fabrication
I have been developing these devices for a year or so now and the use of liquid resin is incredibly effective and produces a very professional looking results.
Following the photos above:
- Use a 32mm hole saw to cut out a steel and a plywood disc to hold the sensor probes in place during fabrication.
- Flatten and drill the ends of the probes to 3mm for the electrical connections.
- Attach the cables.
- Drill three holes in the plywood disc for the two long probes on the outside and the short DS18B20 probe in the middle.
Next is a three stage process for applying the resin:
- Insert the plywood about 1/4 way up the body of the main tube and pour in a small amount of resin and hardener, making sure that there is plenty of space between all the electrical contacts.
- After the resin has set hard, turn the assembly upside down and fill the tube with resin around the three probes.
- After this batch of resin has set, turn it back upright and fill the top of the tube with resin.
Now test the device for short circuits with a multimeter.
Step 3: Test and Calibrate the Probe Using Arduino
The DS18B20 is easy to set up, but the wiring is counter intuitive and there are two different ways to wire it which can create more confusion. For the probe with a stainless tip and leads attached, yellow = signal and black and red are connected together and go to ground (GND).
Download and install the Dallas Temperature library (http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip or search the interweb for latest version). Then use the oneWireSearch program to find your probe's address.
Copy and paste the address into the main code in the next step.
Simple?
Run the main code and immerse the soil probe in very, very wet soil - it should be a thick goo type liquid. The soil should be the same as the soil you want to monitor and it will have various salts in it that conduct electricity when wet. When the soil is dry, the conductivity dramatically reduces to almost zero.
If you look at my code, I have used a value of 0.102 to multiple against the analogue pin reading, but every soil type will be different. The probe should read 'zero' in the air or in dry soil. Extra sensitivity can be created by deciding at what point soil is actually dry, so we could just measure to that point rather than to 'absolutely bone dry', however, I have not done this in this example, just to keep it simple.
Step 4: Arduino Uno Code for Soil Probe
The code is mostly fairly straight forward but it's important to pulse the moisture probe rather than supplying a constant voltage. For one, this saves energy, but most importantly, it helps prevent the electrodes from corroding too quickly. In this example, power for the device is pulsed from pin 9. (Updated September 2018)
#include <OneWire.h> // OneWire DS18S20, DS18B20, DS1822 Temperature Example // http://www.pjrc.com/teensy/td_libs_OneWire.html http://www.pjrc.com/teensy/td_libs_OneWire.html http://www.pjrc.com/teensy/td_libs_OneWire.html // The DallasTemperature library can do all this work for you! // http://milesburton.com/Dallas_Temperature_Control_Library http://www.pjrc.com/teensy/td_libs_OneWire.html http://www.pjrc.com/teensy/td_libs_OneWire.html OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary) int sensorPin = A0; int sensorValue = 0; // variable to store the value coming from the moisture sensor unsigned long moistureValue = 0; float tempsoil; int moisturePowerPin = 9; void setup(void) { pinMode(moisturePowerPin, OUTPUT); Serial.begin(9600); } void loop(void) { byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float celsius, fahrenheit; if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; } Serial.print("ROM ="); for( i = 0; i < 8; i++) { Serial.write(' '); Serial.print(addr[i], HEX); } if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // the first ROM byte indicates which chip switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); // or old DS1820 type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); 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(" Data = "); 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(" "); } Serial.print(" CRC="); Serial.print(OneWire::crc8(data, 8), HEX); Serial.println(); // Convert the data to actual temperature // because the result is a 16 bit signed integer, it should // be stored to an "int16_t" type, which is always 16 bits // even when compiled on a 32 bit processor. int16_t raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw << 3; // 9 bit resolution default if (data[7] == 0x10) { // "count remain" gives full 12 bit resolution raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); // at lower res, the low bits are undefined, so let's zero them if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms //// default is 12 bit resolution, 750 ms conversion time } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print(" Temperature = "); Serial.print(celsius); Serial.println(" Celsius, "); Serial.println(""); Serial.print("Soil temperature: ");Serial.print(celsius);Serial.println(" Celsius, "); digitalWrite(moisturePowerPin, HIGH); // Powers up the moisture sensor for 0.1 seconds to prevent corrosion. sensorValue = analogRead(sensorPin)*0.102; // The sensor is calibrated by multiplying by 0.102. delay (100); digitalWrite(moisturePowerPin, LOW); // Powers down the moisture sensor Serial.print("Soil moisture: "); Serial.print(sensorValue); Serial.println(" %"); delay (10000); }
Attachments
Step 5: Final
The next thing to do would be to transmit the data to somewhere nice and warm and dry where we can sit leisurely drinking coffee and gaze in adoration at our work. I certainly don't want to be constantly having to walk over to the soil probe to look at a tiny LCD screen - I'm far too lazy for that!
http://www.goatindustries.co.uk/weather/
This soil probe is connected to a full blown GPRS weather station module which will be featured in a separate Instructable - just as soon as I retrieve the rain gauge data from a black hole in the Arduino's memory system!
Watch this space for more weather station Instructables including testing a proper professional anemometer and wind vane and maybe even a weather station development printed circuit board.