Jump to content

A Smart(ish) Pond Level Controller - Arduino based


Crossy

Recommended Posts

I know, the first question is "What the Flip is an Arduino?". Arduino is a family of open-hardware micro-controllers beloved by the hobby-robot community.

 

They live here https://www.arduino.cc/

 

We will be using an Arduino "Uno", which is one of the entry-level units, it looks like this (actually this is a Chinese clone, more of that in a minute).

 

20171119_174412.jpg

 

As you can see he's pretty small, he's also very low power consumption and (most importantly) very low cost. The unit in the photo cost a whole $2.90 (with free shipping), no that's not a typo https://www.aliexpress.com/item/Free-shipping-UNO-R3-MEGA328P-with-usb-cable-for-Arduino-Compatible-Dropshipping/32241225914.html it also arrived only 7 days after ordering!

 

Anyway, enough of the "what" how about the "why"?

 

The Problem

We have a koi pond, it leaks somewhat (about 2cm per day), it also has a vertical "aeration" thingy, which, if the level gets a bit low looks like this:-

 

world-cup-fountain2.jpg?imgmax=1600

 

Pond water comes from the river via our irrigation pump and a filter. Topping up the level means opening the fill valve and starting the pump, a manual task often "forgotten" particularly when it is raining.

 

Enter the need for something automatic.

 

The level needs to be quite tightly controlled (+- about 1") so a float valve wasn't going to cut it (and the irrigation pump doesn't have a flow switch anyway). I bought a couple of reed float switches:-

 

20171119_111433.jpg

 

Great, trouble is they tend to bob up and down when the fish feed (more like great-whites than koi) driving the relay and pump control mad. We also added a motorised valve to control the flow to the pond when garden watering (using the same pump) was occurring, this needs about 1.5 seconds to go from closed to open meaning a timer of some sort was required.

 

I tried designing something using 555 timers and relays, but the requirements got a bit beyond the "simple" solution. Actually, I spent more time than I care to admit trying to get something working properly. Considering that I got the prototype Arduino based controller built and working in a morning there's a considerable (in theory at least) time/cost saving too.

 

Enter the Arduino idea.

 

The Requirements.

 

Inputs.

Pond level (from the reed switches)

Tank low (from the water tank float) so we don't run the pump dry

 

Outputs.

Pump on

Valve open (and close)

 

Constraints.

Level switches must be constant low-level for (insert time period) before the pump and valve operate.

Once level is satisfied then the pump must over-run for (insert time period) to ensure that the level really is ok.

 

I think you can see why my idea of 555 timers and a few relays got "a bit out of hand".

 

Before you decide that it already sounds too complicated this is the completed controller, it really is simple.

 

20171119_095101.jpg

 

To be continued.

 

Link to comment
Share on other sites

9 hours ago, maxpower said:

What have you used to shield inputs, cant get a decent zoom on the photo.

Beware of holes in your enclosure, ants and bugs will enjoy making adjustments.

Yeah, with a cable run of about 50m to the tank sensor and 4m to the float switches keeping electrical nasties out of the sensitive bits is vital.

 

All will be revealed once I've drawn it all up, for now suffice to say that inputs are opto-isolated (the bit of strip-board on the left). There are few 1N4007 diodes around, actually a legacy from the relay based (non)solution, they can't hurt although I doubt they really achieve much.

 

My usual bug-discouragement (a couple of moth balls) is already installed.

 

Link to comment
Share on other sites

Nice project there Crossy.
Funny I was looking at these last week with the thought of making up a house heat sensor display, bought on by Sheryl's house roof removal and insulation upgrade.
Maybe you can beat me to it, as your brain still works.

Sent from my SM-J700F using Tapatalk

Link to comment
Share on other sites

1 hour ago, carlyai said:

Funny I was looking at these last week with the thought of making up a house heat sensor display, bought on by Sheryl's house roof removal and insulation upgrade.
Maybe you can beat me to it, as your brain still works.

Go for it Carl.

 

The nice thing about these chaps is there are literally thousands of ready made add on modules available for a few bucks. Most actually cost less than the sum of the parts, add on the time needed to design and make a board it's really a no-brainer.

 

Also don't worry about writing code. Arduino is programmed in C and there are masses of libraries and examples for you to use as a basis along with several very active forums for when you get stuck.

 

It's many years since I wrote any code (and it wasn't C anyway) but I got the lash-up working very quickly.

 

