Does Arduino Uno hibernate by itself or why does my scetch seem to halt?

I have a greenhouse project that's supposed to take care of the greenhouse ventilation, i.e. temperature control.

The project uses a Dallas 1-wire-bus temperature-sensor to measure the room's temperature and is powered by a 12 volt battery. I have planned to install a solar-system to change the battery, but haven't done that yet.

The scetch is basically a bunch of IF-statements that opens the vent when the room-temperature exeeds 24 C and closes it when the temperature falls below 22 C. The vent opens in three stages so that when we go above 24 C, the vent opens 1/3 of the maximum, then the scetch waits for 5 minutes to let the temperature stabilize and if the temperature is still above 24 we go to 2/3:s and wait for another 5 minutes before opening to max, if needed. Closing of the vent goes similarly. Now, when I sit beside the Arduino and test the system, everything works fine, no problems at all, the vent opens and closes just like intended. I have of course shortened the delay that causes the scetch to wait for the room-temperature to stabilize, to one minute; don't want to wait for a half an hour for the whole process to complete. Then I change the delay back to 5 minutes and leave Arduino to do it job.

Then the next day comes. The vent opens as normal, but when it should close in the evening when the temperature drops, for some reason nothing happens, the vent stays open. If I now press the reset-button or connect Arduino to the laptop to monitor the serial, the scetch starts from the beginning and works fine again.

I wonder if anyone would have any glue of what happens here. Is it the 5 minute delay in the end of the main-loop that causes the problem or what? I checked the voltage of the battery and it was still 12,5 V. Even if the voltage should drop, there would still be enough for Arduino to keep on going. It's quite a mystery! I'm going to alter the scetch to use timers instead of delay to be able to make arduino to do even more than just open the vent, but it would be nice to find out the cause of this particular misbehaviour.

I'll attach the scetch later if someone want's to take a look at it. Just remembered that it's on the windows-part of my laptop and I'm mainly using Linux so it takes some time to get it moved in here when having to restart the computer and so on...

GardenElf:
I'll attach the scetch later if someone want's to take a look at it.

You are very unlikely to get help until you do.

Edit: corrected per Robin2

...R

It is probably a logical flaw in your chain of "if" statements.

If you are concerned that your uno is actually "stopping" for some reason, the first thing to try, is making your program also turn the led on the board on and off every few seconds. If it is still blinking when you come back, then your program is still running.

The next thing to do, is to realise that, for some reason, you sometimes get bogus readings from the sensor, and your program needs to ignore these or at least not do something stupid.

Well, I did actually read the thread "Read this before posting"... But to be able to attach the scetch I'd first have to dig it out from another operating system on the same computer I'm working on AND secondly to translate the comments into english (and add some more) so you guys would understand what I'm trying to say... didn't have time to do that yesterday evening. I'll try to do it tonight.

The only thing between working and non-working was the delay time (5 min vs. 1 min) that causes the scetch to wait a while so that the temperature settles. That also causes that I'm not able to make any leds to blink every few seconds but every five minutes :slight_smile: This is one of the reasons why I'm going to rewrite the scetch to use timers instead of a simple delay.

GardenElf:
...AND secondly to translate the comments into english (and add some more) so you guys would understand what I'm trying to say...

While I do appreciate your willingness to translate the comments I suspect you will find many folks on this forum who tend to ignore comments but are quite capable of reading C++ source code. In other words, why wait?

I usually take comments with a grain of salt, eg.

  Serial.begin (9600);   // initialize serial port to 1200 baud

There are also a few of that are capable of speaking several languages.. I can read and speak some spanish, some italian, some German and a little french and I find your comment somewhat condescending as it is your issues that I want to try to solve.
This Forum is a big part of my education.. along with books on both my Kindle Fire and my Nook book readers that are never more than two to four meters away from me.
Even with Google Translate, which I use frequently as it is a serious part of my education... As well,
Google is a source of possible solutions to or direction to the answers required.
I am a 68 year old retired engineer trying to learn a new and versatile, valuable programming language...
I realize that Google is my friend and I frequently use it to find solutions for those that can't or won't make the effort to do so..
I use it to find answers to what I don't understand... Yet.

