Introduction: Automatic Irrigation System

About: Electrical Engineer, control systems, automation, small electronics, home automation, microcontrollers etc.

This is an in-depth tutorial on how i created an auto-irrigation system for a garden using the Texas Instrument Tiva family microcontroller. There are a handful of examples online about irrigation systems but I really wanted something that could take advantage of a handful of sensor options. The main system will be easily expandable for number of zones and will allow you to add and remove sensors as you need them.


(By clicking vote in the top right corner)

Step 1: The Parts

To construct the system I was able to use a lot of development board or recycle boards from old products.

The Launchpad:

First the Tiva launchpad is the brain of the system. It has a TM4C123GH6PM micro onboard and includes the programming and debugging interface. It will run of the on-board 16 Mhz crystal but this can be changed on the board, in the code, or with a custom board design. We can also use the RGB LED on the launchpad for feedback to the user.

Power Source:

To power the entire system I am using a standard 12 VDC power supply. You can pick these up online or at your local electronics store. You may even have one laying around. I then recycled an older car usb charger that had a broken plug on it. These charges take ~12VDC from the battery of your car and convert it to ~5VDC. We can use the 12 VDC to open/close our valves and the 5VDC to power launchpad and any of our sensors.


To control the actual water flow to the zones I purchased a couple of cheap 12 VDC valves offline. I chose 12 VDC because of the power source mentioned earlier but this can be adjusted to your specific needs.


To actuate the values I purchased a 4 relay breakout board online. You can find these all over the place and they will allow us to switch a connection to the valve's positive terminal. They will use the 5 VDC power supply for operation but output 12 VDC to our valves. You can find relay boards that will allow a wide range of voltages (AC and DC) through the relays if you are using a different valve.


We will use a handful of sensors in this system to make decisions about skipping watering cycles, predicting over-watering, monitoring timing, and operator control.


I picked up a DS1307 breakout board online that I will used to monitor the current time. These rtcs are fairly reliable and pretty cheap. The on-board battery will maintain the time for about 9-17 years without external power. The clock can accurately count up to the year 2100 and has leap year compensation. It also comes with a bit of non-volatile memory available for storing values (if you wanted to allow an operator to change settings and hold them after a power loss) I know typically you wouldn't consider an RTC as a "sensor". I threw it in this category because we are relying on this module for the entire system to work. Compared to some of the other sensors this module will be used the most

Temperature Sensor:

For this system I will be utilizing the internal temperature module of the TM4C123GH6PM micro to monitor the temperature within the enclosure. This is purely for protection to prevent any damage to any of the components. If the temperature is ever detected above a threshold the system will turn on a warning LED, shut down everything, and then go to sleep until a user wakes it through a button press.

Moisture Sensor:

I am going to implement a moisture sensor option that a user can insert into the ground soil of a zone to use for detecting if a watering cycle should be skipped and also to detect an over-watering scenario. There are several options for moisture sensors. I chose a simple one that would provide analog feedback to the controller and allow me to change the sensitivity of its effect. In the current software I'm only implementing this to provide feedback to the user, but it can easily be moved to make direct changes to watering cycles.

Humidity/Temperature Sensor:

Another option to include (with or without the moisture sensor) is a humidity and temperature sensor. This can provide more feedback about the current environment for making adjustments to the watering schedule. We can shorten a watering time if we feel that there is enough humidity in the air or if the temperature is lower than normal. I've chosen the HIH-6130 humidity and temperature sensor because it provides both humidity and temperature in one reading. This sensor will use I2C communication. The current implementation for this sensor is ratio based. We will monitor the current relative humidity based on a target value. This ratio is applied to the length a zone should be on for. For example if we are directly on target for our RH we would have a ratio of 1 and therefor the system will water each zone as it is specified to. If the RH was half of what was expected it would provide double the watering. This will work for slight humidity changes, but will probably need to changed in the future for a better coverage.

Capacitive Button:

Finally we will include a capacitive sensor as a button for user control. Whats nice about this being capacitive is we can place it inside the enclosure and the user will still be able to "press" the button based on a marker on the outside. The button will have multiple functions depending on if it is pressed once, held, etc. We will cover how this works better in the software portion.

Step 2: The Diagram

