Stuck or some kind of crash

That's exactly how you use it. You need to "pat" (reset) the watchdog timer regularly in the main loop of your code. Then, if your code crashes, the watchdog timer times out and issues a CPU reset.

Yes, of course it is. But the watchdog timer is a pragmatic response to the realities of life: it's usually difficult or impossible to guarantee that your code is totally bug-free, and your hardware is totally immune to random spikes or other external influences.

You always need to work on making your software (and hardware) better, but acknowledging that it may never be perfect, the watchdog provides a second line of defence in systems where crash recovery and continued service is important.

As an aid to fault-finding, you might want to save various bits of diagnostic information when a watchdog reset occurs, to help identify the problem. It might even be as simple as a timestamp from a real-time chip (RTC), so you can see how often it happens and if it's associated with a particular time of day.

On the last such system I built, I added an SD card reader and stored the crash reports on that. Then I could just pop out one SD card an pop in another, without having to connect to the system with a PC.

+1.

And no one who can’t stay awake reading this article

should use a watchdog and think they are getting better sleep at night for having taken care of anything.

a7

By the way, it's tempting, but wrong, to issue your watchdog "pats" in an interrupt-service routine which is triggered by a hardware timer-based interrupt.

It's tempting because it seems easier: you don't have to worry about where to put the watchdog resets in your main code, and whether you've got enough of them to never end up with an unwanted watchdog timeout while you are doing something legitimate, such as waiting for an external event to happen. In a timer-initiated ISR you are guaranteed to reset the watchdog timer regularly, even if your code is busy doing its legitimate job.

And that's the reason it's wrong; it's very common for a crashed CPU to end up executing a tight loop somewhere, or sitting in a dark, untested corner of your code waiting for an event that will never happen (or happened before you got there). In these circumstances the timer-initiated interrupt will continue to be serviced correctly. In other words, when the interrupt comes along the CPU will jump out of its crash to pat the watchdog, and then return back into the crash. Hence your watchdog doesn't do its job.

Usually all you need is one watchdog reset in your loop() function, at the outermost level. It's good practice to rotate through your loop() function quickly, using millis() and micros() timestamps rather than delay() when it's necessary to do things at intervals or wait for a set period.

Hey, that's a great article! Wakeful or not, I recommend everyone read it. Out of interest, the last system I used a WDT on, I used an external one connected to the reset pin. Connected between the 0V and 5V rails I had a permanently-connected capacitor and resistor in series, with their junction connected to a spare input port. The capacitor took three seconds after applying power to charge up enough to look like a logic 1 on the input port. Thus my code could differentiate between a power-up start (capacitor discharged) and a watchdog-initiated start (capacitor charged).

I've even messed with one that switches off the 5V power rail, pauses for a couple of seconds, and switches it on again, initiating a clean power-up after a crash. That worked great. It's based on a well-known saying: "There's no reset like a power-down."

@matti1999: Could you post a link to that video you mentioned?

Hi,
Can I ask why everybody is going after a bandaid approach?
bandaid

Instead of looking at the most probable cause.


I presume the pump being switched is mains voltage and inductive?
Can I suggest you get the relay OFF the PCB and keep all of your mains wiring, in particular the pump wiring AWAY from sensor wiring and ALL low voltage supplies.

PLEASE, PLEASE a circuit diagram amd a picture of you project please?

Well draw a complete diagram, if you want to do proper troubleshooting/debugging, then please supply the asked for information, so we can give you accurate replies.

Tom.... :grinning: :coffee: :coffee: :australia:

Hi,
If you are switching mains voltage, 110Vac or 240Vac, it is extremely dangerous having that sort of voltage on your PCB AND SO CLOSE to the low voltage circuitry.
You should have a PCB cutout like this.

Tom.... :grinning: :coffee::coffee: :australia:
PS. I do like the realtime scaling of images after you have added the link in your message :+1: :+1: :+1:

I made the PCB as a school project for beginners, and the idea for the high voltage was for a grow light, but I dont use that anyways.

I Just found my diagram I made but its a picture of it, i dont remeber which website i made it on.
il put the diagram in #1

Okay so i made some adjustments to my code, with the watchdog timer and millisDelay.

