Solar powering an Attiny or Arduino with a capacitor, or just use AA? Part 1

If you have a processor in a remote location that you cannot or will not bring a psu cable to, you have several options of supplying it with energy.
Batteries come to mind and these could be rechargeable or not, or one can use a capacitor. After all, those store energy as well. To make a capacitor a viable option, obviously it needs to be a big one (in capacity, not especially in size), and one has the option of adding a solar cell to it.
As I wanted to feed an attiny that is somewhere in my garden and that is asleep most of the time and as I had some idle solar panels  (9 Volts, 2 Volts) those seemed  suitable to use, but as they do not provide much energy during the night, I needed to store that energy as well. As storage Nicads or even a LiPo came to mind. A Lipo I discarded as it takes some extra circuitry to do any decent charging. A nicad obviously needs some consideration in charging and discharging  as well, but they are more tolerant albeit that a deep discharge is usually not appreciated by them, nor is a constant charge.
Therefore I also considered using a “supercapacitor” I have a capacitor of 10.000uF but one can hardly call that a supercapacitor, but nowadays supercapacitors are readily available at modest prices. They would be easy to use in a charging circuit (basically a resistor would be enough) and they don’t mind frequent  charge and discharge. As their charge is  limited, obviously I would need a solar-cell, so the only thing I needed to see is if they would carry my application ‘through the night’

The Charge of a capacitor is expressed in Coulomb (symbol C).
this can be expressed as:

C=F * V  (where of course ‘F’ stands for the capacity in Farad)
Energy in Joule is expressed as:
J=C*V
Which is:
F*V*V  of F.V²
However, at a given voltage and capacity only half of the energy is available to charge the capacitor hence the energy in the capacitor will be:
J=½ * F *V²
and Joules can also be expressed as ‘Wattseconds’:
J=W *s

So if we calculate the number of Joules in the capacitor at 5.1 Volt:
J=0.5 * 1.5 * 5.1² = 19.5 J
Now obviously we will not all use those as the attiny kinda stops working at 1.8 Volt. If we calculate the number of Joules still left then we come to
J=0.5 * 1.5 * 1.8² = 2.43 J
So the amount of usable energy comes to 19.5-2.43= 17J (rounded down)

From an earlier project on  an attiny13 that was put to sleep only to awake every so many seconds, I found out that the current consumption was 5.5 uA at 5 Volt. Now obviously it will consume a bit less when the voltage drops, so lets assume 4uA at an average of 3.45 Volt (The average voltage being (5.1+1.8)/2=3.45 Volt).
We can calculate the average power consumption as V*I:
3.45 * 4*10⁻⁶ = 13.8 uWatt
as we have 17 Joules available and 17 joules being 17 Ws (Wattseconds) we can calculate the time:
J=W*s
s=J/W
s=17/(13.8 *10⁻⁶)
s=17/13.8  *10⁶
s=1.23 *10⁶
s=1230 000 sec (1,23 million seconds)
that is:
20.531 min, is
342 hrs is
14 days
Now this is just an approximation as there might be some current leakage. The processor will need to do something when awake, like flash a  led or send something, so it will probably not make the full 14 days, but that is not important as it is obviously enough to carry us through the night and probably an overcast day as well.

So how would this be if I used normal AA batteries or NiCad batteries?
As example for regular alkaline batteries  I will take the ubiquitous Philips  LR6. Fortunately someone else already calculated the energie stored in these batteries  at  1986 mAh at a discharge of 100mA. As the performance of these batteries is increasing when the discharge decreases, I will use 2000mAh for my calculations.
If one uses 3 of those to get to 4.5 Volts that will be a total of 9000mWh or 9 Wh.
Again, we will not be able to use this all as we have 1.8 Volt as lower limit, so we will be stuck with 3.6 Wh that we cant use, leaving  5.4 Watthour usable energy.
The average Voltage on the  processor will be:
(4.5+1.8)/2=3.15 Volts.
the average power consumption thus is:
3.15* 4*10⁻⁶ = 12.6uW
as we have 5.4 Wh available we can again calculate the time:
h=5.4/12.6 * 10⁶
h=0.428571 *10⁶
h=428571 hr
=17857 days
=592 months
=50 years
Wow. Why would anybody want to use anything else but LR6 batteries ?
Well for several reasons: 3 of those batteries take more space and eventhough they tend to perform well at low temperatures and low discharge rate, we all have experienced that Alkaline batteries left in a hardly used device tend to leak, even destroying that device by its corrosive leaking. Advantages and disadvantages of alkaline batteries are discussed here.
Nevertheless using alkaline batteries can be a good choice, but don’t forget to change them.

