UNO hangs without cause

One of my UNO compatibles (Robored) controls a central heating system with several heat sources, among that a very efficient solar collector.
There are 5 Dallas temperature sensors, two optically coupled quad relay boards and an I2C LCD display. Of course there are separate power supplies for the UNO and the relays. Earlier issues with the remote display were solved when I used a cat6 shielded cable, now the installation has worked flawlessly for over a week.

But today I noticed the temperatures on the display were no longer updated, all valves were closed and the circulation pump was off. When I restarted the board, the solar collector was very near boiling point; less than one minute from catastrophy.

What can possibly cause the UNO to hang and why does it do that with all peripherals switched off?
Can it be caused by the I2C library, the oneWire library or the Dallas one? One peculiar thing I noticed is that sometimes the 1th temp. sensor misses a conversion, probably because the request.temperatures and sensors.getTempCByIndex(0) are too close together.

Will it help if I switch 2 outputs low in setup and make these high in "loop"?
If no software solution is possible I am forced to add an independent emergency circuit that overrides the UNO's pump and solar valve output, something I prefer to avoid.

Post your code (in code tags).

Pete

Hi Pete,
Thank you for showing interest.
Had to remove some stuff that isn't relevant but I'm afraid this is still gonna be a long read....

#include <Wire.h>  // Comes with Arduino IDE

#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
/*-----( Declare Constants )-----*/
const int buttonsPin = A0;
const int fireplacehotPin = A3;
const int bypassPin = 4;
const int pumpPin = 5;
const int solarvalvePin = 6;
const int mainvalvePin = 7;
const int heaterPin = 8;
const int boilervalvePin = 9;
const int overtempvalvePin = 10;
const int fireplacevalvePin = 11;
/*-----( Declare objects )-----*/
OneWire oneWire (2); //create onewire object
// 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
DallasTemperature sensors(&oneWire);
float TempIn1C; //room temperature
float TempIn2C; //solar temperature
float TempIn3C; //system temperature
float TempIn4C; //boiler output
//float TempIn5C; //heat exchanger not present

/*-----( Declare Variables )-----*/
byte downbutton = false;
byte enterbutton = false;
byte upbutton = false;
byte boilerstate = false;
byte fireplace = false;
byte heaterState = false;
byte solarState = false;
boolean timerStart = false;
boolean idle = true;
boolean overtemp = false;
int buttonValue = 0;
int fireplacehot = 0;
int menuValue = 2;
float setTemp = 20.5;
int deltaT = 10;
int minT = 30;
unsigned long timer = 0;
unsigned long oldtimer = 0;
unsigned long elapsed = 0;


void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  
 sensors.begin();
 
  lcd.begin(20,4);  
  for(int i = 0; i< 3; i++)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
   //start with outputs off//
  digitalWrite (bypassPin, HIGH);
  digitalWrite (pumpPin, HIGH);
  digitalWrite (solarvalvePin, HIGH);
  digitalWrite (mainvalvePin, HIGH);
  digitalWrite (heaterPin, HIGH);
  digitalWrite (boilervalvePin, HIGH);
  digitalWrite (overtempvalvePin, HIGH);
  digitalWrite (fireplacevalvePin, HIGH);
  
   //define pins //
  pinMode (bypassPin, OUTPUT);
  pinMode (pumpPin, OUTPUT);
  pinMode (solarvalvePin, OUTPUT);
  pinMode (mainvalvePin, OUTPUT);
  pinMode (heaterPin, OUTPUT);
  pinMode (boilervalvePin, OUTPUT);
  pinMode (overtempvalvePin, OUTPUT);
  pinMode (fireplacevalvePin, OUTPUT);
  
  lcd.backlight(); // finish with backlight on  
//-------- Write initial characters on the display --------
  // NOTE: Cursor Position: Lines and Characters start at 0  
  lcd.setCursor(1,0); //Start at character 1 on line 0
  lcd.print("solar " );
  lcd.print("     ");
  lcd.print("sys");
  
  lcd.setCursor(0,1);
  lcd.print("*heating");
  lcd.print("    set ");
  lcd.print (setTemp,1);
   
  lcd.setCursor(1,2);
  lcd.print("boiler");
  lcd.setCursor(12,2);
  lcd.print("now");
  lcd.setCursor(1,3); 
  lcd.print("fireplace");
  
  
}/*--(end setup )---*/