Docedison

I changed the delay time in the end of the loop to 3 minutes yesterday (it was 5), and today the system has been working perfectly. Did the pretty long delay cause the trouble and if so, why? Nothing else has changed in the code.

// Kasvihuoneen lämpötilasäädin, eli luukkuautomatiikka.

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2 /*-(Connect to Pin 2 )-*/

OneWire ourWire(ONE_WIRE_BUS);                               
DallasTemperature sensors(&ourWire);                        

// Määritellään pinnit ja muuttujat

const int raja1 = 3; // limit-switch vent closed
const int raja2 = 4; // limit-switch vent fully open
const int virta = 5; // motor power relay
const int suunnanvaihto1 = 6; // motor polarity change relay 1
const int suunnanvaihto2 = 7; // motor polarity change relay 2
int raja1tila; // state of limit switch 1
int raja2tila; // state of limit switch 2
int lpt; // room temperature
int asento; // vent position



void setup() 
{
Serial.begin(9600); 
sensors.begin(); 
pinMode(raja1, INPUT_PULLUP);
pinMode(raja2, INPUT_PULLUP); // Otetaan pinnien 3 ja 4 ylösvetovastukset käyttöön. Muistettava kytkeä rajakytkimet siten että rajatilassa eivät johda!
pinMode(virta, OUTPUT);
pinMode(suunnanvaihto1, OUTPUT);
pinMode(suunnanvaihto2, OUTPUT);
Serial.println("Alkutilanne:");
raja1tila = digitalRead(raja1);
Serial.print("Raja1 = ");
Serial.println(raja1tila);
raja2tila = digitalRead(raja2);
Serial.print("Raja2 = ");
Serial.println(raja2tila);
digitalWrite(virta, HIGH);
digitalWrite(suunnanvaihto1, HIGH);
digitalWrite(suunnanvaihto2, HIGH);
delay(2000);

// Tarkistetaan onko luukku auki ja jos on, suljetaan jotta saadaan varmuus luukun asennosta
Serial.println("Tarkistetaan onko luukku kiinni");
if (raja1tila == 0)
  {
  digitalWrite(suunnanvaihto1, LOW); // kytketään moottori sulkemissuuntaan
  digitalWrite(suunnanvaihto2, LOW); // kytketään moottori sulkemissuuntaan
  Serial.println("Suljetaan luukku, suunnanvaihtoreleen pitäisi nyt vetää");
  delay (100); // kytkentäviive mahd. häiriöiden välttämiseksi
  digitalWrite(virta, LOW); // Kytketään moottorin virta
  Serial.println("Virtareleen pitäisi vetää");
  while(raja1tila == 0)
    {
    raja1tila = digitalRead(raja1);
    }
    digitalWrite(virta, HIGH);
    digitalWrite(suunnanvaihto1, HIGH);
    digitalWrite(suunnanvaihto2, HIGH);
    Serial.println("releiden pitäisi nyt olla pois päältä");
    asento = 0;
  }
}


void loop() // main loop