Using NiCad batteries gives a somewhat similar calculation. Suppose we use 3 cells of 1.2 Volt 2000mAh (or 2Ah).
Total energy will be 3.6*2= 7.2 Wh
useable energy will be (3.6-1.8)* 2=3.6 Wh
the average voltage we set at (3.6+1.8)/2=2.70 Volt
The average power consumption will be:
2.7* 4*10⁻⁶ = 10.8uW  (V*I)
The time will thus be:
h=(3.6/10.8) * 10⁶
=333333 hr
=38 yrs
Now if that only was true. My experience with  for instance solar garden lights (that often only have an 800mAh cell)  is that they usually dont last through the winter… and mind you, those are being recharged (which could contribute to their demise).
Nevertheless they may be a good choice.

In a following article I will discuss some practical examples

 

A capacitive soil humidity sensor: Part 2

In a previous article I presented a simple way to read a capacitive moisture sensor with a simple RC generator.
In this post I will present a sensor with some added functionality that can be read through I2C. The circuit (figure) doesnt need much explanation: the RC generator we saw in the previous article and the two variable resistors in a voltage divide read by analogue inputs. The Attiny 45  is the heart, or rather the brains of the sensor. As the Attiny  functions as an I2C slave we will need the TinyWireS library. The library comes with some examples and one example was quite easy to rework to what I needed. The code is as follows.

#define I2C_SLAVE_ADDRES 0x4
#include <TinyWireS.h>//https://github.com/rambo/TinyWire
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif

volatile uint8_t i2c_regs[] =
{
	0x00,
	0x00,
	0x00,
	0x00,
};
// Tracks the current register pointer position
volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);

byte LDRvalue;
byte NTCvalue;
int MoistPulse;

/**
 * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the
 * send-buffer when using this callback
 */
void requestEvent()
{
	TinyWireS.send(i2c_regs[reg_position]);
	// Increment the reg position on each read, and loop back to zero
	reg_position++;
	if (reg_position >= reg_size)
	{
		reg_position = 0;
	}
}

/**
 * The I2C data received -handler
 *
 * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does
 * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly,
 */
void receiveEvent(uint8_t howMany)
{
	if (howMany < 1) { // Sanity-check return; } if (howMany > TWI_RX_BUFFER_SIZE)
	{
		// Also insane number
		return;
	}

	reg_position = TinyWireS.receive();
	howMany--;
	if (!howMany)
	{
		// This write was only to set the buffer for next read
		return;
	}
	while(howMany--)
	{
		i2c_regs[reg_position] = TinyWireS.receive();
		reg_position++;
		if (reg_position >= reg_size)
		{
			reg_position = 0;
		}
	}
}


void setup()
{
	pinMode(1, INPUT);
	TinyWireS.begin(I2C_SLAVE_ADDRESS);
	TinyWireS.onReceive(receiveEvent);
	TinyWireS.onRequest(requestEvent);
}

void loop()
{
	readSensors();
	/**
	 * This is the only way we can detect stop condition (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=984716&sid=82e9dc7299a8243b86cf7969dd41b5b5#984716)
	 * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead).
	 * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop.
	 */
	TinyWireS_stop_check();
}

void readSensors()
{
	LDRvalue = (analogRead(A2)) >>2; // max value is 1023/4=255 is 1 byte (FF) physical pin3=PB4=A2
        i2c_regs[0] = LDRvalue;
	NTCvalue = (analogRead(A3)) >>2; // max value is 1023/4=255 is 1 byte (FF) pin2=PB3=A3
	i2c_regs[1] = NTCvalue;
	//pulsepin= pin6=PB1
	MoistPulse = pulseIn(1, HIGH);
	i2c_regs[2] = highByte(MoistPulse); // or use = MoistPulse >> 8;
	i2c_regs[3] = lowByte(MoistPulse); // or use = MoistPulse & 0xFF;
}

I have called the pulseIn function with an integer rather than with a long. This means that you will have to choose a value for R3 that gives a reasonable range for the type of soil that you use. A range of say 0-200 uS is very reasonable. Once you have done that you can also add a timeout to the pulseIn function. This should be abt 2 times the pulselength you expect (but depends on the duty cycle). With regard to the two variable resistors, they are in pull up so their value is Rntc = Rseries/((1023/ADC) – 1));  For the NTC this could be substituted in a Steinhart Hart approximation