il would very much like to know if im doing anything wrong :smiley:

Some of comments and varaiables is writen in danish

#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <MovingAverageFilter.h>
#include <avr/wdt.h>
#include <millisDelay.h>


MovingAverageFilter movingAverageFilter(10); //Gennemsnitet vil blive udregnet efter 10 mÄlinger, dette kan forÞges hvis der Þnskes et mere prÊcist gennemsnit.

int Pumpe = A4;
int Niveau_kontakt = 11;

float tempPin = A5;

int Jordfugtighed = A3;

millisDelay Temp;
millisDelay Soil;
millisDelay Pump;

const unsigned long TempTime = 1000;
const unsigned long PumpRunTime = 2000;
const unsigned long SoilCheckTime = 60000;


// LCD opsĂŠtning
const int  rs = 10, en = 9, d4 = 8, d5 = 7, d6 = 6, d7 = 5; // pins
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Variabler til jordfugtighedsmÄleren
const int AirValue = 592;   //you need to replace this value with Value_1
const int WaterValue = 278;  //you need to replace this value with Value_2
int intervals = (AirValue - WaterValue) / 3;

int soilMoistureValue = 0;
int SoilMoistureLevel = 0;
int SoilState;

bool LowWaterLevel = false;

bool FirstScan = true;

// Variabler til temperatur mÄling
float TempVal;
float NuvaerendeTemp; // Den nuvĂŠrende temperatur





//----------------------------------------------------------------------------------------//
void setup() {
  pinMode(Pumpe, OUTPUT);
  pinMode(Niveau_kontakt, INPUT);
  pinMode(tempPin, INPUT);
  pinMode(Jordfugtighed, INPUT);


  analogRead (A0); // force voltage reference to be turned on
  analogRead (A1); // force voltage reference to be turned on

  Serial.begin(9600);

  lcd.begin(20, 4);
  digitalWrite(Pumpe, HIGH);

  // Watchdog timer sat til 4 sekunder
  wdt_enable(WDTO_4S);
}

void loop() {

  wdt_reset(); //Starter watchdog timer forfra.

  lcd.setCursor(0, 1);
  lcd.print("Jorden = ");
  lcd.setCursor(0, 2);
  lcd.print("Temperatur = ");



  // NÄr JordfugtighedsmÄleren skal testes bruges dette stykke kode, som mÄler vÊrdien for hvad der er luft og hvad der er vand
  /*
    int val;
    val = analogRead(A3); //connect sensor to Analog 0
    Serial.println(val); //print the value to serial port
    delay(100);
  */


  // Hvis vandniveauet bliver for lavt vil en flydekontakt blive hĂžj og slukke for pumpen
  if (digitalRead(Niveau_kontakt) == HIGH) { //Start if
    //   Serial.println("Vand niveau er lavt"); // Hvis vand niveauet bliver lavt skrives en besked til serial om at niveauet er lavt
    LowWaterLevel = true;
    digitalWrite(Pumpe, HIGH); // Pumpe OFF
    lcd.setCursor(0, 0);
    lcd.print("Vand niveau lavt");
  }//End if
  else {
    LowWaterLevel = false;
    lcd.setCursor(0, 0);
    lcd.print("                ");
  }

  if (!Soil.isRunning()) { // Hvis "Soil" ikke tÊller sÄ skal den starte den og take en mÄling af jorden. Denne mÄde gÞr ogsÄ at det fÞrste scan vil mÄlingen blive taget da tiden ikke er startet i nu.
    SoilCheck();
    Soil.start(SoilCheckTime);
  }

  if (SoilState == 3) {
    SoilState = 0;
    if (LowWaterLevel == false) {
      Pump.start(PumpRunTime); // Start pumpen i 2 sekunder
    }
  }

  if (Pump.isRunning()) { //Hvis tiden er startet, startes pumpen.
    digitalWrite(Pumpe , LOW);
    // Serial.println("Pumpe ON");
  }
  if (Pump.justFinished()) { // NÄr tiden er gÄet stoppes pumpen.
    digitalWrite(Pumpe, HIGH);
    // Serial.println("Pumpe OFF");
  }

  if (!Temp.isRunning()) { // Hvis tiden for temperatur mÄlingen ikke er i gang tages en mÄling og tiden startes.
    TempMaalling();
    Temp.start(TempTime);
  }

}//Void loop end

