soil moisture sensors and watering system using shift registers and analog mux's

Hello, Its been quite a while since i've worked with arduino and electronics so i'll try to get right back into the swing of things here...

I have a project i've been thinking about for a while, it involves 4 (or more) digital shift registers daisy chained together, and 2 (or more) analog multiplexers as well... the initial idea is to have 32 digital inputs and outputs and 16 analog inputs and outputs while only using about 9 digital outputs and 1 analog input on the arduino, leaving more inputs and outputs on the arduino to be used for other things.

the project is kindof based on an idea i got after seeing the project called the 'garden arduino' found here...

it involves using galvanized nails soldered to wires that are connected to the arduino... both of the nails are then inserted into soil. 5v current is sent through one nail, and depending on the moisture in the soil the conductivity between the two nails changes and that change is measured by an analog input of the arduino. basically the way the original garden arduino project is written, it detects that value and then if the value voltage read by the analog pin drops below a certain level, it kicks on a digital output that is attached to a relay that controls a water pump. the water pump feeds water to the plant, thereby creating a self watering plant.

I made a version of this project and was happy with the results, but there was something left to be desired because the for each plant i wanted to hook up individually i would need a seperate water pump and line (which seemed redundant) and i was also limited by the number of digital and analog inputs i had on the arduino.

so, i decided to get some 595 shift registers and some 4051 analog multiplexers, seeking to expand the I/O capabilities of the arduino for this project. i also came up with some ideas for improving the project:

-to avoid needing individual pumps and lines for each plant, decide to only use a single pump that can deliver strong pressure, and splitting the water line into 16 water lines with solenoid valves connected to each line... in this way the solenoids can control each individual line instead of individual pumps.

-use half of the digital shift registers for controlling the relays hooked up to the solenoids and pump

-use the other half of the shift registers for sending 5v current to the 5v galvanized in the soil.

-use all of the analog inputs for detecting values such as the soil moisture detector nail in the soil, or components that detect light, temperature, humidity, etc...

I've got the arduino hooked up to a daisy chained sequence of 4 shift registers...
-clock on digital pin 5
-latch on digital pin 6
-data on digital pin 7

and i've got the arduino hooked up to a single analog multiplexer (for now) with the data selection pins (S0-S2) and i/o pin (Z) connected
-S0 on digital pin 2
-S1 on digital pin 3
-S2 on digital pin 4
-Z on analog pin 0

(i can expand the number of analog I/O later by using another 3 digital pins by daisy chaining them)

anyway... i'm probably being long winded by now but anyway... i've got it hooked up now, but i don't have much experience programming with daisy chained shift registers. I also have to simultaneously send 5v through a specific channel of the shift registers, while also detecting that through a specific channel of the mux and then turn on the pump and open a solenoid valve.

I'd just like some help getting some ideas as to where to start in programming this. in the meantime, i'm going to just start coding and see what comes back to me from the deep recesses of memory... i'm definitely out of practice.

I definitely appreciate you reading this through and any advice, suggestions, and guidance you might have to offer.

thank you.

You are probably not going to like what I am about to say but there is no getting around it. You need to draw a complete schematic with pen & paper of your entire circuit and take a photo of it with your cell phone and post it. If you have some other means of generating a schematic that would be fine. If the schematic is too large you can use multiple 8.5 x11" printer sheets and show the
lines going off the edge of the page with the note "To page-2) etc.
We can't help you with any code without the schematic. Alternately , you could generate a wiring list that shows which pin on which chip goes to which pin on another chip etc. but that would be a worst case scenario.
No schematic, no code. I don't know if it is possible to describe your circuit with words. (not to be interpreted as "there are no words to describe your circuit...")

thanks for the prompt response... I'll get to work on it...

attached is an image of the breadboard layout, as well as an image of a wiring schematic.

thank you!

here is a wiring key for the above images...

red - 5v
black - Ground
blue - Clock 595 shift register
yellow - Latch 595 shift register
green - Data 595 shift register

grey - Selector 0 Analog multiplexer
ochre (gold) - Selector 1 Analog multiplexer
orange - Selector 2 Analog multiplexer
cyan - I/O for Analog Multiplexer

pink - solenoid valves and water pump
purple - 5v for soil moisture sensor probes
brown - analog inputs for soil moisture sensor probes

Hi plato_3,