The code to call the values (and that is loaded onto the master arduino) is even simpler:

#include <Wire.h>
void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  for (byte i=0;i<4;++i){
  Serial.print("0x");
  Serial.println(readRegister(i),HEX); // print the character
}
Serial.println(" ");
    delay(1000);
  }

uint8_t readRegister(uint8_t regaddress)
{
	Wire.beginTransmission(4);
	Wire.write((byte)regaddress);
	Wire.endTransmission();
	Wire.requestFrom(4, 1);
	return Wire.read();


 delay(500);
}

This code only prints out the values, you still need to combine the LSB and MSB from the cycle time and e.g. switch a pump based on the value. You could do that with this function:

int combine (byte lsbv, byte msbv)
{
	int value = msbv << 8;
	value = value | lsbv;
	//value= msbv<<8 | lsvb;//if you want to do it in one go
	return value;
}

Don’ t forget that the I2C lines need pull-up resistors of 4.7-10k.

In a next article I will present the construction of the probe itself.

A capacitive soil humidity sensor: Part 1

An automated plant/garden watering system is a popular application for  the Arduino and other microcontrollers. The humidity sensor that is often used is  often a resistance meter: 2 probes in the soil form a resistor and as part of a voltage divider that gives info on the amount of water in the soil.
The major shortcoming of these sensors is that since there is a current flowing, the probe is sensitive to electrolytic corrosion. Another shortcoming is that it doesnt really give information on the soil humidity, but more on the  ion concentration in the soil. Remember: pure water is a bad conductor, It are the ions in the water that make it a conductor.

To get around the corrosion, people have started to feed the probe with AC rather than DC current, but at best the circuits for this supply a pulsating DC current. Another  possibility to minimize corrosion is to  switch off  the current to the probe and only switch it on when a measurement is taken, say every 5  minutes.

All these measures help but even then, just due to the contact with moist soil, the metal on the probe will corrode and weather.
Another method is to encase the probes in plaster. Some people swear by it but I  think it is bothersome. Also the plaster encased probe has a lag as it will retain water  for some time after the  soil is already dry and it will still be dry for some time after the soil is already moist.

Capacitive measuring is a way to avoid these problems. With capacitive measurement the ‘plates’ of the capacitor can be electrically isolated from the soil and the soil in fact forms the dielectrum of the capacitor. Water makes a good dielectrum, whereas ions dont. Capacitive measuring therefore will have a better correlation with the actual amount of water in the soil than resistive measuring and, as said, ideally there will not be any corrosion.

Although the Arduino can measure capacity, it needs 3 pins for that. Also, it isnt really practical to have a long wire as part of your soil probe capacitor go to your Arduino as the wire and whether it is  straight or curly or in a loop, will act as a parasitic capacity and affect the measurement.
Putting your Arduino right onto your plantbed might also not be the best solution.

capacitive74hc14
RC Oscillator With 74HCT14

A better way to do this is to introduce an RC oscillator in which the soil functions as a capacitor and the Arduino measures the frequency that comes out of the oscillator. More water  will increase the value of the ‘capacitor’ which usually will lower the frequency (or increase the cycle time) and that can be measured with the arduino.

An easy RC oscillator can be seen in the figure to the right. A 74HC14 or 74HCT14 Inverter Schmitt-trigger is all you need. For the HC version the Frequency is:
f=1/T=1/(0.8*R*C)
for the HCT version it is:
f=1/T=1/(0.67*R*C)

But in fact the frequency isn’t really that important because we are not making a frequency meter. We are only interested in changes of the frequency that relate to  dry, moist or wet soil. The workings of this type of Oscillator are explained here. and here. The theory behind the frequency calculation is explained here.