// MÄling og udregning af temperaturen. Temperaturen kan visses med decimaltal.
void TempMaalling() {
  TempVal = analogRead(tempPin);
  float Voltage = TempVal * (5000 / 1024.0); // Udregning af spÊndnings oplÞsning. Da refferencen er 5V(5000mV) og det analog input bruger 10 bit som ogsÄ svare til 0 - 1023.
  float cel = Voltage / 10; // NÄr temperaturen stiger 1 grad celsius stiger spÊndingen med 10 mV og ved 25 grader celsius er spÊndingen 250 mV.

  // Temperaturen skrives til LCD skrĂŠmen
  if ( cel !=  NuvaerendeTemp) {
    NuvaerendeTemp = cel;
    lcd.setCursor(14, 2);
    lcd.print(cel);
    lcd.print("C°");

    Serial.print("TEMPRATURE = ");
    Serial.print(cel);
    Serial.print("C°");
    Serial.println();
  }
}

// MÄlling af jord fugtigheden
void SoilCheck() {
  float soilMoistureValue_Paletblad = analogRead(A3);
  float input = soilMoistureValue_Paletblad; // Input til udregning af gennemsnits jordfugtighed.
  float output = 0;


  for (int n = 0; n < 10 + 2; n++) // For loop for gennemsnits udregning
  {
    output = movingAverageFilter.process(input); // Udregning af det sammelagte gennemsnits resultat fra jordmÄling
  }

  // MÄling af jordfugtighed som om dannes til info om jorden er tÞr, vÄd eller meget vÄd som bliver sendt til serial.
  SoilState = Soil_Moisture(output, 1);
  Serial.println(output);
}

I forgot to post the code where I calculate the soil moisture, so here it is.

int Soil_Moisture(float soilMoistureValue, int Row) {
  if (soilMoistureValue > WaterValue && soilMoistureValue < (WaterValue + intervals)) {
    Serial.println("Very Wet");
    lcd.setCursor(10, Row); // cursoren sÊttes pÄ linje "LCDLineNr" plads 10
    lcd.print("         ");
    lcd.setCursor(10, Row); // cursoren sÊttes pÄ linje "LCDLineNr" plads 10
    lcd.print("Very Wet");
    int SoilMoistureLevel = 1;
    return SoilMoistureLevel;
  }
  else if (soilMoistureValue > (WaterValue + intervals) && soilMoistureValue < (AirValue - intervals)) {
    Serial.println("Wet");
    lcd.setCursor(10, Row); // cursoren sÊttes pÄ linje "LCDLineNr" plads 10
    lcd.print("         ");
    lcd.setCursor(10, Row); // cursoren sÊttes pÄ linje "LCDLineNr" plads 10
    lcd.print("Wet");
    int SoilMoistureLevel = 2;
    return SoilMoistureLevel;
  }
  else if (soilMoistureValue < AirValue && soilMoistureValue > (AirValue - intervals)) {
    int LCdLineNr;
    Serial.println("Dry");
    lcd.setCursor(10, Row); // cursoren sÊttes pÄ linje "LCDLineNr" plads 10
    lcd.print("         ");
    lcd.setCursor(10, Row); // cursoren sÊttes pÄ linje "LCDLineNr" plads 10
    lcd.print("Dry");
    int SoilMoistureLevel = 3;
    return SoilMoistureLevel;
  }
}

Hi,

So how do you turn your pump on and off?
What are the specs of the pump?
If the pump is not mains powered, what is its power supply?

Tom.... :grinning: :+1: :coffee: :australia:

The pump runs on 6v, so i use a external power supply which is connect to a relay modul that's controled by the arduino to open and closes the "+" signal to the pump. The arduino powers the coil and an output is used to activate the relay to close the circuit.

I use this kind of relay. I know i could use a transitor to do the same thing but then i would have to protect from transient. I know that a diode and a capsitor would remove the transient when the pump is turned off but I dont own a soldering iron to make a new PCB.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.