First of all, can I ask the most obvious question: why not just use an Arduino Mega? 16 analog and 54 digital outputs…

Second question: do you actually need those analog multiplexers at all? Might be worth experimenting to see if you can loose them completely. Just connect a diode up to each sensor, common the diode outputs and connect that to your analog input. Since you will only apply 5V to one of the sensors at a time, that’s the sensor you will be reading. The diodes will prevent the voltage leaking away to ground via the other sensors.

As for your shift registers, you can use shiftOut(). If you have 3 registers, send 3 bytes out with 3 calls to shiftOut() before pulsing the latch line.

Paul

i have an arduino mega... and the reason i'm doing it this way is i want to be able to go beyond the 16 analog and 54 digital outputs of the mega, and i also want to make this project feasible for someone who also just has a uno or something else... basically i'm trying to make a low cost growing system that can handle as many plants or sections of plants that someone might need and i want it to be doable on any arduino.

secondly, i'm using the analog multiplexers because i've got more than enough of them, and i'd like to get more familiar with them... that and i have way more multiplexers than i do diodes at the moment... i like the idea of having a common diode output for all the sensors... really simplifies the coding for the project and takes out the necessity of the multiplexers altogether...

is there any case in which i would want to use analog multiplexers instead of using a common diode output? any advantage or use that i could still put them to if i choose to do the common diode output method you suggested?

thanks for your help.

plato_03:
i have an arduino mega... and the reason i'm doing it this way is i want to be able to go beyond the 16 analog and 54 digital outputs of the mega, and i also want to make this project feasible for someone who also just has a uno or something else...

OK, fair enough, and very altruistic of you!

plato_03:
secondly, i'm using the analog multiplexers because i've got more than enough of them, and i'd like to get more familiar with them... that and i have way more multiplexers than i do diodes at the moment...

Well, I think that kind of goes against your first point. Not everyone will have lots of analog multiplexers and diodes are much cheaper.

plato_03:
i like the idea of having a common diode output for all the sensors... really simplifies the coding for the project and takes out the necessity of the multiplexers altogether...

I don't know for sure the idea will work at all, that's why I suggested experimenting with it before abandoning your multiplexers.

If it does work, you could extend the idea to a matrix. 8 rows could be driven by 8 shift register outputs, and 6 columns connected (via diodes on each sensor) to 6 analog inputs, giving 48 sensors. Again, experiment needed to see if this works well, especially if the sensors are close together in the soil.

plato_03:
-to avoid needing individual pumps and lines for each plant, decide to only use a single pump that can deliver strong pressure, and splitting the water line into 16 water lines with solenoid valves connected to each line... in this way the solenoids can control each individual line instead of individual pumps.

Couldn't you just use a servo motor, attach a pipe and code it so it points to each plant?

Something like this?

WalkItOut:
Couldn't you just use a servo motor, attach a pipe and code it so it points to each plant?

Something like this?

Arduino Automatic Watering System for Plants Sprinkler : 7 Steps (with Pictures) - Instructables

i'm planning on hooking up 16 plants to this (or more) and want to have it so that i can basically have as many plants hooked up as i have shift register outputs for it... basically each plant would use 2 shift register outputs, one to detect moisture level in the soil and another one to kick on the solenoid valve that feeds water to that particular plant... the lines go straight to each plant so there is no spilling or anything... i noticed with the method that you suggested that some water gets spilled on the floor during delivery to the plants, and i definitely want to avoid messes and waste in my system. i'm making this to use for industrial and commercial indoor or outdoor farming, or for personal botanical projects that people might have... but the idea is to make something that can water as many plants as you need with precision.

PaulRB:
I don't know for sure the idea will work at all, that's why I suggested experimenting with it before abandoning your multiplexers.

If it does work, you could extend the idea to a matrix. 8 rows could be driven by 8 shift register outputs, and 6 columns connected (via diodes on each sensor) to 6 analog inputs, giving 48 sensors. Again, experiment needed to see if this works well, especially if the sensors are close together in the soil.

i like this idea of a matrix... i see how that could potentially work out very well... sensors being close together won't be an issue considering each plants soil will be isolated. I like all these ideas alot, they will make the project alot simpler to start coding... I'm thinking perhaps what i should do is use the analog multiplexers to switch to each column of the sensors, so that i can switch between which column is being read without using up any more analog inputs/outputs on the arduino...