leydenjarI tested my set-up initially with a sort of Leyden Jar as a capacitor. Simply put I taped two pieces of alufoil on the outside of a glass jar, attached wires to it and tried if I could measure a change between an empty and a full jar. I started out using a 100k resistor, but only got a decent range after using a 2M2 resistor: an empty jar gave me 1uSec (maybe less, but I guess that was my lower limit) a half full jar around 50uS and a full jar about 100uS (measured with PulseIn). From using a known capacitor I knew I had to use the formula f=1/T=1/(0.67*R*C), but as said, neither the frequency or the actual capacitor value are of much importance as we are just looking for  changes.

Nevertheless the capacity of this jar (when full) could be calculated from
100*10⁻⁶=0.67*2.2*10⁶*C
C=(100*10⁻⁶)/(1.47*10⁶)
C=68*10⁻¹²
C=68pF
Now ofcourse this isn’t entirely correct as with PulseIn We only measured half a cycle, so in fact the Capacity is more likely to be 136pF, provided the dutycycle is 50% (some sources say it is 50% others say it is 33% with the space  2*mark).

byte pin = 8;
unsigned long duration;

void setup()
{
  pinMode(pin, INPUT);
  Serial.begin(115200);
}

void loop()
{
  duration = pulseIn(pin, HIGH);
  Serial.print("Time ");
  Serial.print(duration);
  Serial.print(" usec ");
  Serial.print(500/duration);
  Serial.print(" kHz ");
  Serial.print(500000/duration);
  Serial.println(" Hz");
  delay(500);
}

Then it was time to do some garden field tests. There are several ways to construct a probe: two pieces of PCB at a distance from eachother, One piece of PCB with two plates etched onto it, or a piece of double sided PCB. With regerd to the latter, we tend to think of a capacitor as two plates with a dielectrum in between, but in fact it can also be two  plates with a dielectrum around it.

capacitive probe-textMy garden field test, using two insulated plates of PCB (picture) kinda gave similar results as with the Leyden Jar so I knew I had a decent design.

Yet, two plates is not really very handy: you have a loose wire connecting the plates and as that forms part of the capacitor it introduces stray capacitance, so I decided to go for either a double sided PCB, or a single sided PCB with two plates etched onto it and then place the oscillator on that PCB as well. Frankly, that idea isnt new as many of the (semi)DIY (e.g. the ‘Chirp’) or commercial capacitive probes follow that design as well.

Now it is always good  that before you make a PCB to think through what you want. As I was using only 1/6th of the 74HCT14, I was thinking maybe I could use the other gates as RC oscillators as well  for e.g. an LDR or NTC. Now ofcourse I immediately dismissed that again as I could just as well use an analog read of those and I would have to run extra cables that would all carry a frequency signal, no doubt those would interfere, but it got me thinking. The ‘Chirp’ has a big brother that has an I2C interface, if I would add that, I could add some other sensors (light, temperature)  to my probe. With just the capacitive sensor I would have to run 3 wires (+Vcc, signal, ground). With I2C 4 wires (+Vcc, SDA, SCL, Ground) would be enough for a number of sensors on my probe. Also, as I have various plantbeds, having a number of I2C probes wouldnt require  more inputs on my Arduino.

Obviously, adding I2C meant adding a microcontroller, preferably a cheap one, which easily brings one to the attiny25/45/85 series. If you have good eye sight and a steady hand, you could consider the soic version that is available from 30-70 cts. If you go for a DIP version, that is around 0.9-1 euro. Considering one can get an entire Pro Mini for about 1.20, obviously that is a narrow gap and I (or you) could consider giving each plantbed a totally dedicated  Pro Mini microprocessor that could take care of the irrigation as well.
Having said that, in the past, I have made a self contained system for plantbeds, just using 1 Opamp, so maybe I should just consider this I2C excercise a ‘learning excercise’

capacitive74HC14_attinyI came up with the following circuit. It is easy to recognise the RC oscillator. The cycle signal is fed to PB1 whereas the analog inputs on PB3 and PB4
A3= PB3=physical pin2;A2=PB4=physical pin3.
Pin PB2 is used as SCL signal and PB0 as SDA signal for the I2C interface.

If for any reason you do not have a 74HCx14 in your toolbox, there are other ways of constructing an RC generator. E.g. a 555 or a 74HC00. Even a single transistor could be used. With this type of oscillator the dutycycle approaches 50%
rc-osc