Anyway, I bought:-

 

I already had in stock:-

  • 12V 1A power supply
  • 12V 4-pole change-over Omron relay
  • 4-pin opto-coupler
  • 2.2k 1/4W resistor
  • Bit of strip board.
  • IP65 (yeah, sure it is) box with a clear door.

 

USB lead to connect the Arduino to my PC.

 

Assorted wire, connectors etc.

 

Drawings and code coming soon.

 

EDIT I actually bought three Arduino boards and one of these https://www.aliexpress.com/item/ProtoShield-prototype-expansion-board-with-mini-bread-plate-based/726121913.html the original idea being to build the interface on it, but the interface turned out to be so simple (two components) that I built it on a scrap of Veroboard. 

 

EDIT 2 Carl, how about this temperature sensor for $0.70 https://www.aliexpress.com/item/Smart-Electronics-KEYES-KY-001-3pin-DS18B20-Temperature-Measurement-Sensor-Module-for-Arduino-Diy-Starter-Kit/32572003499.html data sheet for the DS18B20 device here  https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf a dead clever little beast, does all the hard work for you.

Link to comment
Share on other sites

Wow!  My solution would be a spotlight, two switches and  beer!

 

1.  Point the spotlight toward the pond that is visible from a window in your house.

2.  Turn the spotlight on with a switch mounted on the wall next to the window.

3.  If the pond is low, turn on the pump with the switch mounted on the wall next to the window.

4.  Have a beer or two while the pond is filling.

5.  When the pond is full turn off the pump.

6.  Turn off the spot light.

7.  Have another beer.

8.  Repeat the process every time you get thirsty, the pond will never get too low!

Link to comment
Share on other sites

I'm thinking I would use a toilet cistern float.

 

But if one wants to be hi tech. Three steel rods in a blue plastic tube, , a 12v power supply  and two? relays. 

One rod is "ground/common",  one rod is high , one rod is low. Pump switches on when lower rod is uncovered and switches off when the top rod is covered.

 

All-in-one? $ 9.00

http://realezshop.com/products/df96d-ac220v-5a-din-rail-mount-float-switch-auto-water-level-controller-with-3-probes/

 

UT8YtiXXI8aXXagOFbXw.jpg

 

Make your own rods and housing. The housing is to reduce waves caused by your whales!

 

 

 

Edited by VocalNeal
Link to comment
Share on other sites

1 hour ago, VocalNeal said:

I'm thinking I would use a toilet cistern float.

 

But if one wants to be hi tech. Three steel rods in a blue plastic tube, , a 12v power supply  and two? relays. 

One rod is "ground/common",  one rod is high , one rod is low. Pump switches on when lower rod is uncovered and switches off when the top rod is covered.

 

All-in-one? $ 9.00

http://realezshop.com/products/df96d-ac220v-5a-din-rail-mount-float-switch-auto-water-level-controller-with-3-probes/

 

UT8YtiXXI8aXXagOFbXw.jpg

 

Make your own rods and housing. The housing is to reduce waves caused by your whales!

 

 

 

Grabbing a few relays and a 12 volt supply could become an electrolytic nightmare. Electronic probe controllers work fine in ideal conditions but can quickly become unreliable in contaminated liquids.

 

Programmable automation allows one to quickly apply logic to problems like false switching etc.

Link to comment
Share on other sites

Wow!  My solution would be a spotlight, two switches and  beer!
 
