Let me start with saying it is not really an ‘Arduino’ but an Atmega 328 with Arduino bootloader.
After doing several ‘garduino’ projects, i wanted to build something that I could use to either run a greenhouse outside, or a growbox inside the house, for veggies and stuff during the winter.
The circuit contains various elements, that I will discuss:
Most will probably recognize the ‘barebones arduino’ basically the atmega 328, a crystal, 2 capacitors and a reset circuit.
K1: is a header that will feed into 4 relays that have the following functions:
Switch on the irrigation, switch on a lamp, switch on a heater, switch on a fan
K2: is an FTDI header for uploading programs to the Atmega.
K3: is a header to connect a DHT11 moisture and temperature sensor. Those only need 3 connectors, but I had 2 with different pin lay-outs, hence the 4 prong connector. R11 is a pull up resistor
K4: is the IIC header that connects to an LCD
K5: is a connector to connect an RTC module. The Led and resistors are optional… just in case you would want a led flashing every second.
CN 1 and 2 are to connect a soil moisture sensor. In order to save the sensor being broken down by electrolysis quickly, The transistor is there to switch off current through the sensor.
The Zenerdiodes are there to protect the Atmega against high voltages that may build up on a long wire.
There are 2 switches tat can be used freely. Currently I use the pushbutton to select a different reading on the LCD and the throw switch is still unused.
The level Switch is a switch that closes when the waterlevel in the reservoir is too low. It is a simple float switch
The LDR can determine if it is day or night if no RTC is used. ofcourse for inside use it is not that usefull
Software:
/* meet de vochtigheid
als minder dan ingestelde waarde, pomp aan
meet temperatuur
als lager dan ingestelde waarde, verwarming aan
meet humidity
als hoger dan ingestelde waarde zet ventilator aan
ventilator ook aan snachts
http://www.quickgrow.com/gardening_articles/fans_air_movement.html
LCD commands:
lcd.setBacklight(LED_OFF);
lcd.noBacklight();
lcd.clear();
lcd.home();
*/
/*-----( Import needed libraries )-----*/
#include
#include //Malpertida
#include "RTClib.h" //Adafruit
//DHT11 instellingen
#include
dht DHT;
/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
/*-----(Declare RTC objects )------*/
RTC_DS1307 RTC; //declare onject
/*-----( Declare pins )------*/
byte moisturePin=0; //read soil mositure
byte levelPin= 1; //analogue Pin1 set level for irrigation
byte humidPin=2; //Physical pin4 Humidity sensor
byte lightPin=5; //Switches on light
byte fanPin=6; //Switches fan
byte pumpPin =7; //Switches pump
byte hotPin= 8; // Switches heater
byte buzPin=9; // Switches buzzer
byte emptyPin=10; //digital Pin10 guards waterlevel
byte spikePin=12; //Digital Pin12 -> Extra for intermittent switching of spike
byte LDRPin=3;// analog pin for LDR
byte PushButton=4; // PushButton
byte SwitchButton=3;// Make Switch
byte push=0;
byte sButton=0;
#define DHT11_PIN humidPin
/* Variable setting */
unsigned int moist=0; //will contain the soil moisture level
unsigned int irrigate=0; //sets level for irrigation in case no potmeter
byte level=0;
int c;// contains the temperature reading
// these constants won't change:
const int sensorMin = 40; // LDR minimum, discovered through experiment
const int sensorMax = 1012; // LDR maximum, discovered through experiment
byte light; // value for LDR reading
// Create a set of new characters
const uint8_t charBitmap[][8] = {
{
0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 }
,
{
0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 }
,
{
0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 }
,
{
0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 }
,
{
0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 }
,
{
0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 }
,
{
0x0, 0x4, 0xE, 0x15, 0x4, 0x4, 0x4, 0x0 }
,
{
0x4,0x4,0x4, 0x4, 0x15, 0xE,0x4,0x0 }
};
/// -------- end creation--------------
//The following function, "setup", must always be present
void setup()
{
Serial.begin(115200);
//upload defined characters to LCD
//---------------end upload----------------
pinMode(levelPin,INPUT); // set level
pinMode(humidPin,INPUT); // measures humidity
pinMode(emptyPin,INPUT); // measures reservoir
//digitalWrite(emptyPin, HIGH); // turn on pullup resistors
pinMode(SwitchButton, INPUT); // make Switch
pinMode(PushButton, INPUT); // PushButton
pinMode(spikePin,OUTPUT); // for alternative supply to spikes
pinMode(pumpPin,OUTPUT); // Output for Relay
pinMode(fanPin, OUTPUT); // Output for fan
pinMode(hotPin, OUTPUT); // Output for heater
pinMode(lightPin, OUTPUT);// Output for light
pinMode(buzPin, OUTPUT); // Output for buzzer
digitalWrite(pumpPin, LOW);// Pump off
digitalWrite(spikePin, LOW);// moisture sensor off
digitalWrite(fanPin,LOW); // fan Off
digitalWrite(hotPin,LOW); // heater off
digitalWrite(lightPin, LOW); // light Off
digitalWrite(buzPin, LOW); // buzzer off
/* Now LCD */
lcd.begin(16,2); // initialize the lcd for 20 chars 4 lines, turn on backlight
int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));
for ( int i = 0; i < charBitmapSize; i++ )
{
lcd.createChar ( i, (uint8_t *)charBitmap[i] );
}
lcd.backlight();
// Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("Greenhouse");
// ------- Quick 2 blinks of backlight -------------
flash(2);
// ------- Quick buzz--------------------------------
// buzz(1);
Wire.begin(); //needed for RTC, not for LCD
RTC.begin();
/* Set the date / time to the time this program was compiled.
Comment this OUT, AND upload, to let the clock just run. */
// RTC.adjust(DateTime(__DATE__, __TIME__));
}
/*----------------------------(end setup )---------------------*/
void loop()
{
DateTime now = RTC.now(); //Get the current data
// Serial.print("The year is ");
// Serial.print(now.year(), DEC);
// Serial.print(" Month = ");
// Serial.print(now.month(), DEC);
// Serial.print(" Day = ");
// Serial.print(now.day(), DEC);
// Serial.print(" Time = ");
// Serial.print(now.hour(), DEC);
// Serial.print(':');
// Serial.print(now.minute(), DEC);
// Serial.print(':');
// Serial.print(now.second(), DEC);
// Serial.println();
//------------end of RTC
// ---------- 1. Check if there is enough water -------------
// check if there is water
level= digitalRead(emptyPin);
Serial.print(level);
if (level==0) {
digitalWrite(buzPin, HIGH);
delay (50);
digitalWrite(buzPin, LOW);
delay(500);
}
//------------2. Read the soil moisture content/switch pump----------------
/*
First read the level set with P1 on the levelPin and store that in 'irrigate'
*/
irrigate=sample(levelPin);
/*
Then we read the soil humidity sensor.
We'll first have to set the spikePin to HIGH, in case that is used to feed the sensor.
After the reading we set it back)
If the value read ('moist') is smaller than what is considered dry ('irrigate')
then the pump should be switched on for a specific time.
This is done by indicating a higher treshhold for switching the pump off
*/
digitalWrite(spikePin, HIGH);// put voltage on the humidity sensor
delay(100); //wait a short while
moist=sample(moisturePin); //read soil humiditySensor
//
digitalWrite(spikePin, LOW);
// level= digitalRead(emptyPin);// just read again to make sure
if (moist <= irrigate) digitalWrite(pumpPin, level);
if (moist >= irrigate+5) digitalWrite(pumpPin, LOW); // prevents Jitter
//-------------3. Read the DHT11 humidity/temp sensor-----------------
// now we measure temperature and air humidity
// READ DATA
// Serial.print("DHT11, \t");
int chk = DHT.read11(DHT11_PIN);
switch (chk)
{
case DHTLIB_OK:
// Serial.print("OK,\t");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
case DHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error,\t");
break;
default:
Serial.print("Unknown error,\t");
break;
}
//-------------4. Read LDR ----------------------------------------
light=Map(LDRPin);
/* ------------------Actions -------------------*/
//-------------5. DISPLAY DATA ------------------------------------
// Serial.print(DHT.humidity,1);
// Serial.print(",\t \t");
//Serial.println(DHT.temperature,0);
/* Display data on LCD */
push=digitalRead(PushButton);
//Serial.print("Push. : ");
// Serial.println(push);
if (push==1) // pushbutton not pressed
{
lcd.clear();
lcd.setCursor(0, 0); //set cursor on first line (line 0)
lcd.print("Temp. : ");
lcd.print((float)DHT.temperature, 0);
lcd.print (char(1)); // prints degree sign
lcd.print("C");
lcd.print(" ");
lcd.print (char(7-level));
Serial.print(level);
// Serial.print("Temp. (oC): ");
// Serial.println((float)DHT.temperature,2);
lcd.setCursor(0,1); //set cursor on 2nd line
lcd.print("Humidity: ");
lcd.print((float)DHT.humidity, 0);
lcd.print("%");
lcd.print(" ");
// Serial.print("Humidity (%): ");
//Serial.println((float)DHT.humidity, 2);
delay(1000); // wait for one second and then print the soilmoisture
lcd.setCursor(0,1);
lcd.print ("Irr. Level: ");
lcd.print(irrigate);
lcd.setCursor(0,0);
lcd.print("Moisture: ");
lcd.print(moist);
lcd.print(" ");
}
if (push==0) // pushbutton pressed
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("licht: ");
lcd.print(light);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print("licht niv.: ");
lcd.print(analogRead(LDRPin));
//buzz(1);
}
// ---------------5. Action on temperature ------
c=(DHT.temperature);
if (c<=20) //Serial.println(c);
{
// switch on heating
digitalWrite(hotPin,HIGH);
} else {
digitalWrite(hotPin,LOW);
}
//--------------6. Action on Humidity -----------
if (DHT.humidity >=50)
{
// switch on fan
digitalWrite(fanPin, HIGH);
}
else
{
digitalWrite(fanPin,LOW);
}
delay(1000);
//end dht
//end loop
}
//------- End of Main program-----------
//
//-------- Start of functions------------
int sample(int z)
/* This function will read the Pin 'z' 5 times and take an average.
Afterwards it will be mapped to 8 bits by dividing by 4
Could ofcourse immediately divided by 20
*/
{
byte i;
int sval = 0;
for (i = 0; i < 5; i++){
sval = sval + analogRead(z);// sensor on analog pin 'z'
}
//sval = sval / 5; // average
//sval = sval / 4; // scale to 8 bits (0 - 255)
sval=sval / 20;
return sval;
}
//------------- Flash the backlight a number of times--------
void flash(byte y)
{
byte j;
for (j=0; j<y;j++)
{
lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight(); // finish with backlight on
return;
}
// This function will sound the buzzer "u" times
void buzz(byte u)
{
byte k;
for (k=0; k<u;k++)
{
digitalWrite(buzPin, HIGH);
delay(200);
digitalWrite(buzPin, LOW);
delay(200);
}
return;
}
// This function will blink an LED a number of times for a specific duration
void ledblink(int times, int lengthms, int pinnum){
for (int x=0; x<times;x++){
digitalWrite(pinnum, HIGH);
delay (lengthms);
digitalWrite(pinnum, LOW);
delay(lengthms);
}
}
// This function maps the LDR reading into nrs 0-3
int Map(byte sens) {
// read the sensor:
int sensorReading = analogRead(sens);
// map the sensor range to a range of four options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
// do something different depending on the
// range value:
switch (range) {
case 0: //
// Serial.println("dark");
lcd.backlight();
break;
case 1: //
// Serial.println("dim");
lcd.backlight();
break;
case 2: //
// Serial.println("medium");
lcd.noBacklight();
break;
case 3: //
// Serial.println("bright");
lcd.noBacklight();
break;
}
return range;
}