555-oscillator-probe

In a next article I will discuss how to implement the I2C software.

Arduino for greenhouse or growbox

greenhouse2Let 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;
}


Opamp for your garden

opamp-probe

(You may want to have look at the improved version right away)

I admit that this has little to do with Arduino’s, but when working on my previous articles on moisture probes and garden irrigation with an Attiny, I mentioned using op-amp comparators instead of microcontrollers, so I thought I’d publish one like that as well.
The concept of an op-amp comparator is simple, if the ‘+’ gate is higher than the ‘-‘ gate, the output goes high, otherwise it goes low.
So with a humidity sensor attached in dry soil, the resistance of that sensor is high and therefore the voltage on the ‘-‘ gate is low and presumably lower than the voltage on the ‘+’ pin and therefore thge output of the opamp will go high.

This will switch on the Solidstate relay and the pump will start pumping. The water that flows into the plantbed will decrease the resistance between the humidity spikes, th evoltage on the ‘-‘ pin wil rise until it is above the level set with P1, the output will go low and the pump will be switched off.

Instead of a Solidstate relay you can also choose for a regular relay, hence the circuit around T1.

Capacitor C2 is in fact a bit optional. after the output of the op-amp goes low, C2 will still have a bit of charge that will keep the pump turn a little bit longer after the humidity is ‘enough’. It also gives a bit of delay in switching the pump on. This avoids jittering of the pump.

The value of R1 largely depends on the type of soil probe you decide to make. Some people have two spikes close together and that would call for a lower value of R1, some people choose to have the spikes at opposite sides of a plantbed, obviously that calls for a higher value of R1.

It is not really necessary to adapt R1, but if R1 and the resistance of the probe in ‘almost to dry’ condition are far off, the gain of P1 will be limited.

As this is an Arduino dedicated site, I will pull the arduino in here as well. You could choose not to let the Arduino do the measuring of the soil through its analog gates, but you could hook up th eoutput of the above opamp to a digital port of the Arduino and only let it check high or low.
You could build, say 4 of these circuits, each (use a quad opamp then) and have your arduino just do the measuring of the outputs and take appropriate action.741pcb

this is a design that is for toner transfer. So you are looking at it from the pertinax side. PDF design here. (NOTE There is new design in which a flaw was eliminated)
Below the component placing on the PCB. Unfortunately (I use a different program for the circuit and the PCB as I dislike Fritzing’s circuit design), the numbering of the components is different, but it does not take a rocket scientist to figure it out.741-opbouw

U3 is the connector for the power. J1 is the connector for the probesu6 is there for a different spacing of the capacitor. U2, U4 and U5 are for a relay. U5 and U2 should be drilled according to the size of the relay you happen to use.
J2 is the switching output of the SSR. The entire PCB is about 4×5 cm.

Mounting components on the PCB

Power supply is 5-10 Volt. Depending on what type 741 you are using it could be up to 18 or 22 volts. If you feed with more than 10 Volts you need to recalculate and adapt the value of R2 in the circuit (unfortunately this has come out as R4 on the PCB design) . The forward voltage on the 39MF22 is 1.2 Volts, for a regular LED that is nominal 2 Volts. So if you would feed with say 15V and say 10 mA, you would need a resistor of 12.8/10=1.28k (say 1.4 k). With the current resistor you would have a current of12.8/0.330=39mA. That is too much for the 39MF22 (max 20 mA). The max supply voltage with the current 330 ohm resistor is in fact 10 Volts (and that is alreday pushing it with 20.6mA).

The current 330 Ohm resistor gives a value of 5.5 mA, which is just above the trigger current of the 39MF22.
Because of variations in resistor values and forward voltages of the LED, 330 might in some instances be just a bit too much if you are feeding the circuit with just 5 volts. Try 220 or a 180 Ohm resistor then.

You should stick to the following minimal and maximal values of your resistor (in Ohm)

Voltage Min value Max value
5 90 360
6 140 560
7 190 760
8 240 960
9 290 1160
10 340 1360
11 390 1560
12 440 1760
13 490 1960
14 540 2160
15 590 2360
16 640 2560
17 690 2760
18 740 2960