void loop()
{
  
  timer = millis(); //start counting milliseconds
  if (timerStart == false)
  oldtimer = timer; //prepare for later use
  else
  elapsed = timer - oldtimer; //calculate elapsed time
  
  if (elapsed >= 6000) //timeout reached
  {timerStart = false;
  elapsed = 0; //return to default menu value
  menuValue = 2; //cleanup display
  lcd.setCursor(0,0); //remove * line 0
  lcd.print (" ");
  lcd.setCursor(0,2); //remove * line 2
  lcd.print (" boiler");
  lcd.setCursor(0,3); //remove * line 3
  lcd.print (" ");
  lcd.setCursor(0,1); //write * line 1
  lcd.print ("*heating"); 
  lcd.setCursor(10,3);
  if (fireplace == true)
  lcd.print (" ON ");
  else
  lcd.print (" OFF");
  lcd.setCursor(8,2);
  if (boilerstate == true)
  lcd.print (" ON");
  else
  lcd.print ("OFF");
  lcd.setCursor(6,0); //remove solar entries
  lcd.print ("      sys     ");}
  
  sensors.requestTemperatures();
  
    //here I remove everything concerning text on the LCD
//the complete sketch is much longer than allowed here
  
 
  }
  lcd.setCursor (19,3);//put a cross in the last display position.
  lcd.print ("X");
  
  TempIn1C = sensors.getTempCByIndex(0);
  TempIn2C = sensors.getTempCByIndex(1);
  TempIn3C = sensors.getTempCByIndex(2);
  TempIn4C = sensors.getTempCByIndex(3);
  //TempIn5C = sensors.getTempCByIndex(4);//not (yet) installed
  lcd.setCursor (19,3);
  lcd.print ("+");
  
   /*Here the code starts that actually makes
  decisions based on settings and temperatures*/
  if (fireplace == true) //open valve and start pump
  {
  digitalWrite (fireplacevalvePin, LOW); //pin 11
  digitalWrite (pumpPin, LOW); //pin 5
  lcd.setCursor (16,3);
  lcd.print ("P");}
  if (fireplace == false && overtemp == false && solarState == false)
  {lcd.setCursor (16,3);
  lcd.print (" ");
  digitalWrite (fireplacevalvePin, HIGH);}
  
  fireplacehot = analogRead (fireplacehotPin);
  if (fireplacehot < 500 && fireplace == false)
  {fireplace = true;
  fireplacewarning ();
  }

  //conditions for the solar collector to operate
  lcd.setCursor (15,3);
  if (TempIn2C >= minT && TempIn2C >= TempIn3C + deltaT)
  solarState = true;
  else 
  solarState = false;

  if (solarState == true) //solar collector must be enabled
  {digitalWrite (solarvalvePin, LOW);
  lcd.print ("S");
  if (heaterState == false)//start pump when heating = off
  {delay(2000);
  lcd.setCursor (16,3);
  digitalWrite (pumpPin, LOW);
  lcd.print ("P");}}

  if (solarState == false)
  {digitalWrite (solarvalvePin, HIGH);
  lcd.setCursor (15,3);
  lcd.print (" ");}
  
  if (fireplace == false && solarState == false)
  {digitalWrite (pumpPin, HIGH); //no pump required
  lcd.setCursor (16,3);
  lcd.print (" ");
  }

  //conditions for the boiler to operate
  lcd.setCursor (17,3);
  if (boilerstate == true)
  digitalWrite (bypassPin, LOW); //tapwater from boiler
  else
  digitalWrite (bypassPin, HIGH); //tapwater from CV
  if (boilerstate == true && TempIn3C >= TempIn4C + 5.0)
  {digitalWrite (boilervalvePin, LOW);
  lcd.print ("B");}
  else
  {digitalWrite (boilervalvePin, HIGH);
  lcd.print (" ");}
  
  //start heating when room temp is below settemp
  if (idle == true && TempIn1C < setTemp)
  startHeating(); //heater was previously off
  //continue heating until 0.1C above settemp
  if (idle == false && TempIn1C >= setTemp + 0.1)
  stopHeating(); //heater was previously on
  //terminate heating when fireplace is used
  if (idle == false && fireplace == true)
  stopHeating ();
  
    //what to do in case of overheating
  if (heaterState == false && TempIn3C >= 85.0)
  {overtemp = true;
  digitalWrite (fireplacevalvePin, LOW);
  digitalWrite (overtempvalvePin, LOW);
  digitalWrite (pumpPin, LOW);
  lcd.setCursor (18,3);
  lcd.print ("!");}
  if (overtemp == true && TempIn3C < 85.0)
  {digitalWrite (fireplacevalvePin, HIGH);
  digitalWrite (overtempvalvePin, HIGH);
  digitalWrite (pumpPin, HIGH);
  overtemp = false;
  lcd.setCursor (18,3);
  lcd.print (" ");}
  }

  //conditions for normal heating
  void startHeating()
  {if (fireplace == true) //skip operation
  return;
  digitalWrite (mainvalvePin, LOW);//open valve
  delay(4000);
  digitalWrite (heaterPin, LOW);//start heating
  idle = false;
  heaterState = true;
  lcd.setCursor (18,3);
  lcd.print ("H");}

  void stopHeating()
  {
  digitalWrite (heaterPin, HIGH);//stop heating
  delay(10000); //allow heat to disperse
  digitalWrite (mainvalvePin, HIGH);//close valve
  idle = true;
  heaterState = false;
  lcd.setCursor (18,3);
  lcd.print (" ");}
 

  void fireplacewarning()
  { for(int i = 0; i< 100; i++)
  {
    lcd.backlight();
    delay(100);
    lcd.noBacklight();
    delay(100);
  }
   lcd.backlight();
  }