The diagram should be pretty self explanatory. We have the power section at the top showing our 12 VDC input. Then we have the recycled 12VDC-5VDC converter outputting the power for our micro and sensors. The sensors are all located towards the left side. Starting from the top we have the capacitive sensor for a button, followed by the DS1307 real time clock, then the HIH-6130 humidity sensor, and finally next to that is the soil moisture sensor. One sensor not pictured here is the internal temperature sensor for the launchpad.

To the right side you see the four relays (which are all contained on a single circuit board) and each of the valves they are wired to. Different relay boards may or may not have two outputs as shown here (they may be tied together already). It isn't necessary to tie them together but I have it shown in the diagram. The way the relays/valves work is the valve needs the 12VDC power to open and no power to close by the force of the water. To make sure the valve is able to close and not have the output of the relay board floating we will toggle the relay between ground and 12VDC.

The pinout for each of the zones and a few of the sensors can be adjusted. It may require some changes to the code but I tried to pull most of the pins and registers into definitions at the top of the relevant file or in the typedefs file. The only ones to be careful of are the ADC pins, which would require a channel change, and the timer/interrupt pins, which would require a change to the configuration. The I2C sensor will need to be placed on one of the I2C sets and the code will need to be configured to work for that set.

The current setup the firmware is written for is as follows:


Zone0: Port D.3

Zone1: Port E.1

Zone2: Port E.2

Zone3: Port E.3

Capacitive button:

Control: Port B.2

Signal: Port E.0

Analog Moisture Sensor:

GND: Port B.1

Control: Port B.0

Signal: Port B.5

Real Time Clock and Humidity/Temperature Sensor:

I2C3 SCL: Port D.0

I2C3 SDA: Port D.1

Step 3: The Software

The basic structure of the software is a start-up routine that initializes all of the peripherals followed by a state block that allows the system to switch between different modes. There are also several timers and interrupt handlers that process information at a certain interval or monitor outside peripherals for input. Each of the sensors are broken down into individual modules (except the internal temperature sensor). You'll find the modules as libraries in the drivers directory. The methods that are to be used publicly outside the module start with the modules names. The code should be pretty well commented.

I've posted the software on my git account so that I can publish updates as I expand the system and correct bugs I come across.

The basic breakdown is as follows:

The Zones:

The zones are defined at the begging of main.c. We have:






Zone* Zones[NUMBER_OF_ZONES] = { &zone0, &zone1, &zone2, &zone3};

Throughout the software we use the NUMBER_OF_ZONES #define to iterate through the zones. We use an array of pointers to each of the zones to access them quickly without having to make multiple copies in memory. The definitions are then pretty straightforward. Each zone is a structure containing the properties: Status, OverrideStatus, Port, Pin, OnHour, OnMinute, and OnLength. You can add as many as you can find GPIO for, add the pointer to the array, and update the NUMBER_OF_ZONES #define to indicate the number of zones you have.

System Modes:


This is our primary mode. For this mode we set the status LED color to green, well pull the current time from the DS1307, and then we check the current zone status based on our new time.


OVERRIDE mode is designed for an entire system override. This occurs when a user presses the capacitive button for a set amount of time. In this mode we set the status LED color to red and then check if the system has been running in override mode for 24 hours. If we have been we clear the override status and return to run mode. If we havent we continue to leave the system in override mode.


The SYSTEM_SHUTDOWN mode is intended for safety critical shutdown. Currently the only module that could implement system shutdown is the internal temperature sensor. Every time we check the internal temperature sensor we compare it to a threshold. If we pass the threshold we enter this mode where we clear each of the zones, turn the red LED on steady, disable all of the timers and interrupts and then go into hibernation mode. The only way to exit from this mode is by a user pressing the wake button on the Launchpad itself.

The Interrupts:

Button Interrupt:

The button interrupt handler has two parts. The first handles when the button is pressed. This will toggle a flag saying we saw a button press, turn the BLUE LED on, and start Timer 0 which will simply increment a counter. When the button is released we will turn off the BLUE LED, disable Timer 0, and evaluate the duration of the button press. Currently the only condition checked for is a system override which is a button press of 2 seconds. If we detect a system override action we switch based on the current run mode. For entering system override mode we flash the RED LED for confirmation, and set the mode to OVERRIDE. For leaving system override we clear all zone overrides, flash the GREEN LED for confirmation, and set the mode to RUN.