As you may have noticed, there is a small mistake in the PCB design as that the LED and the resistor to the 39MF22 have been switched. This should not make any difference for the SSR version, but it may cause the Relay not to shut off. So if you are making the relay version, just switch the LED and the 330 Ohm (or adapted value) in position: The circuit is right, the PCB is wrong

ATtiny for your garden

This post is largely theoretical: Finished project here

Since I have a habit of being not home but still need my water gardened I was trying to find a way to do that. Of pourse there are the watering clocks like the Gardena or others that can be programmed to water the garden for a certain time ach day or each week and I have used thoes but the have two drawbacks:

They will water even if it is not necessary + I always feel a bit anxious to use those if I am away for a long time, just in case something goes wrong and the mains waterline will start spraying for days on end.

Therefore I decided to turn to a microcontroller. Ofcourse ‘Arduino’ pops to mind but that seemed a bit like overkill for a simple task, but it seemed like a good idea to develop a system on the Arduino an then transfer it to an ATtiny45.

The idea was to let the Arduino measure moisture in my plantbed and then depending on a preset value for moisture or dryness, switch on a pump.

As the ATtiny has several pins that could be used as an output or input, I was thinking to find a use for the other pins a swell and I found the perfect solution. As the watering function will probably only be used in the summertime, after planting, I could use the device earlier alrady for heating up a propagator. yes I know there are heated propagators but I just could not find one in my local gardenshops.

First a bit of theory:

spanningsdelerIn this figure, the voltage Va is a function of the Voltage Vcc and the two resistors R1 and R2. The Current I flowing through R2 and R1 is Vcc/(R1+R2) and therefore the voltage over R1 and thus the voltage Va=I x R1.

If we subsitute I then the formula will be (Vcc/(R1+R2))xR1= Vcc*R1/(R1+R2)=Va.

With a Vcc of 5 V and both resistors being 10 k, the voltage Va therefore will be 2.5 V.

If R2 would be replaced by a variable resistor such as an NTC or a humidity sensor, the voltage over Va will vary dpending on the value of the temperature or the humidity and that voltage Va will subsequently be read by an analog port on the Attiny.

The temperature sensor

NTCThe temperature sensor is quite easy. a 10 k NTC will do the trick. It will come in the place of R2 so with a rising temperature the voltage on Va will rise as well.

The value of an NTC (e.g. 10k)  is usually given at an ambient temperature of 25 degrees Celsius. Therefore, at 25C the voltage on Va should be 1/2 Vcc.
Initially I had the intention to calculate the temperature with the Steinhart-Hart formula but as I only needed two temperatures, one to switch on the heating and one to switch off the heating in the propagator, it made more sense to just measure the Va at these specific temperature as this also takes into account a variation in the Vcc, in the resistor R1 and in the resistance of the leads to the NTC.
I wanted to keep the temperature between 21 and 26 degrees and you will find my values for that in the program. The values that you will need might be different. Mind that the Analogue ports will give you a reading between 0 and 1023. The Arduino can map this with the map command, but it is just as useful to divide by 4. The function that does this is the function ‘sample’. It will take the average of 5 readings and then divide that (‘map it’) by four.

The humidity sensor

Build-Your-Moisture-SensorThe humidity sensor is basically not more than 2 spikes driven into the ground. The citcuit is similar to that of the temperature reader, with the spikes taking the place of the NTC. In my experience, soil that is just sufficiently humid gives a resitence (with my humidity resistor) of  about 10 k. Also here if the soil dries out, the resistence of the sensor will increase and the voltage on the analogue port will rise. A specific dryness or wetness of the soil therefore corresponds with a certain value on the analogue port.

Construction

The construction of a humidity sensor is quite simple although there seem to be various ‘schools’ of thought. Some people will embed their ‘spikes’ in plaster of paris to give a more even reading of moisture. Most people however will just take two metal spikes that are inserted in the earth. There are however two things to remember: the spikes need to be attached to eachother, otherwise putting them in another position may cause the distance between the two spiks to chanage and therefore also the resistance; the spikes need to be made of galvanized material will they stand any chance of surviving being in the soil. Galvanized nails are a popular material, but they ar ehard to solder. Th best way is to file or sand the place where one wants to solder the wire. Wrap the wire around the spike and solder and then to top it off, pit some shrink wrap around it to ensure a good contact between the wire and the spike.