Your code is going to stop you left a else statement out on the overemp

/here I remove everything concerning text on the LCD

If that code is anything like the rest of your posted code, you'd do well to use the F() macro a bit more.

Next time you post code, could you do us all a favour and use the auto-format tool before you paste your code, please?

Had to remove some stuff that isn't relevant

Unless those were only comments, if you have unexpected behavior, every single line of code is important.

Thanks for your contributions.

be80be: I don't see anything wrong there, also the conditions for "overtemp" are only met when the system temperature exceeds a critical value, in which case heat is dumped in the fireplace heat exchanger and a radiator mounted on an outside wall. The UNO stopped processing today with just 36 C. system temperature.

AWOL: No idea what you mean by F() macro.

sterretje: uploading code is limited to 9000 characters. What I omitted were routines that are used for entering values like preferences and temperatures. Without touching the buttons, default values are used. And I also left out part of the setup that switches each peripheral on for test purposes.
I can upload the whole sketch as an attachment if you're interested.

CDK1:
I don't see anything wrong there,

But somebody else might.

uploading code is limited to 9000 characters.

You can upload a longer program by attaching the .ino file

A common cause of problems that don't happen immediately is running out of memory or over-writing memory locations.

...R

CDK1:
AWOL: No idea what you mean by F() macro.

https://www.google.com/search?q=F()+macro

That was very helpful!
With the F() added to all text strings RAM usage is down to 21% (from 48%).

Strange there is no mention of this in any of the example sketches I've seen or in the Arduino reference guide.
Whether or not this solves the issue only time can tell.

couple of things....
long code can be saved as a txt file and attached as a file.

NASA has redundant redundant safety systems. blow off valve is a term created for such a reason.
storing hot water above the heater allows the cold to sink into the heater, reducing the need for pumps.

an old term is putting all your eggs in one basket.

I think you can see where I am going.
any sensor can fail, and we often use the cheapest stuff possible.
any wire connection can fail.
any wire can fail, vibration, wear when it penetrates an enclosure, etc

don't forget to add warning lights.

3-mile island did not have the first sensor that would have detected a problem. it was a particulate counter on the exhaust. completely left out of the build. it would have alarmed well before any other problems. of course redundant safety measures picked up when the problem got worse.

The early shuttle had 3 computers, all doing the same thing. any one that failed left 2 working.

. . . and even when you think you've got everything covered this can still happen

CDK1:
That was very helpful!
With the F() added to all text strings RAM usage is down to 21% (from 48%).

Strange there is no mention of this in any of the example sketches I've seen or in the Arduino reference guide.
Whether or not this solves the issue only time can tell.

Actually, it is there. PROGMEM - Arduino Reference

dave-in-nj:
NASA has redundant redundant safety systems. blow off valve is a term created for such a reason.
storing hot water above the heater allows the cold to sink into the heater, reducing the need for pumps.

an old term is putting all your eggs in one basket.

I think you can see where I am going.
any sensor can fail, and we often use the cheapest stuff possible.
any wire connection can fail.
any wire can fail, vibration, wear when it penetrates an enclosure, etc

don't forget to add warning lights.

In the system I built over a decade ago, there were sensors, a complicated analog board and also a mechanical thermostat. It has worked well and the thermostat never had to take over.
Then last year I discovered Arduinos and was amazed by the flexibility, so one after the other I replaced by analog circuits and used UNOs for the entrance gate, the solar shower cabin and the heating system.
My sketches are crude, but I am still learning.