General Timer 1 Interrupt:

This is a one second timer we will use to check sensor input and print to the UART. Upon entering the interrupt we clear the flag. Then we check the internal temperature sensor, the humidity/ext. temperature sensor, and the moisture sensor. These values get saved in their respective areas. We then print the status of all measurements and zones to the UART. If a user has the USB debug port plugged into a PC and opened a terminal they should see a message like the following printing every second:

TIME: 18:46:27









Before we leave the general timer interrupt we check if our one second timer has hit a multiple of 10. If it has we toggle the status led on, if not we toggle the led off, and then we increment the counter. This gives us a nice indicator to the user to show that the system is still running and what mode it is currently in. The LED will give just a quick flash every ten second

The Modules:


AMS_InitSensor - Initializes AMS on ADC1 sequence 0

AMS_ReadSensor - Reads average sensor value (256 samples)


DS1307_GetTime - Gets current time from DS1307

DS1307_SetTime - Sets DS1307 to specified time

bcdToDec - Converts binary coded decimal value to decimal value

decToBcd - Converts decimal value to binary coded decimal value


HIH6130_UpdateData - Reads data from HIH6130

HIH6130_GetStatus - Returns HIH6130 status

HIH6130_GetHumidity - Returns HIH6130 humidity reading

HIH6130_GetTemperature - Returns HIH6130 temperature reading


I2C_SetupI2C3 - Setup process for I2C3

I2C_SendSlaveStart - Sends slave address and start bit followed by a stop bit

I2C_ReadBytes - Reads n number of bytes

I2C_ReadBytesFromAddress - Reads n number of bytes from address

I2C_ReadSingleByte - Reads single byte from address

I2C_WriteByte - Writes single byte to address

I2C_WaitForDone - Waits for I2C Master bus to clear

I2C_Delay - Delays milliseconds


UART_SetupUART0 - Setup routine for UART0

UART_PrintMessage - Prints array of characters to UART

UART_PrintLong - Prints long value to UART

Step 4: The Final Product

Here it is. The images show the final product. To finish it off I wrapped up the voltage regulator board in some electrical tape and placed everything neatly in a small plastic enclosure I had lying around. I then used some long 8 conductor wire to run from where I've placed the system to the valves outside. I'm only showing one valve here as I set it up but I've switched that with a 4-way splitter and have 4 different zones running now. I also needed to get some different fittings because I wanted to run this particular zone through a small plastic tubing. I ran the system through a heat test of 8 hours of run-time, cycling the relays every minute. The casing stayed under 90 degrees F the entire time.

Step 5: Expanding

Where to go from here?

There are a handful of additions i'd like to get to eventually. Some ideas that might make the system better:

- The analog moisture sensor module should not rely on GPIO for power and ground. We can still switch the sensor using GPIO, but it should really be connected to the power rails. Currently I have it running off GPIO because the nice connection plugs come as an inline set of 3.

- The analog sensor conversions should be triggered and collected using timers and interrupts. Currently we use a processor trigger whenever we want to get a value. We could run these off of the one second general timer and once the conversion is complete trigger an interrupt handler to retrieve the values

- Implement timeouts. On all of the sensor readings we could implement timeouts so that if waiting for the I2C bus or waiting for an ADC conversion takes to long we exit and try again later.

- Implement watchdog. There is currently no watchdog in the system, so if we got locked up anywhere we wouldn't know until our system stop watering our gardens.

- Set system to sleep between zone changes. We could implement a run mode where we calculate the time until the next zone change and have the system go to sleep for that amount of time. This would mean the clock is not running unless we are currently switching a zone. This would mean a lot less power usage from the micro and sensors

- Internet ready! An addition I am currently working on adding is making this board internet ready. In the future I plan to port the system to use the new Tiva Connected Launchpad where I have a webpage running from the microcontroller. This would allow a user to log into the system anywhere they have an internet connection to monitor the system and adjust settings.

Epilog Challenge VI

Participated in the
Epilog Challenge VI

Green Design Contest

Participated in the
Green Design Contest

Summer #mikehacks Contest

Participated in the
Summer #mikehacks Contest

Sensors Contest

Participated in the
Sensors Contest

Outdoor Workshop Contest

Participated in the
Outdoor Workshop Contest