i suppose my question at this point is, how do i individually control which shift register outputs are on or off? i'm looking for an example and i'm having difficulty finding anything that says in a straightforward way how to code up 4 shift registers together and individually control specific outputs... I'll keep digging around but if anyone has experience with that, i'd appreciate hearing from you about it... thanks.

Something like:

#define shiftRegisterCount 4

byte shiftRegister[shiftRegisterCount];

void setRegisterBit(int i, int v) {
  bitWrite(shiftRegister[i>>3], i && 7, v);
}

void updateShiftRegisters() {
  digitalWrite(latchPin, LOW);
  for (int i=0; i < shiftRegisterCount; i++)
    shiftOut(dataPin, clockPin, LSBFIRST, shiftRegister[i]);
  digitalWrite(latchPin, HIGH);
}

(untested, not even compiled!)

thanks for getting back to me with that code… in the time before i read that i had already written up some code and put it to work… i decided to not use the analog mux’s yet… i’ve just got the inputs from the soil sensors going to individual analog inputs… i just was anxious to get it working… i figure i can get the multiplexers going once i’ve got enough sensors and solenoids to where i’ll need them…

here is the code i wrote.

int dataPin = 8;
int latchPin = 9;
int clockPin = 10;

int plantOne = 800;
int plantTwo = 800;
int plantThree = 800;

void shiftControl(int SR4, int SR3, int SR2, int SR1, int duration)
{
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, SR4);
  shiftOut(dataPin, clockPin, MSBFIRST, SR3);
  shiftOut(dataPin, clockPin, MSBFIRST, SR2);
  shiftOut(dataPin, clockPin, MSBFIRST, SR1);
  digitalWrite(latchPin, HIGH);
  delay(duration);
}

void waterControl(int solLVal, int solRVal, int pumpVal, int offset, int runTime)
{
  shiftControl(solLVal, solRVal, 0, 0, offset);
  shiftControl(pumpVal, solRVal, 0, 0, runTime);
  shiftControl(solLVal, solRVal, 0, 0, offset);
}


void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  shiftControl(0,0,0,0,10);
  Serial.begin(9600);

}

void loop()
{
  shiftControl(0,0,0,1,10);
  plantOne = analogRead(0);
  Serial.print("Plant 1 : ");
  Serial.print(plantOne);
  Serial.print(" | ");
  shiftControl(0,0,0,2,10);
  plantTwo = analogRead(1);
  Serial.print("Plant 2 : ");
  Serial.print(plantTwo);
  Serial.print(" | ");
  shiftControl(0,0,0,4,10);
  plantThree = analogRead(2);
  Serial.print("Plant 3 : ");
  Serial.println(plantThree);
  Serial.print(" | ");
  Serial.println(".............................................");
  shiftControl(0,0,0,0, 1000);
  if(plantOne < 375)
  {
    waterControl(0, 1, 128, 500, 2500);
    Serial.println("Watering Plant 1...");
  }
  if(plantTwo < 375)
  {
    waterControl(0,2,128,500,2500); 
    Serial.println("Watering Plant 2...");
  }
  if(plantThree < 375)
  {
    waterControl(0,4,128,500,2500);
    Serial.println("Watering Plant 3..."); 
  }

}

let me know what you think, if there is any room for improvement or anything… thanks!

i just thought i should write here as a follow up… i found a few things in my code that had to be change, so here is the new code for the project (with better notes).

basically, i got everything wired up, wrote up some code and got everything going. i chose not to have water going through the pump or the lines yet, because i’m not completely done designing or building this… the electronics aren’t in an enclosure yet either, so i’m keeping everything dry until i can get everything sealed up that needs to be.

anyway, after i hooked everything up i found an issue with the 8 channel relay bank that controls the pump and solenoids.
the first time i tried my code, it worked great… however, upon unplugging the arduino from my computer, the solenoids and pump would all turn on, until controlled again by my arduino. if left like that, in the case of the arduino losing power, all plants would be flooded with water until power is turned on again. (not good)