1.  Point the spotlight toward the pond that is visible from a window in your house.
2.  Turn the spotlight on with a switch mounted on the wall next to the window.
3.  If the pond is low, turn on the pump with the switch mounted on the wall next to the window.
4.  Have a beer or two while the pond is filling.
5.  When the pond is full turn off the pump.
6.  Turn off the spot light.
7.  Have another beer.
8.  Repeat the process every time you get thirsty, the pond will never get too low!
Thats antiquated automation. Don't you know that you must wait till 6 pm for your first beer?

Sent from my SM-J700F using Tapatalk

Link to comment
Share on other sites

14 minutes ago, carlyai said:

Thats antiquated automation. Don't you know that you must wait till 6 pm for your first beer?

It's 6 pm somewhere in the world! 

 

And in addition, if his wife complains that he is drinking too much beer he can always say that he is just following the instructions for maintaining HER Koi pond.  I would recommend that he be wearing full body armor at the time!

 

It's easy to give advice like this when you live alone with only 7 dogs to answer to!

Link to comment
Share on other sites

Toilet float valve is out as the irrigation pump doesn't have a flow / pressure switch.

 

I've not had a lot of joy with conductive probe sensors either, and it's a fish pond with lots of growing plants, algae etc. Plus, I know the currents will be very small, but I'm not sure how the fish will react.

 

It's going to take a while longer for the drawings, I have to create some library models, at least things will be faster once they're done.

 

Link to comment
Share on other sites

38 minutes ago, Crossy said:

I've not had a lot of joy with conductive probe sensors either, and it's a fish pond with lots of growing plants, algae etc

 

I didn't believe it either when I found one one day in a old pulp mill with a stainless nut hanging on a piece of wire. But yes I suppose some algae could attach itself to the low level one and increase the level difference. The 1' level difference requirement is quite small. But one would notice that and give the probes a wipe as part of general maintenance so should be installed with some slack in the wiring.

 

The current doesn't flow in the pond as such just across the rods which will only be a few centimeters apart if worried one could use a stainless tube as the stilling well and make that negative then there would be no current outside the system. I notice though that some Koi carp systems use exposed electrodes.

 

Capacitance or ultrasonic/radar are a bit more expensive. I suppose one could use some float switches but needs a lot of tweaking during set up and even they would be susceptible to algae/weed. Just using the old KISS principle.

 

Link to comment
Share on other sites

Quick and dirty diagram.

 

Pond-1.jpg

 

Note the pond fills via the bio-filter, so the circulation pump needs to be off whilst filling to avoid overflow.

 

Pond Level and Tank Level switches are both closed to fill the pond.

 

 

Link to comment
Share on other sites

And version 1 of the code that makes it work, not the best or most efficient code, but I'm no programmer.

 

But, it does actually work and control the pond level.

 


/*
  Fishpond level controller for Arduino Uno 
  V1.0
  By Dave Cross  November 2017
*/

// Constants won't change.
const int ledPin =  LED_BUILTIN;                          // the number of the LED pin (actually pin 13)
const int Valve = 8;                                      // drive pin for valve relay
const int Pump = 9;                                       // drive pin for pump relay
const int Sensor = 12;                                    // input pin from level sensor
const unsigned int ondelay = 60;                         // time the sensor must be active before the pump starts, 1/10 seconds (100=10 seconds) max 6553 seconds
const unsigned int offdelay = 300;                       // time to run the pump after sensor indicates full, 1/10 seconds (100=10 seconds) max 6553 seconds

// Variables will change:
int PumpStart = 0;                                        // indicates whether the pump should be running or not

void setup()
// stuff that runs once
{
  // set the digital pins as output:
  pinMode(ledPin, OUTPUT);
  pinMode(Valve, OUTPUT);
  pinMode(Pump, OUTPUT);
  // set the digital pins as input:
  pinMode(Sensor, INPUT);
  digitalWrite(Sensor, HIGH);                                     //enable the internal pullup resistor
  // make sure the pump is stopped
  digitalWrite(Valve, HIGH);
  digitalWrite(Pump, HIGH);
}