{

Serial.println("Varsinainen ohjelma alkaa");
sensors.requestTemperatures(); // Lähetä lukukomento anturille
lpt = sensors.getTempCByIndex(0);
Serial.print("Huoneen lämpötila on ");
Serial.print(lpt);
Serial.println("°C");
delay(1000);
raja1tila = digitalRead(raja1);
raja2tila = digitalRead(raja2);

//   Luukun aukaisu lämpötilan ylittäessä 24 C, odotetaan 5 minuuttia jokaisen avaussekvenssin jälkeen.

if (lpt > 24)
{
  Serial.print("Luukun asento on ");
  Serial.println(asento);
  Serial.print("Raja1 = ");
  Serial.println(raja1tila);
  Serial.print("Raja2 = ");
  Serial.println(raja2tila);
  
  
  if (asento == 60) // Jos luukku on auki 60%, avataan luukku asentoon 100%
  
  {
    Serial.println("Avataan luukku asennosta 60% -> 100%");
    digitalWrite(virta, LOW); // Kytketään moottorivirta päälle
    // Ajetaan päin rajakytkintä 2
    while (raja2tila == 0)
    {
      raja2tila = digitalRead(raja2);
    } 
    asento = 100; // Asetetaan luukun asennoksi "100%"
    digitalWrite(virta, HIGH); // Moottorivirta pois päältä
  }
  
  
  if (asento == 30) // Jos luukku on auki 30%, ajetaan luukku asentoon 60%
  
  {
    Serial.println("Avataan luukku asennosta 30% -> 60%");
    digitalWrite(virta, LOW); // Kytketään moottorivirta päälle
    delay(5000); // Moottori käy 5 sekuntia
    asento = 60; // Asetetaan luukun asennoksi "60%"
    digitalWrite(virta, HIGH); // Pysäytetään moottori
  }
  
  
  if (asento == 0) // Jos luukku on kiinni, ajetaan luukku asentoon 30%
  
  {
    Serial.println("Avataan luukku asentoon 30%");
    digitalWrite(virta, LOW); // Kytketään moottorivirta päälle
    Serial.println("Kytketään moottorivirta päälle");
    delay(5000); // Moottori käy 5 sekuntia
    asento = 30; // Asetetaan luukun asennoksi "30 %"
    digitalWrite(virta, HIGH); // Pysäytetään moottori
    Serial.println("Sammutetaan moottorivirta");
  } 
  
}



//   Luukun sulkeminen lämpötilan laskiessa 24 C:n tai alle. Odotetaan 5 minuuttia jokaisen sulkemissekvenssin jälkeen

if (lpt < 22)
{
  
  if (asento == 30) // Jos luukku on auki 30%, suljetaan luukku kokonaan
  
  {
    digitalWrite(suunnanvaihto1, LOW); // Moottorinsuunnanvaihto päälle
    digitalWrite(suunnanvaihto2, LOW); // Moottorinsuunnanvaihto päälle
    Serial.println("Suljetaan luukku asennosta 30% -> kiinni");
    delay(500); // kytkentäviive 0,5 sek mahdollisten häiriöiden välttämiseksi
    digitalWrite(virta, LOW); // Kytketään moottorivirta päälle
    // Ajetaan päin rajakytkintä 1
    while (raja1tila == 0)
    {
      raja1tila = digitalRead(raja1);
    } 
    asento = 0; // Asetetaan luukun asennoksi "0%"
    digitalWrite(virta, HIGH); // Moottorivirta pois päältä
    digitalWrite(suunnanvaihto1, HIGH); // Moottorin sunnnanvaihto pois päältä
    digitalWrite(suunnanvaihto2, HIGH); // Moottorin sunnnanvaihto pois päältä
  }
  
  if (asento == 60) // Jos luukku on auki 60%, ajetaan luukku asentoon 30%
  
  {
    digitalWrite(suunnanvaihto1, LOW); // Moottorinsuunnanvaihto päälle
    digitalWrite(suunnanvaihto2, LOW); // Moottorinsuunnanvaihto päälle
    Serial.println("SUljetaan luukku asennosta 60% -> 30%");
    delay(500); // Häiriönestoviive 0,5 sekuntia
    digitalWrite(virta, LOW); // Kytketään moottorivirta päälle
    delay(4000); // Moottori pyörii 4 sekuntia
    asento = 30; // Asetetaan luukun asennoksi "30%"
    digitalWrite(virta, HIGH); // Pysäytetään moottori
    digitalWrite(suunnanvaihto1, HIGH); // Moottorin sunnnanvaihto pois päältä
    digitalWrite(suunnanvaihto2, HIGH); // Moottorin sunnnanvaihto pois päältä
  }
  
  
  if (raja2tila == 1) // Jos luukku on auki 100% , ajetaan luukku asentoon 60%
  
  {
    digitalWrite(suunnanvaihto1, LOW); // Moottorinsuunnanvaihto päälle
    digitalWrite(suunnanvaihto2, LOW); // Moottorinsuunnanvaihto päälle
    Serial.println("Suljetaan luukku asentoon 60%");
    delay(500); // Häiriönestoviive 0,5 sekuntia
    digitalWrite(virta, LOW); // Kytketään moottorivirta päälle
    delay(4000); // Moottori pyörii 4 sekuntia
    asento = 60; // Asetetaan luukun asennoksi "60 %"
    digitalWrite(virta, HIGH); // Pysäytetään moottori
    digitalWrite(suunnanvaihto1, HIGH); // Moottorin sunnnanvaihto pois päältä
    digitalWrite(suunnanvaihto2, HIGH); // Moottorin sunnnanvaihto pois päältä
   }
   
}

delay(180000); // Lämpötilantasausviive 3 minuuttia ennen seuraavaa aukaisu-/sulkemissekvenssiä 

}// end main loop