i tried changing up the wires to the relay to fix this, but it only caused another problem… when i changed up the wires, the pump and solenoids would stay off when the arduino lost power (as they should) but i noticed that the switching was reversed with how the pumps and relay were controlled. i had made a change to the code to turn on the solenoid first before the pump, so that pressure doesn’t build up in the lines, and then the pump comes off for 2.5 seconds, then turns off, then the solenoid turns off a half second later. rather than that working correctly, i noticed it was reversed… so the solenoid and pumps were always on and open, except for when they were supposed to be watering, in which case it would turn off the solenoid, and then turn off the pump…

so basically it was either working correctly but would turn on the pump when powered down, or it would work incorrectly but at least the pump didn’t come on when powered down.

i quickly deduced that there was no rewiring that would fix this, it would need to be done in code… and that the solution was to invert the signals coming from the shift registers to the solenoids and pumps…

so rather than sending 2 bytes like this ‘10000000 00000001’ i rewrote the code to send something like ‘01111111 11111110’ instead.
now the code works perfectly AND the pumps and solenoids stay closed when powered down… so everything now works exactly as it should.

besides that i also added a new function for water control, changed some of the timing, and also mae it so that whenever its done watering it sends the off signal to the solenoids and the pump 3 times just to make sure that it turns off for sure. ( i had noticed that sometimes it wouldn’t turn on or off when it should and i figured that resending the off signal a few times would help ensure that they definitely get turned off when they should.

anyway, here is the new commented code! thanks for all your help!

/*

-Garden Arduino using Shift Registers, relay banks, solenoids,
and a water pump.

written by plato_03 5/9/2014
email me: plato_03@hyahoo.com

----------------------------------------------------------------*/

/*setting variables for controlling the data, latch, and clock
 pins of the shift shift registers*/
int dataPin = 8;
int latchPin = 9;
int clockPin = 10;

/*variables that will hold the values of soil moisture for
 each plant */
int plantOne;
int plantTwo;
int plantThree;

/* shiftControl - a function for controlling the shift registers, 
 both in sending 5v signals to individual plants but also to 
 control relays. SR4-SR1 variables values range between 0-255, 
 which pushes those values as a binary sequence through each shift 
 register. 
 
 if you are to add or take away shift registers, you would need to 
 revise this portion of code to have more 'SRx' variables, and add 
 another line of 'shiftOut' for each additional shift register. 
 the 'duration' variable is how long the code delays before moving 
 on to the next event afterwards.
 
 currently it sends out 4 bytes of information, the first two bytes
 are to control the 5v going to each soil probe, the last two bytes
 are to control the relay bank that are hooked up to the solenoids
 and water pump.
 
 when sending out 5v to soil moisture probes, it will send out data
 to each shift register as follows:   
 SR4      SR3      SR2      SR1
 11111111 11111111 00000000 00000001
 11111111 11111111 00000000 00000010
 11111111 11111111 00000000 00000100
 ^^^^^^^^-^^^^^^^^---soil moisture probes
 
 when controlling the pump and the solenoids it will send 0's 
 instead of 1's to SR4 and SR3 to turn on the relays as follows:
 
 SR4      SR3      SR2      SR1
 pump-->01111111 11111110 00000000 00000000
 01111111 11111101 00000000 00000000
 01111111 11111011 00000000 00000000
 solenoids-^^^^^^^-^^^^^^^^
 */



void shiftControl(int SR4, int SR3, int SR2, int SR1, int duration)
{
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, SR4);
  shiftOut(dataPin, clockPin, MSBFIRST, SR3);
  shiftOut(dataPin, clockPin, MSBFIRST, SR2);
  shiftOut(dataPin, clockPin, MSBFIRST, SR1);
  digitalWrite(latchPin, HIGH);
  delay(duration);
}

/* waterControl - a function for controlling the water pump and 
 solenoids. they should be wired up to a relay bank, which are
 controlled by the shift registers. it works by using shiftControl
 function, except with more parameters. 
 
 solLVal and solRVal is the same as SR4 and SR3 from shiftControl 
 and are used to turn on solenoids connected to the relays. 
 
 pumpVal is for turning on the pump and the solenoid and replaces 
 solLVal in the 2nd iteration of shiftControl. 
 offset is how long the solenoids open or close up before and after
 the pump runs. 
 
 runTime is how long  the pump stays on before turning off.
 
 notice that in the place of SR2, an SR1, they are always 0. this is
 because soil moisture sensors are always off during watering.
 
 */