There is a blow-off valve in the heating system, so there will only be a mess in the house, no explosion.
But the solar collector has its own funny characteristics. It contains not much fluid and is well isolated, without circulation the fluid starts to boil within 2 minutes of bright sunshine. When it boils dry, the temperature rises until the glass shatters.
For circulation two items are crucial: the valve must be AC powered (normally closed) and the pump should work. So I must make an additional analog circuit that takes over in case the UNO doesn't do what I told it to do.

I have used the F() trick on all display strings, put the "sensors.requestTemperatures();" far away from the "TempIn1C = sensors.getTempCByIndex(0);", uploaded the improved sketch to the board and yet within half an hour saw the DallasTemperature library missed a conversion and briefly displayed -127.0.

Life is mean sometimes.

Maybe I'm wrong but when you run a if statement and it's true it will run the whole statement the way it looks to me you reset the statement with stuff like overtemp = false;

You should be something like this

If overtemp =<hot 
Do this 
else if  overtemp =>hot 
let's cool it down

But the way I see your code it could get stuck in a loop that never happens because you just reset the test.

I guess this is the part we are talking about:

//what to do in case of overheating
  if (heaterState == false && TempIn3C >= 85.0)
  { overtemp = true;
    digitalWrite (fireplacevalvePin, LOW);
    digitalWrite (overtempvalvePin, LOW);
    digitalWrite (pumpPin, LOW);
    lcd.setCursor (18, 3);
    lcd.print ("!");
  }
  if (overtemp == true && TempIn3C < 85.0)
  { digitalWrite (fireplacevalvePin, HIGH);
    digitalWrite (overtempvalvePin, HIGH);
    digitalWrite (pumpPin, HIGH);
    overtemp = false;
    lcd.setCursor (18, 3);
    lcd.print (" ");

The first part sets the flag when the system temperature is above the limit and the heater is switched off, so the cause is solar radiation or too high flames in the fireplace. This happens several times each year, two valves are opened and the pump is powered.

The second part is only executed when an "overtemp" condition has existed but the temperature has dropped below the threshold. To me that is a logical way of doing things, I don't see how that could lead to an endless loop.

The UNO hangs randomly at much lower temperatures. It stops updating the temperatures and cannot execute the overtemp routine.

CDK1:
I have used the F() trick on all display strings, put the "sensors.requestTemperatures();" far away from the "TempIn1C = sensors.getTempCByIndex(0);", uploaded the improved sketch to the board and yet within half an hour saw the DallasTemperature library missed a conversion and briefly displayed -127.0.

Life is mean sometimes.

You can post your full updated code as attachment so somebody can have a look at it.

A reading of -127.0 should be ignored; multiple consecutive readings of -127.0 in a short time are an issue. One precaution you can build in is that if that happens you open the valve and start the pump. I don't know the further implications for your system but it can prevent the solar collector from getting damaged (if I understand you correctly).

Your thread's title is 'Uno hangs without cause'. Is that still happening? If so, the watchdog timer was mentioned earlier and can be used to reset the Arduino.

So far freezing (the UNO) happened once after about a week since the last reboot. The -127.0 error came yesterday, shortly after uploading the latest sketch that is in the attachment.

sketch_gate.ino (12.1 KB)

I guess you posted the wrong sketch? Anyway, the code for this one might be a bit cleaner if you use more functions; e.g.

  if (carButton == HIGH) // vehicle button has been pressed 1th time
  {
    openGates();
  }

And openGates() will contain the body of the if

void openGates()
{
  gateClosing = LOW;
  gateOpening = HIGH; //gate is moving to open position
  digitalWrite (leftgateclosePin, HIGH);
  delay(300);
  digitalWrite (rightgateclosePin, HIGH);
  delay(300); //in case gate was previously closing
  digitalWrite (leftgateopenPin, LOW); //left relay activated
  delay(1000); //right gate is delayed to avoid collosion
  digitalWrite (rightgateopenPin, LOW);//right relay activated
  delay(1000); //releases the limit switch
  pedestrian = false;
  StartTimer();
  lcd.setCursor(8, 0);
  lcd.print("Opening");
}

sterretje:
I guess you posted the wrong sketch? Anyway, the code for this one might be a bit cleaner if you use more functions;

It would be a lot easier to read if you used a consistent indentation scheme.