When you specify a constant it gets translated into an int.
For a 5 minute delay try :-

delay(300000UL)

^ So it was a programming error then, delay value went off limits. Good to know, thanks Mike.

In the Elements of Programming Style it states:
"To avoid this unconscious acceptance [that the comment affects your understanding of the code], in The Psychology of Computer Programming Weinberg suggests that comments should be written on the right side of the page and code on the left, so the comments can be covered during debugging."

So having the comments in a not understood language is a good thing.

KeithRB:
So having the comments in a not understood language is a good thing.

And with a little bit of care in choosing variable and function names and in the way the code is organized it should almost be self-documenting.

...R

Which are also points that Kernigham and Plauger bring up!

Grumpy_Mike:
When you specify a constant it gets translated into an int.
For a 5 minute delay try :-

delay(300000UL)

No, it doesn't. The compiler does not foolishly take 300000 as written and truncate it to some 16-bit number. The value being higher than 32767 the compiler makes the constant an appropriate type. I can't find the official page about this, but this one will do for now:

The Standard has now invented a new way of working out what type an integer constant is. In the old days, if the constant was too big for an int, it got promoted to a long (without warning). Now, the rule is that a plain decimal constant will be fitted into the first in this list

int long unsigned long

that can hold the value.


Example code to demonstrate long constants are OK:

void foo (unsigned long bar)
  {
  Serial.println (bar);
  }

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  foo (300000);
  } 

void loop () { }

Output (as expected):

300000

There is no need to qualify a single literal like 300000 with UL or L or anything else. The compiler can work that part out for itself.


The only time the qualification is needed is in situations (like this thread) where you want to force an expression to fit, eg.

  unsigned long myResult = 1400 * 1000;

In this example the entire expression is done using int arithmetic, and the result is not 1400000 (on the Arduino).

So to fix this:

  unsigned long myResult = 1400UL * 1000;

Back to this thread, this line is OK as I demonstrated above:

delay(180000);

However if you had made it explicit (how you got to 180000) it would not be, eg.

delay (3 * 60 * 1000);  // delay 3 minutes

Now you have a problem, because it multiplies 3 ints together and does not get 180000.

Example:

void foo (unsigned long bar)
  {
  Serial.println (bar);
  }

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  foo (3 * 60 * 1000);
  }  

void loop () { }

Output:

4294950688

In that case you need to write:

delay (3UL * 60 * 1000);  // delay 3 minutes

Or:

delay ((unsigned long) 3 * 60 * 1000);  // delay 3 minutes