Metal spikes in the soil. especially if they have a DC current going through them, may corrode very quickly. In practice that has not bothered me that much, but there are some things that one could do to prevent corrosion: only put tension to the pins when the device is actually read. In that case the humidity sensor should not be connected to +Vcc but to digital pin 0 that can be switched on right before the reading and switched off  right after it. Another thing one can do –but in our example we are a pin short- is not to connect the pin and its pull down resistor to + V and earth, but to two digital output pinds that then will feed it with an AC current bij alternating the polarity of the two digital pins and only to read it when the proper pin is high.

Also, avoid using copper. Copper seems to be pretty good in actually picking up voltages from the earth whcih may cause some weird effects when you are trying to read the resistance. You may get complte different readings if you reverse the connection to those copper spikes.

The program

The program is fairly simple. First it starts with some descriptions and gives the lay-out for the Attiny. It then defines the pins and sets the variables.
It then reads the humidity sensor with the ‘sample’ function and stores the result in the variable ‘moist’. It compares the value for ‘moist’ with the value that is set for ‘irrigation’. If it is lower or equal to that value, it switches on the pump by setting the ‘pumpPin’ high.
If it is a level of 5 above that value, iyt switches the pump off.
This is done to avoid the pump switching on and off repeatedly and to make the soil wet enough. Depending on the flow of water in your particular set up, you may want to alter that value of ‘5’.
It then reads the temperature, again with the ‘sample’ function and stores the result in the variable ‘ntc’. It then sees if this value is less than ‘142’ (which is 21 degrees in my case)  and if so, it switches on the heating in my propagator. It then compares the value with ‘155’(which is 26 degrees in my case) and if so, switches off the heating.
As a heater I have used a 40 W lamp that is switched via a solidstate relais.

So just to summarize: I use this device in summer outside to water my plantbeds and in  early spring I use it inside to heat a propagator. The device therefore is never controlling both temperature and irrigation at the same time, but if you would use it in a greenhouse, ofcourse it could.
Although the irrigation could be done by switching an electric valve in the main waterline, I have opted to use an immersible pump in a large bucket with water. As immersible pumps should not run dry, I have used a reed switch with a magnet on a floating device to cut the power to the pump if the water level is too low.

Protection

protect

I am not going to point out that if you are switching a pump or a lamp that you have to be careful with the mains voltage that can kill you. If you have no knowledge of these things you should not attempt to fiddle with it. But there is something else I need to point out: If the lines of the of your sensors to your ATtiny are long, they may pick up spikes that could be too high for the ports on your microcontroller and you may want to consider a bit of protection. This can be obtained by adding a 1 k resistor and a 5v1 zener as is shown in the picture. Obviously if you use that you need to recalibrate the values that are read from the sensor.

 /*February 2012 

Sensors:
-NTC  aan analoog  pin1
-Humidity spike aan analoog pin2
*--------------NTC-------------------------------
* Schematic:
*   [Ground] -- [10k-pad-resistor] -- | -- [NTC] --[Vcc]

*                                     |
*                                Analog Pin 3
*
*    Rntc=((Vcc * pad / Vpin1) - pad);
*   =((1024 * pad / RawADC) - pad);
*
*-------------------------------Humid------------------------------

* Schematic:
*   [Ground] -- [10k-pad-resistor] -- | -- [Spikes] --[Vcc]
*                                     |
*                                Analog Pin 2
*
If the humidity sensor gets too dry, the resistance goes up and the voltage on the analog pin goes down. As a result the pump relais is activated. The sensor measures ca 10 kOhm if the soil is moist enough. The reading therefore should be at 512 (with a pull down resistor of 10k).
* If the temperature goes down the resistance of the NTC goes up and therefore the voltage on the analogue port goes down and a relay can be switched (for heating or for ventilation). In my case the resistance should be between 12.5 and 10k Ohm (21-23 degrees Centigrade) the reading on the analogue port thus must be kept between 512 and 455.

ATTiny pins
Physical  Analoog  Digital
1           0          5   Reset, PinChange Interrupt
2           3          3   INT0,3
3           2          4   INT0,4
4           Ground
5                      0   INT0,0
6                      1   INT0,1
7           1          2   INT0,2
8           Vcc
*/
//Pin definitions
int ntcPin= 3; //analogue Pin3  ->Physical pin2
NTC int humidPin=2;//analogue Pin2  ->Physical pin3  Humidity spike
int pumpPin =2;//digital  Pin2  ->Physical pin7  Bevloeiingspomp
int warmPin=1;//digital  Pin1  ->Physical Pin6  Verwarming
int signalPin=0;//Digital  Pin0  ->Physical Pin5  Extra

