Are you pressing any button or you just let it run as is?
Your sketch won't compile for me. You declared 'watchdog' as a local variable in setup() and tried to use it in loop(). I had to move the declaration to above setup(). In the future, please post the latest WORKING version when you have made changes.
After fixing up your sketch (adding comments and more meaningful names) I don't see anything that is likely to cause a crash. I think your problem is likely power.
// Arduino replacement for Aerponics controller board
// Version 1.3.2
// Author timo121357 29.7.2019 with help from Arduino Forum
// Watchdog - Version: Latest
#include <Watchdog.h>
// Buttons of Aeroponics unit and corresponding Arduino IO pins
const byte ModeButtonPin = A0;
const byte PhaseButtonPin = A1;
const byte lightButtonPin = A2;
// LEDs of Aerponics unit and corresponding Arduino IO pins
const byte othersLEDPin = 3;
const byte flowersLEDPin = 4;
const byte herbsLEDPin = 5;
const byte vegetablesLEDPin = 2;
const byte ripeningLEDPin = 7;
const byte growingLEDPin = 8;
const byte seedingLEDPin = 6;
// Relay board and corresponding Arduino IO pins
const byte lightRelayPin = 9;
const byte pumpRelayPin = 10;
// Default states
enum Modes {Vegetables, Herbs, Flowers, Other};
byte mode = Vegetables;
enum Phases {Seeding, Growing, Ripening};
byte phase = Seeding;
byte lastModeButtonState = HIGH;
byte ModeButtonState = HIGH;
byte lastPhaseButtonState = HIGH;
byte PhaseButtonState = HIGH;
byte lastLightButtonState = HIGH;
byte lightButtonState = HIGH;
unsigned long pumpChanged = 0; // time when pump state last was changed
unsigned long lightChanged = 0; // time when light state last was changed
unsigned long currentMillis = 0; // current time
// light timers in hours: On, Off: Seeding, Growing, Ripening
unsigned long lightTimer[][6] =
{
{4, 20, 20, 4, 20, 4}, // mode 0: Vegetables
{4, 20, 20, 4, 20, 4}, // mode 1: Herbs
{4, 20, 20, 4, 20, 4}, // mode 2: Flowers
{4, 20, 20, 4, 20, 4} // mode 3: Others
};
// pump timers in seconds: On, Off: Seeding, Growing, Ripening
unsigned long pumpTimer[][6] =
{
{30, 30, 5, 240, 5, 480}, // mode 0: Vegetables
{30, 30, 5, 115, 3, 177}, // mode 1: Herbs
{30, 30, 5, 60, 3, 300}, // mode 2: Flowers
{60, 120, 60, 180, 60, 600} // mode 3: Others
};
Watchdog watchdog; // Watchdog declaration
void setup()
{
Serial.begin(9600); // initialize serial communications at 9600 bps
pinMode(ModeButtonPin, INPUT_PULLUP);
pinMode(PhaseButtonPin, INPUT_PULLUP);
pinMode(lightButtonPin, INPUT_PULLUP);
pinMode(vegetablesLEDPin, OUTPUT);
pinMode(herbsLEDPin, OUTPUT);
pinMode(flowersLEDPin, OUTPUT);
pinMode(othersLEDPin, OUTPUT);
pinMode(seedingLEDPin, OUTPUT);
pinMode(growingLEDPin, OUTPUT);
pinMode(ripeningLEDPin, OUTPUT);
digitalWrite(pumpRelayPin, HIGH);
pinMode(pumpRelayPin, OUTPUT);
digitalWrite(lightRelayPin, HIGH);
pinMode(lightRelayPin, OUTPUT);
watchdog.enable(Watchdog::TIMEOUT_2S);
}
void loop()
{
watchdog.reset();// Watchdog gets a bone
// store current time before timer controls start
currentMillis = millis();
readButtons(); // read input from buttons
// Set indicator LEDs:
// Mode LEDs
digitalWrite(vegetablesLEDPin, mode == Vegetables);
digitalWrite(herbsLEDPin, mode == Herbs);
digitalWrite(flowersLEDPin, mode == Flowers);
digitalWrite(othersLEDPin, mode == Other);
// Phase LEDs
digitalWrite(seedingLEDPin, phase == Seeding);
digitalWrite(growingLEDPin, phase == Growing);
digitalWrite(ripeningLEDPin, phase == Ripening);
// control light time
if (digitalRead(lightRelayPin) == HIGH)
{
// Light is ON
if ((currentMillis - lightChanged) >= 3600000UL * lightTimer[mode][phase * 2])
{
// Turn light off
digitalWrite(lightRelayPin, LOW); //turn light off after timer has expired
lightChanged = currentMillis;
}
}
else
{
// Light is OFF
if ((currentMillis - lightChanged) >= 3600000UL * lightTimer[mode][phase * 2 + 1])
{
// Turn light on
digitalWrite(lightRelayPin, HIGH); //turn light back on after timer has expired
lightChanged = currentMillis;
}
}
// control pump time
if (digitalRead(pumpRelayPin) == HIGH)
{
// Pump is ON
if ((currentMillis - pumpChanged) >= 1000UL * pumpTimer[mode][phase * 2])
{
// Turn pump off
digitalWrite(pumpRelayPin, LOW); //turn pump off after timer has expired
pumpChanged = currentMillis;
}
}
else
{
// Pump is OFF
if ((currentMillis - pumpChanged) >= 1000UL * pumpTimer[mode][phase * 2 + 1])
{
// Turn pump on
digitalWrite(pumpRelayPin, HIGH); //turn pump back on after timer has expired
pumpChanged = currentMillis;
}
}
}
void readButtons() // read input from buttons
{
static unsigned long lastButtonChangeTime = 0;
//left button
ModeButtonState = digitalRead(ModeButtonPin);
if (ModeButtonState != lastModeButtonState && (millis() - lastButtonChangeTime > 10))
{
lastButtonChangeTime = millis();
lastModeButtonState = ModeButtonState;
if (ModeButtonState == LOW)
{
if (++mode > Modes::Other)
mode = Modes::Vegetables; // update mode and roll over when 3 is exceeded
}
}
// middle button
PhaseButtonState = digitalRead(PhaseButtonPin);
if (PhaseButtonState != lastPhaseButtonState && (millis() - lastButtonChangeTime > 10))
{
lastButtonChangeTime = millis();
lastPhaseButtonState = PhaseButtonState;
if (PhaseButtonState == LOW)
{
if (++phase > Phases::Ripening)
phase = Phases::Seeding; // update phase and roll over when 2 is exceeded
}
}
// light button
lightButtonState = digitalRead(lightButtonPin);
if (lightButtonState != lastLightButtonState && (millis() - lastButtonChangeTime > 10))
{
lastButtonChangeTime = millis();
lastLightButtonState = lightButtonState;
if (lightButtonState == LOW)
{
digitalWrite(lightRelayPin, !digitalRead(lightRelayPin)); //toggle light
lightChanged = currentMillis;
}
}
}
Hello,
thanks again for all the support and help! I really did not expect anyone to be so kind as to rewrite my code, too. I was under the impression the version I posted was the working one, sorry for the inconvenience caused!
I removed the resistors feeding the LEDs on the original circuit board, cut off everything else than what was holding the LEDs in place and reattached the remaining parts with hot glue. Each LED is fed from a separate pin and they are all connected back to ground via a common 2k2Ohm resistor. Only two leds will ever be lit at the same time.
The buttons are connected with the original flat cable to A0, A1, A2 and GND on the Arduino UNO
Relay card is fed from the output pins 9 and 10, 5V and ground. The relay is triggered from the pins and powered from the 5V line. This is a potential cause of trouble?
Pictures of the device and the connections can be found here: https://photos.app.goo.gl/aWPWqXCp1WGzFY7n9
At the start I press the phase button to put the device in growing mode. After a watchdog reset it will go to seeding mode and I use that as a indicator for a crash.
Next test is with Johnwassers rewritten code.
thanks
It might help to add some debug messages and keep a PC connected. With the right messages you can tell if the crash is happening randomly or when either of the relays is being switched. If the problem happens when a relay is triggered, the problem is more likely to be a power glitch.
Each LED is fed from a separate pin and they are all connected back to ground via a common 2k2Ohm resistor
I'm not a hardware specialist but One Resistor seems calling for trouble (practically speaking, diodes don't have same characteristics - esp if different colors - and therefore there's a risk that one diode will start conducting and the other won't so you won't see your 2 lights.). Also seems it's a pretty high value - LEDs are probably not very bright?
Relay card is fed from the output pins 9 and 10, 5V and ground. The relay is triggered from the pins and powered from the 5V line. This is a potential cause of trouble?
Yes you might draw too much current and the voltage for you arduino board collapses (esp. if you power from USB) and your board reboots. You should power relay separately.
It has been a few days. I have now installed two separate power supplies to the system and am feeding the Arduino from one and the relay from the other. I also redid all wiring and positioned the relay as far away from the Arduino board as possible. Unfortunately the crashing continues.
Any suggestions what I should monitor in debug logs to find the root cause for the crashes?
Start every line with millis() as 8 hex digits with leading zeros or spaces.
Print enough to trace every branch taken and any critical values but keep everything short and use a high serial baud rate to make less load for the real code.
Don't end the line for every branch taken until you have a point you want saved then end the line, close the file to update the FAT and reopen the file to get the next line. SD will lose all data written since file open in a crash. You never get the crash, just what led up to it unless that's an external or hardware gotcha so don't fix code that you can't find the break in logic or other bug just to fix code.
PS you read the last X-many lines to see just before the crash. Crashes often occur when the stack and heap cross but not always right away, that's why to watch data as well as trace execution. The system log is a debug tool, the time stamps give you timing information to go with the trace and data.
I would physically remove the relay from the circuit and let it run.
If I does, I would try a different Arduino with same code and nothing hooked up to it except the single LED and resistor for grow mode indication. Manually ground the selector pin to put it in correct mode and let it run.
SOLVED!
After getting my code reviewed and rewritten the system still malfunctioned. I bought a second Arduino board and new relays, still same problem. After this I started suspecting the problem is neither the code nor the Arduino HW but has to be either the light or the pump. I disconnected the pump and the problem was gone.
The pump motor is a coil. A coil is a conservative electric component, it hates change. So when you switch the pump off, the coil wants to maintain the current it has had and increases voltage over it self to prevent the current from dying. Once the voltage becomes high enough it makes a spark where it is easiest for it to happen. The spark causes transients that Arduino can not take and hangs.
The solution to this problem is an RC Snubber, a resistor and a capacitor in parallel with the motor. I used 100 Ohm and 120 pF with 500 V rating. Problem solved. Now I have constant basil crops in my garage.
Timo
No protection diode on the induced load?
timo121357:
The solution to this problem is an RC Snubber, a resistor and a capacitor in parallel with the motor. I used 100 Ohm and 120 pF with 500 V rating. Problem solved. Now I have constant basil crops in my garage.
Read about Flyback diode (aka kickback diode, snubber diode, commutating diode, freewheeling diode, suppression diode, clamp diode, or catch diode)... your system as you have it is still at risk, an “inductive spark” can be way more than 500V
Thanks for the comments.
There is a diode across the relay coil already, but it has no effect on the pump coil as the pump coil is on the switched side of the relay. The pump motor is 230VAC, no diode can be connected across it. The RC snubber circuit is the right solution.
The capacitor in the RC circuit only gets a fraction of the voltage across it, as it is connected in series with a resistor that takes most of the voltage. 500V has worked fine so far.
Weird - if it’s a consumer 230VAC pump it should have its embedded protection and so a correctly sized power relay should be fine - same as if you were plugging or unplugging the pump.