void loop()
{
  // code that needs to be running all the time.


  // make sure the sensor is active for ondelay
  if (digitalRead(Sensor) == LOW )                                // low is float switch ready to fill
  {
    for (unsigned int i = 0; i <= ondelay; i++)                   // timer loop to debounce the float switch when it bobs on the water
    {
      delay (100);
      digitalWrite(ledPin, !digitalRead(Sensor));                 // update the LED
      if (digitalRead(Sensor) == HIGH)                            // reset the timer if the sensor goes high
      {
        PumpStart = 0;                                            // ensure the pump isn't going to run                                      
        break;
      }
      PumpStart = 1;                                              // set the pump to run
    }
  }

  if (digitalRead(Sensor) == HIGH)                                // high is float switch full
  {
    PumpStart = 0;                                                // set the pump to stop
  }

  //control the pump
  //start
  if (PumpStart == 1)
  {
    digitalWrite(Valve, LOW);                                     //open the valve. low energises the relay
    delay (1000);                                                 //delay for the motorised valve to open
    digitalWrite(Pump, LOW);                                      //start the pump
  }

  //stop
  if (PumpStart == 0)
  {
    for (unsigned int i = 0; i <= offdelay; i++)                  // delay before the pump stops, ensures it's not on/off continually
    {
      delay (100);
      digitalWrite(ledPin, !digitalRead(Sensor));                 // update the LED
      if (digitalRead(Sensor) == LOW)                             // reset the off timer if the level goes low
      {
        PumpStart = 1;                                            
        break;
      }
    }
    if (PumpStart == 0)                                           // check we really want the pump off
    {
      digitalWrite(Valve, HIGH);                                  //close the valve
      digitalWrite(Pump, HIGH);                                   //stop the pump
    }
  }
}

 

Link to comment
Share on other sites

4 hours ago, Crossy said:

And version 1 of the code that makes it work, not the best or most efficient code, but I'm no programmer.

 

But, it does actually work and control the pond level.

 

Good job getting all this to work.

This routine can be written several ways but it really does not matter for this simple job.

 

Hint if you are writing the version 2. Look at the IF ELSE structure.

 

Edited by maxpower
Link to comment
Share on other sites

... and then there was a problem ...

 

After running happily for a few days things went awry and the pump failed to start on low water level, grrr.

 

Bridging the level switch with a link resulted in ... nothing!

 

Pressing the reset switch returned normal operation. Checking the code revealed no infinite loops or the like, but something had caused things to lock-up.

 