// Variabelen setting
int moist=0; // maybe float is not necessary
int ntc=0;   // maybe float is not necessary
int ldr=0;   // maybe float is not necessary
int irrigate=512; // level for irrigation ca 126 after mapping

//The following function, "setup", must always be present
void setup() {//Serial.begin(9600);// for debugging only, remove for Attiny
pinMode(ntcPin,INPUT);// meet temperatuur
pinMode(humidPin,INPUT);// meet vochtigheid
pinMode(signalPin,OUTPUT);//Signaallamp oid
pinMode(warmPin,OUTPUT);//Output for heating element
pinMode(pumpPin,OUTPUT);//Output for Relais/waterpump
digitalWrite(pumpPin, LOW);
digitalWrite(warmPin, LOW);}

void loop() //This function must always be present
{
/* First we read the Humidity sensor. If the sensor is >10 k this is considered dry As the sensor is in a voltage divider of 10k the value read then will be 1/2 Vcc In analogue value this will be about 1/2 *1024=512 and after mapping it will be 127

So if the value read ('moist') is smaller than what is considered dry ('irrigate'), the pump should be switched on for a specific time. This is done by indicating a higher treshhold for switching the pump off

*/

moist=sample(humidPin);  //read humiditySensor
//This function samples 5 times and averages
// Serial.print("Value Read: ");
// Serial.println(moist);
if (moist <= irrigate) digitalWrite(pumpPin, HIGH);
if (moist >= irrigate+5) digitalWrite(pumpPin, LOW);

/* Now read the temperature sensor. If  the sensor is 10 k this is considered 26 degrees, the analogue reading will be 512 and 128 after mapping at a higher value the heating should be switched off
If the sensor is 12k5 this is considered 21 degrees, the analogue reading will be 455 and 113 after mapping this is the lower treshhold and the heating should be switched on
In real life however the values 142 and 155 corresponded better with those temperatures (apparently theory and practice do not always match)
*/

ntc=sample(ntcPin); // Serial.println(ntc);
if (ntc <= 142) digitalWrite(warmPin, HIGH);
if (ntc >= 155) digitalWrite(warmPin, LOW);} //end loop

// Sample Function
int sample(int z)
/* This function will read the Pin 'z' 5 times and take an average.Afterwards it will be mapped by dividing by 4 */

{
int 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 = 255 - sval;  // invert output
return sval;
}

Getting the code in the ATtiny

Now this may all be very well, but how to get the program in the ATtiny, as it has no bootloader? Well, there are several ways. One can use the Arduino IDE to generate the hexfile and then program that with either a parallelport programmer or a USBtiny programmer, or if one has an Arduino, the Arduino can be used as a programmer. Several websites have described this and I will refer to the procedure as explained by John Boxalin his blog.

In principle the method is as follows.

  • Connect the 6 pins between the Arduino and the ATtiny that make up the official in line programming header.
  • Add a specific ATtiny board file to yr IDE.
  • Load the Arduino with the ‘ArduinoISP’ sketch.
  • Then choose ‘ATtiny 85 (w/ Arduino as ISP)’ as your board.
  • Load the ‘Garden’ sketch and upload as usual.

Do I really need a microcontroller for this

Some people may wonder if perhaps even using an ATtiny for this is overkill? Well, ofcourse it is because what you are basically doing here is comparing two values. The value for a measured temperature (or humidity) with a set value and there are devices that have been used for doing exactly that for years already: Opamps, like the trusty 741:

opamp Obviously with this design it is harder to set a low and a high level (one can use two opamps for that) but that means it will keep the temperature (or humidity)  at a narrower level. For other possible op amp solutions see here and here

Using a microcontroller however has advantages over an op amp because it is easier to add functions (e.g. time) or look at things like ‘is the reservoir still full, won’t my pump run dry?’. With an op amp that means ‘extra parts’ (actually, that is not always necessary: Check here)