void waterControl(int solLVal, int solRVal, int pumpVal, int offset, int runTime)
{
  shiftControl(solLVal, solRVal, 0, 0, offset);
  shiftControl(pumpVal, solRVal, 0, 0, runTime);
  shiftControl(solLVal, solRVal, 0, 0, offset);
}

/*setup shift register latch, clock, data pins, begins the Serial
 output, and also sends a shiftControl signal to turn off all the 
 relays by sending all 1's through SR3 and SR4, and turns off all 
 moisture probes by sending all 0's to SR1 and SR2*/
void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  Serial.begin(9600);
  shiftControl(255,255,0,0,10);


}
/*loop turns on each soil moisture probe in sequence, stores the 
 energy that gets through the other end of moisture probe as a
 variable (plantOne, plantTwo, plantThree, etc), it then displays
 through serial moniter which plant is being detected and what the
 value is that was read by the moisutre sensor, then moves on to 
 detecting the next one.*/
void loop()
{
  shiftControl(255,255,0,1,10);
  plantOne = analogRead(0);
  Serial.print("Plant 1 : ");
  Serial.print(plantOne);
  Serial.print(" | ");
  shiftControl(255,255,0,2,10);
  plantTwo = analogRead(1);
  Serial.print("Plant 2 : ");
  Serial.print(plantTwo);
  Serial.print(" | ");
  shiftControl(255,255,0,4,10);
  plantThree = analogRead(2);
  Serial.print("Plant 3 : ");
  Serial.println(plantThree);
  Serial.println(".............................................");
  shiftControl(255,255,0,0, 1000);

  /*these 'if' conditions are for if the water level of any plant
   goes below the level stated, then it will read in the serial 
   moniter that is it Watering Plant X and kick on the pump and 
   solenoid needed to water the plant using waterControl function.
   after the waterControl function is used, shiftControl is called
   twice to make sure that the water pump and solenoids are all 
   closed for sure.*/
  if(plantOne < 375)
  {
    Serial.println("Watering Plant 1");
    Serial.println(".............................................");
    waterControl(255, 254, 126, 500, 2500);
    shiftControl(255,255,0,0,10);  
    shiftControl(255,255,0,0,10);
  }
  if(plantTwo < 375)
  {        
    Serial.println("Watering Plant 2");
    Serial.println(".............................................");
    waterControl(255,253,125,500,2500);
    shiftControl(255,255,0,0,10);
    shiftControl(255,255,0,0,10);
  }
  if(plantThree < 375)
  {
    Serial.println("Watering Plant 3");
    Serial.println(".............................................");
    waterControl(255,251,123,500,2500);
    shiftControl(255,255,0,0,10);
    shiftControl(255,255,0,0,10); 
  }

}

plato_03:

WalkItOut:
Couldn't you just use a servo motor, attach a pipe and code it so it points to each plant?

Something like this?

Arduino Automatic Watering System for Plants Sprinkler : 7 Steps (with Pictures) - Instructables

i'm planning on hooking up 16 plants to this (or more) and want to have it so that i can basically have as many plants hooked up as i have shift register outputs for it... basically each plant would use 2 shift register outputs, one to detect moisture level in the soil and another one to kick on the solenoid valve that feeds water to that particular plant... the lines go straight to each plant so there is no spilling or anything... i noticed with the method that you suggested that some water gets spilled on the floor during delivery to the plants, and i definitely want to avoid messes and waste in my system. i'm making this to use for industrial and commercial indoor or outdoor farming, or for personal botanical projects that people might have... but the idea is to make something that can water as many plants as you need with precision.

PaulRB:
I don't know for sure the idea will work at all, that's why I suggested experimenting with it before abandoning your multiplexers.

If it does work, you could extend the idea to a matrix. 8 rows could be driven by 8 shift register outputs, and 6 columns connected (via diodes on each sensor) to 6 analog inputs, giving 48 sensors. Again, experiment needed to see if this works well, especially if the sensors are close together in the soil.

i like this idea of a matrix... i see how that could potentially work out very well... sensors being close together won't be an issue considering each plants soil will be isolated. I like all these ideas alot, they will make the project alot simpler to start coding... I'm thinking perhaps what i should do is use the analog multiplexers to switch to each column of the sensors, so that i can switch between which column is being read without using up any more analog inputs/outputs on the arduino...

Ah right.

Did you manage to complete the project?