A quick and dirty solution would be a simple bit of electronics (based on a 555 timer) to "press" reset if the code stopped running (it's called a watchdog). A bit of Googling revealed a better solution, the Arduino has a built-in watchdog. All one has to do is set a time-out period (16ms to 8 seconds) and insert a line into the code to feed him on a regular basis. If the code stops running, he doesn't get fed and presses the reset button restoring normal operation.

 

Enter version 2 of the code, it's got a few other tweeks inserted after some reading on better ways to do stuff. The whole lot runs to a massive 1,422 bytes, the Arduino Uno has 32,256 bytes of program storage available.

 

Version 2 with the watchdog enabled.

 


/*
  Fishpond level controller for Arduino Uno 
  V2.0
  By Dave Cross  November 2017

  Watchdog configuration by Nicholas Larsen - Thanks :)
*/

#include <avr/wdt.h> 

// Constants won't change.
const int ledPin =  LED_BUILTIN;                          // the number of the LED pin (actually pin 13)
const int Valve = 8;                                      // drive pin for valve relay
const int Pump = 9;                                       // drive pin for pump relay
const int Sensor = 12;                                    // input pin from level sensor
const unsigned int ondelay = 120;                         // time the sensor must be active before the pump starts, 1/10 seconds (100=10 seconds) max 6553 seconds
const unsigned int offdelay = 600;                       // time to run the pump after sensor indicates full, 1/10 seconds (100=10 seconds) max 6553 seconds

// Variables will change:
int PumpStart = 0;                                        // indicates whether the pump should be running or not

void setup()
// stuff that runs once
{
  // set the digital pins as output:
  pinMode(ledPin, OUTPUT);
  pinMode(Valve, OUTPUT);
  pinMode(Pump, OUTPUT);
  // set the digital pins as input:
  pinMode(Sensor, INPUT);
  digitalWrite(Sensor, HIGH);                                     //enable the internal pullup resistor
  // make sure the pump is stopped
  digitalWrite(Valve, HIGH);
  digitalWrite(Pump, HIGH);
  
  watchdogSetup();                                                // set up the watchdog 
}

void watchdogSetup(void) 
  { 
    cli();            // disable all interrupts 
    wdt_reset();      // reset the WDT timer 
    /*   
    WDTCSR configuration:   
    WDIE  = 0: Interrupt Disable   
    WDE   = 1 :Reset Enable   
    WDP3 = 1 :For 8000ms Time-out   
    WDP2 = 0 :For 8000ms Time-out   
    WDP1 = 0 :For 8000ms Time-out   
    WDP0 = 1 :For 8000ms Time-out 
    */ 
    // Enter Watchdog Configuration mode: 
    WDTCSR |= (1<<WDCE) | (1<<WDE); 
    // Set Watchdog settings: 
    WDTCSR = (0<<WDIE) | (1<<WDE) | (1<<WDP3)  | (0<<WDP2) | (0<<WDP1)  | (1<<WDP0); 
    sei();            // enable all interrupts 
    } 

void loop()
{
  // code that needs to be running all the time.

    digitalWrite(ledPin, !digitalRead(Sensor));                   // update the LED
    wdt_reset();                                                  // feed the watchdog

  // make sure the sensor is active for ondelay
  if (digitalRead(Sensor) == LOW )                                // low is float switch ready to fill
  {
    for (unsigned int i = 0; i <= ondelay; i++)                   // timer loop to debounce the float switch when it bobs on the water
    {
      delay (100);
      digitalWrite(ledPin, !digitalRead(Sensor));                 // update the LED
      wdt_reset();                                                // feed the watchdog
      if (digitalRead(Sensor) == HIGH)                            // reset the timer if the sensor goes high
      {
        PumpStart = 0;                                            // ensure the pump isn't going to run                                      
        break;
      }
      PumpStart = 1;                                              // set the pump to run
    }
  }

  if (digitalRead(Sensor) == HIGH)                                // high is float switch full
  {
    PumpStart = 0;                                                // set the pump to stop
  }

  //control the pump
  //start
  if (PumpStart == 1)
  {
    digitalWrite(Valve, LOW);                                     //open the valve. low energises the relay
    delay (1500);                                                 //delay for the motorised valve to open
    digitalWrite(Pump, LOW);                                      //start the pump
  }

  //stop
  if (PumpStart == 0)
  {
    for (unsigned int i = 0; i <= offdelay; i++)                  // delay before the pump stops, ensures it's not on/off continually
    {
      delay (100);
      digitalWrite(ledPin, !digitalRead(Sensor));                 // update the LED
      wdt_reset();                                                // feed the watchdog
      if (digitalRead(Sensor) == LOW)                             // reset the off timer if the level goes low
      {
        PumpStart = 1;                                            
        break;
      }
    }
    if (PumpStart == 0)                                           // check we really want the pump off
    {
      digitalWrite(Valve, HIGH);                                  //close the valve
      digitalWrite(Pump, HIGH);                                   //stop the pump
    }
  }
}

The observant will note that the

"wdt_reset();                                                  // feed the watchdog"

line occurs in several places, this is because, even with the timeout set to 8 seconds "Fang" was waking up occasionally and resetting the Arduino. Some parts of the code were taking more than 8 seconds to run. Dropping a reset in each time I updated the LED (which indicates the status of the level switch) solved the issue, not elegant, but effective (I told you I wasn't a programmer).

 

It's now been running for a week or so with no issues ... yet.

 

 

Link to comment
Share on other sites

Onwards and upwards ...

 

Whilst I do subscribe to the motto "If it 'anit f****d don't fix it" I do want to make some improvements.

 

Using the "delay" function isn't very elegant and it pauses the whole code from running, so something needs to be done there and some restructuring is needed to make better use of functions.

 

My whole purpose in starting this thread was to show that even a pleb like me with almost no programming experience (at least nothing recent) can get something working using one of these little beasts in almost no time and at very little cost. There are millions of problems out there waiting for your solution :smile:

Link to comment
Share on other sites

Good job getting all this to work.
This routine can be written several ways but it really does not matter for this simple job.
 
Hint if you are writing the version 2. Look at the IF ELSE structure.
 
I can't remember that much, but have you checked all your open and closed brackets? Seems like some places 4 opened and 3 closed, maybe picked the last one up at the end.

Sent from my SM-J700F using Tapatalk

Link to comment
Share on other sites

31 minutes ago, carlyai said:

I can't remember that much, but have you checked all your open and closed brackets? Seems like some places 4 opened and 3 closed, maybe picked the last one up at the end.

The compiler objects to mismatched brackets so the code that's running is fine, it's possible the last closing one got chopped when I copied the code for the post.

Link to comment
Share on other sites

2 hours ago, Crossy said:

The compiler objects to mismatched brackets so the code that's running is fine, it's possible the last closing one got chopped when I copied the code for the post.

I gave the IF ELSE hint to help improve future code not to look for errors in your existing code.

 

The watchdog is fixing your problem but you really should try and find the source of your crashes. Dont rule out noise and spikes from external components. They are rarely consistent.

Link to comment
Share on other sites

46 minutes ago, maxpower said:

The watchdog is fixing your problem but you really should try and find the source of your crashes. Dont rule out noise and spikes from external components. They are rarely consistent.

Yeah, it is likely power disturbances or lightning induced stuff. The prototype (which doesn't have great long leads attached and has watchdog disabled) has happily been running for ages without a crash.

 

If I get the enthusiasm I'll stick in an EEPROM store (which is non-volatile over a reboot) of how often "Fang" gets triggered, could possibly correlate with thunder activity.

 

Link to comment
Share on other sites

I just had a look at some blogs and projects on the controllers' web site. Lots of great projects and someone is making a project for whole house heat sensors, but using the RF modules and wifi.
They did mention that the controller is fairly unstable at 3.3V, due to power supply ripple, and added some bypass capacitors on the supply line.

I'm not sure if this could be a factor with your setup.

Sent from my SM-J700F using Tapatalk

Link to comment
Share on other sites

  • 3 weeks later...

Just about to fly out for Chrissy, so while in Banggers visited one of my favourite places Baan Mo.
There is a shop that just seems to cater for the microprocessor in this project.
All sorts of sensors, boards, add ons, etc.
I've attached a pic of their card details. .20171219_083733.jpg20171219_083611.jpg

Sent from my SM-J700F using Tapatalk

Link to comment
Share on other sites

  • 2 weeks later...

Well, whilst the controller has been running fairly well it's still been suffering from the occasional "lock-up" despite the watchdog.

 

I added a couple of "heartbeat" LEDs to give me an idea where it was going, it was getting in a loop which included a watchdog reset which explains why the dog didn't wake up.

 

Anyway, boredom over the long break spurred me on to re-write the code, it's now got indicator LEDs to show where it's at and an LCD to do similar stuff. Code structure is better, but not perfect by any means.

 


/*
  Fishpond level controller for Arduino Uno 
  V2.0
  By Dave Cross  November 2017

  Watchdog configuration by Nicholas Larsen - Thanks :)
  LCD code from Sunfounder
*/

#include <avr/wdt.h> 
#include <EEPROM.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// Constants won't change.
const int ledPin =  LED_BUILTIN;                          // the number of the LED pin (actually pin 13)
const int Valve = 8;                                      // drive pin for valve relay
const int Pump = 9;                                       // drive pin for pump relay
const int HeartbeatGreen = 3;                                 // drive pin for heartbeat LED
const int HeartbeatYellow = 5;                                 // drive pin for heartbeat LED
const int HeartbeatRed = 7;                                 // drive pin for heartbeat LED
const int Sensor = 12;                                    // input pin from level sensor

const unsigned int ondelay = 150;                         // time the sensor must be active before the pump starts, 1/10 seconds (100=10 seconds) max 6553 seconds
const unsigned int offdelay = 1200;                       // time to run the pump after sensor indicates full, 1/10 seconds (100=10 seconds) max 6553 seconds

// Variables will change:
int PumpStart = 0;                                        // indicates whether the pump should be running or not
int addr=0;
int val=0;
int dogtimes=0;

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup()
// stuff that runs once
{
  // set the digital pins as output:
  pinMode(ledPin, OUTPUT);
  pinMode(Valve, OUTPUT);
  pinMode(Pump, OUTPUT);
  pinMode(HeartbeatGreen, OUTPUT);
  pinMode(HeartbeatYellow, OUTPUT);
  pinMode(HeartbeatRed, OUTPUT);
  // set the digital pins as input:
  pinMode(Sensor, INPUT_PULLUP);                        //enable the internal pullup resistor                                 
  // make sure the pump is stopped
  digitalWrite(Valve, HIGH);
  digitalWrite(Pump, HIGH);
  lcd.init();  //initialize the lcd
  lcd.backlight();  //open the backlight 
  
  watchdogSetup();                                                // set up the watchdog 
}

//===================================================================================
//====== Set up the watchdog               ==========================================
//===================================================================================

void watchdogSetup(void) 
  { 
    cli();            // disable all interrupts 
    wdt_reset();      // reset the WDT timer 
    /*   
    WDTCSR configuration:   
    WDIE = 1 : Interrupt Disable   
    WDE  = 1 :Reset Enable   
    WDP3 = 1 :For 8000ms Time-out   
    WDP2 = 0 :For 8000ms Time-out   
    WDP1 = 0 :For 8000ms Time-out   
    WDP0 = 1 :For 8000ms Time-out 
    */ 
    // Enter Watchdog Configuration mode: 
    WDTCSR |= (1<<WDCE) | (1<<WDE); 
    // Set Watchdog settings: 
    WDTCSR = (1<<WDIE) | (1<<WDE) | (1<<WDP3)  | (0<<WDP2) | (0<<WDP1)  | (1<<WDP0); 
    sei();            // enable all interrupts 
    } 
    
//===================================================================================
//====== Start The Pump                    ==========================================
//===================================================================================
  void PumpRun()                                                // function to start the pump
  // make sure the sensor is active for ondelay
  {
    for (unsigned int i = 0; i <= ondelay; i++)                   // timer loop to debounce the float switch when it bobs on the water, loop time is about 100ms
    {
      delay (55);
      digitalWrite(ledPin, !digitalRead(Sensor));                 // update the LED
    digitalWrite(HeartbeatYellow, HIGH);                                // heartbeat LED on
    wdt_reset();                                                  // feed the watchdog
    delay (20);
    digitalWrite(HeartbeatYellow, LOW);                                // heartbeat LED off
    lcd.setCursor(0,1);                                         //set the cursor to column 0, line 1 
    lcd.print("Start Delay ");                                        
    lcd.print(i);                                        // Print a message to the LCD.
    lcd.print("    ");
 
      if (digitalRead(Sensor) == HIGH)                            // exit the function if the sensor goes high (abort the timer)
      {                     
      return;
      }
    }                        
        digitalWrite(Valve, LOW);                                     //open the valve. low energises the relay
        delay (1500);                                                 //delay for the motorised valve to open
        digitalWrite(Pump, LOW);                                      //start the pump                                                  
  } 
  
//===================================================================================
//====== Stop The Pump                     ==========================================
//=================================================================================== 
  void PumpStop()                                                    // function to stop the pump
  {
    for (unsigned int i = 0; i <= offdelay; i++)                  // delay before the pump stops, ensures it's not on/off continually, loop time is about 100ms
    {
      delay (55);
      digitalWrite(ledPin, !digitalRead(Sensor));                 // update the LED
    digitalWrite(HeartbeatRed, HIGH);                                // heartbeat LED on
    wdt_reset();                                                  // feed the watchdog
    delay (20);
    digitalWrite(HeartbeatRed, LOW);                                // heartbeat LED off
    lcd.setCursor(0,1);                                         //set the cursor to column 0, line 1 
    lcd.print("Stop Delay ");                                        
    lcd.print(i);                                        // Print a message to the LCD.
    lcd.print("    ");
      if (digitalRead(Sensor) == LOW)                             // exit the function if the level goes low (abort the timer)
      {                                    
        return;
      }
    }
      digitalWrite(Valve, HIGH);                                  //close the valve
      digitalWrite(Pump, HIGH);                                   //stop the pump  
  }

//===================================================================================
//====== Here's the bit that does the work ==========================================
//===================================================================================

void loop()
{
    digitalWrite(ledPin, !digitalRead(Sensor));                   // update the LED
    digitalWrite(HeartbeatGreen, HIGH);                           // heartbeat LED on
    wdt_reset();                                                  // feed the watchdog
    delay (20);
    digitalWrite(HeartbeatGreen, LOW);                            // heartbeat LED off

    dogtimes = EEPROM.read(addr);                               // get the current watchdog count
    lcd.setCursor(8,0);                                         // set the cursor to column 0, line 0
    lcd.print("WDog ");                                        // Print a message to the LCD.
    lcd.print(dogtimes);  
      if (digitalRead(Pump) == LOW)
      {
      lcd.setCursor(0,0);
      lcd.print("Run  "); 
      }
      if (digitalRead(Pump) == HIGH)
      {
      lcd.setCursor(0,0);
      lcd.print("Stop "); 
      }
      lcd.setCursor(0,1);
      lcd.print("                ");  
          
      if (digitalRead(Sensor) == HIGH )                             // High is level OK
      {
        PumpStart = 0;                                              // Set the pump to stop
      }

      if (digitalRead(Sensor) == LOW )                             // Low is level low
      {
        PumpStart = 1;                                              // Set the pump to run
      }

// Check pump status against required status
      if (digitalRead(Pump) == LOW && PumpStart == 0 )                                // If Pump is running and pump needs to be stopped        
        {
        PumpStop();                                                                             // Stop the pump
        }      
      if (digitalRead(Pump) == HIGH && PumpStart == 1 )                                // If Pump is stoped and pump needs to be started        
        {
        PumpRun();                                                                             // Start the pump
        }
}

//===================================================================================
//====== Watchdog timer interrupt.         ==========================================
//===================================================================================
   
    ISR(WDT_vect) // Watchdog timer interrupt. 
      { 
      // Include your code here - be careful not to use functions they may cause the interrupt to hang and 
      // prevent a reset. 
      val=EEPROM.read(addr);
      val ++;
      EEPROM.write(addr, val);
      }

 

Link to comment
Share on other sites

Another thing that popped up when I was testing with the LCD was that the supply voltage to the logic (5V DC) seemed to be decreasing (the LCD contrast went to pot after about 90 seconds of the relays being activated), a burnt finger from the 5V regulator explained why. The 100mA drawn by the relays was just a bit much for the on-board regulator hence the addition of the external LM7805 to supply the relays.

 

Pond Controller V2.jpg

 

Also, I discovered that the watchdog would either reset the Arduino OR run the interrupt routine but not both. Since I really wanted both in order to keep track of how many times Fang had been awakened I modified the interrupt routine thus.

 

The last line is pretty close to a hardware reset (but not quite), good enough for us I think.

 

//===================================================================================
//====== Watchdog timer interrupt.         ==========================================
//===================================================================================
   
    ISR(WDT_vect) // Watchdog timer interrupt. 
      { 
      val=EEPROM.read(addr);      // Read current value, increment and write back 
      val ++;
      EEPROM.write(addr, val);
      asm volatile ("  jmp 0");   // Execute from address 00 (equivalent to a reset)
      }

Since doing this over the long weekend things have been working well and Fang has not awakened once, yet ...

 

 

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.









×
×
  • Create New...