What would cause an Arduino's sketch to hang?

Hello all!

I have been working on this Environmental control system for some time now and thanks to this community is ALMOST completely operational.

The program is quite simple. Take reading from two different sensors, and if they are below or above certain level, switch on a relay.

The problem I am coming across now is that I will occasionally come to the Arduino not functioning as it should... as if the sketch ceases to loop and gets stuck performing its last function with both relays off, one on, or both on. When I reset the Arduino through uploading the same sketch, the Arduino takes a reading and "realizes" it is out of the allowed humidity/co2 level and functions as it should... for a while.

04/03/18 UPDATE:
I am utilizing a new humidity sensor (BME280) which allows me to use the SDA and SCK pins on the Arduino along with the CO2 sensor. I am no longer using duel I2C wires to communicate with the sensors individually, however the problem of the the sketch hanging still persists.

its almost as if the Arduino gets takes one last reading from the sensor(s), acts accordingly... but fails to loop and take another reading. Hence getting stuck performing its last action with the relay(s)

I have revised the code a bit (and used auto-format), by shortening the delay() intervals and changing the IF statements to include <= or >=. Example below.

// CO2 sensor ON-OFF statement
  if (mySensor.ppm >= ppmLevel) {
    digitalWrite(co2Pin, LOW);
    digitalWrite(8, LOW);
  }
  else {
    digitalWrite(co2Pin, HIGH);
    digitalWrite(8, HIGH);
  }
  delay(1000);

  delay(1000);

  // Humidity ON-OFF statment
  int humidity = mySensorB.readFloatHumidity() ;
  if (humidity <= humLevel)
  {
    (digitalWrite(humidityPin, LOW));
    (digitalWrite(7, LOW));
  }
  else {
    (digitalWrite(humidityPin, HIGH));
    (digitalWrite(7, HIGH));
  }

I felt like using a longer interval (50s) would prevent the sketch hanging from occurring so quickly... considering the sketch has hung four times just this morning since the change, I am lead to believe shortening the delay time makes the problem worse.

I have noticed the sketch has a higher tenancy to fail when the 12v-5v buck converter is at 5.1v instead of 5.4v. Perhaps it is a power related problem?
sidenote: co2 connected to 5v, humidity sensor connected to 3.3v. Power source is 12v 1200ma. Total current draw is no more than 600ma

I am currently working on adding the watchdog timer, as I feel this will help me bypass this problem by resetting the Arduino at regular intervals.

Thank you for your input so far.
Attached is a schematic of the sketch and below you will find the revised code.

Link to co2 sensor:
https://sandboxelectronics.com/?product=mh-z16-ndir-co2-sensor-with-i2cuart-5v3-3v-interface-for-arduinoraspeberry-pi

Link to humidity sensor:

Revised code is as follows:

#include <Wire.h>

//in use 02/
#include <NDIR_I2C.h>

//in BME280 use
#include "SparkFunBME280.h"

BME280 mySensorB; //Uses I2C address 0x76 (jumper closed)


NDIR_I2C mySensor(0x4D); //Adaptor's I2C address (7-bit, default: 0x4D)

// Environemntal variables
int humLevel = 84.0;   // highest observed valuse 84 = 100%
int ppmLevel = 700;

// Relay PIN
int co2Pin = 2;
int humidityPin = 3;



void setup()
{
  Serial.begin(9600); // Open serial connection to report values to host
  Serial.println("Starting up");
  // set the digital pin as output:
  pinMode(co2Pin, OUTPUT);
  pinMode(humidityPin, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  delay(1000);

  //CO2 Begin
  if (mySensor.begin()) {
    Serial.println("Wait 10 seconds for sensor initialization...");
    delay(10000);
  } else {
    Serial.println("ERROR: Failed to connect to the sensor.");
    while (1);
  }

  //BME280 USE
  mySensorB.setI2CAddress(0x76); //Connect to a second sensor
  if (mySensorB.beginI2C() == false) Serial.println("Sensor B connect failed");

  Serial.println("Starting up");
  // set the digital pin as output:
  pinMode(co2Pin, OUTPUT);
  pinMode(humidityPin, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  delay(1000);
}

void loop()
{


  //CO2 Begin

  if (mySensor.measure()) {
    Serial.print("CO2 Concentration is ");
    Serial.print(mySensor.ppm);
    Serial.println("ppm");
  } else {
    Serial.println("Sensor communication error.");
  }

  delay(5000);

  //BME280 Begin
  Serial.print(" Humidity: ");
  Serial.print(mySensorB.readFloatHumidity());

  Serial.print(" Pressure: ");
  Serial.print(mySensorB.readFloatPressure(), 0);

  Serial.print(" Temp: ");
  //Serial.print(mySensorB.readTempC(), 2);
  Serial.print(mySensorB.readTempF(), 2);

  Serial.println();


  delay(5000);


  // CO2 sensor ON-OFF statement
  if (mySensor.ppm >= ppmLevel) {
    digitalWrite(co2Pin, LOW);
    digitalWrite(8, LOW);
  }
  else {
    digitalWrite(co2Pin, HIGH);
    digitalWrite(8, HIGH);
  }
  delay(1000);

  delay(1000);

  // Humidity ON-OFF statment
  int humidity = mySensorB.readFloatHumidity() ;
  if (humidity <= humLevel)
  {
    (digitalWrite(humidityPin, LOW));
    (digitalWrite(7, LOW));
  }
  else {
    (digitalWrite(humidityPin, HIGH));
    (digitalWrite(7, HIGH));
  }

  delay(5000);
}

Please always do a Tools > Auto Format on your code before posting it. This will make it easier for you to spot bugs and make it easier for us to read. If you're using the Arduino Web Editor you will not have access to this useful tool but it's still unacceptable to post poorly formatted code. I recommend you to use the standard IDE instead.

When your code requires a library that's not included with the Arduino IDE please always post a link (using the chain link icon on the toolbar to make it clickable) to where you downloaded that library from or if you installed it using Library Manger(Sketch > Include Library > Manage Libraries) then say so and state the full name of the library.

You might find this useful to track down the cause of the hang:

But be warned that you should not use the watchdog timer if you have a Pro Mini or old Arduino Nano with the stock bootloader.

I agree with everything pert said. Please also post a circuit diagram. Your statements about two i2c connections seem suspect. On a standard Uno, there are indeed two sets of connectors, but they both connect to the same pins.

The only thing outside of the "normal wiring" is that I utilize TWO sets of I2C communication wires. One set as the onboard SDATA and SCLOCK pins and one set specified at pin 5 and 6. This is due to me using user created libraries for the two different sensors. Is this the problem?

Quite possibly you have dueling interrupts.

I2C is a bus. It can have many riders but they all need to work with wire.h and have different addresses.

You have very long delays in the loop e.g. delay(50000); (50 seconds) which could give the impression of an unresponsive system.

I would have tended to write this:

  // Humidity ON-OFF statment
  // NOTE: Relay is on when LOW and off when HIGH
  if (humidity < humLevel)
  {
    (digitalWrite(HUMIDITYpin, LOW));
  }
  else {
    (digitalWrite(HUMIDITYpin, HIGH));
  }
  delay(1000);
  // Status LED Code HUMIDITY
  if (humidity > humLevel)
  {
    (digitalWrite(7, HIGH));
  }
  else {
    (digitalWrite(7, LOW));
  }

  delay(50000);

more like this to handle the situation more cleanly where humidity exactly equals humLevel:

  // Humidity ON-OFF statment
  // NOTE: Relay is on when LOW and off when HIGH
  if (humidity < humLevel)
  {
    digitalWrite(HUMIDITYpin, LOW);
    digitalWrite(7, LOW);  // Status LED Code HUMIDITY
  }
  else {
    digitalWrite(HUMIDITYpin, HIGH);
    digitalWrite(7, HIGH);  // Status LED Code HUMIDITY
  }

  delay(50000);

Hi,
I would suggest you forget using delay and use millis to do your delay.

If you select Files, Examples, Digital, Blink Without Delay

It is an example of using millis to delay operations without affecting others.

Delay STOPs all code when it is activated, so no I/O or processing is done for example 50000 or 50 seconds.

Also put in a heartbeat bit of code, that blinks the onboard LED so that you know your code is running.

Tom... :slight_smile:

Add print lines to trace your execution. When you zero in to a last print before it locks, add more if the reason isn't clear.
Print the values that determine where the code does and find that bug.

There's nothing that I can see in the code that would suggest running out of ram so I'm going to go with a power problem. Turning the relay(s) on and off probably glitches the supply to the Arduino so that it resets. You need to show a circuit diagram of precisely how things are wired.

As for your current version of the code ("Last Edit: Today at 10:11:01 by profk007" ):

 Serial.println("Starting up");
  // set the digital pin as output:
  pinMode(co2Pin, OUTPUT);
  pinMode(humidityPin, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  delay(1000);

Why do you do that twice in setup? Remove the second occurrence of that block of code.

int co2Pin = 2;
int humidityPin = 3;

Why do you have names for these pins but not for the relay pins on 7 and 8?

Why have so many delays (a total of 17 seconds)? Just put one delay (e.g. delay(10000)) at the beginning of the loop() function.

It is not nice to keep editing the code in your original post. It makes the comments which follow look stupid. For example, your comment about using 50s delays and @6v6gt's comment on the same subject look weird because there aren't any 50s delays in your code (not now anyway).
Just post a new version each time you have one so that the sequence of events is preserved and comments make sense.

Pete

Hello, thanks for the reply.

I thought about how "rewriting" my post would alter the perception of new readers (for the better) as I included in my new post that I rewritten the code and shortened the 50s delay to 5s. Ill remember to leave things as be next time.

Pin 7 and Pin 8 are "LED status" pins corresponding to either relay 1(co2/fan=co2Pin) or 2(humidifier=humidityPin), a minor detail as I feel like I have bigger fish to fry at the moment.
They light up when the system is in desirable parameters.

The represented circuit is a near exact copy of how the circuit is wired... Breadboard and all.

Excessive use of the delay() function is to simplify the sketch for debugging.

I am beginning to believe problem deals more with power consumption, specifically when both relays try to turn off/off at the same time, function the LEDs, and possibly take a reading from the sensors. Each device utilizes about 60ma at 5v. Still I did not understand why as the power source is 12v 1200ma and max current draw is 600ma at 5v.

The original idea behind utilizing the delay() function is that I am giving the Arduino a "break" to perform its function before moving on...

By giving the sketch break of 50s or delay(50,000), I am allowing the fan connected to one of the relays which is activated when the co2 ppm reads above a certain level to "stay on" for 50s to bring down the co2 concentration to a significant level. A similar deal for the humidifier/humidityPin.

As you may imagine, the sketch "hung" sooner with a shorter delay function as more switching on/off of the relays occurred more frequently and the devices connected to the relays had less of an effect with a shorter delay() time. This lead to a sooner instance of hanging of the circuit.

When the circuit does hang it seems to be just about when the circuit is about to switch on a relay approaching the exact value of the parameter from the sensor. Circuit fails to loop at this point.

I will reinsert the millis() function via blink without delay soon. as for now the sketch is running and will post an serial monitor screen shot when/if it fails.

Thank you for your input.

Current code with delay() strategically placed + named pins for 7 and 8.

#include <Wire.h>

//in use 02/
#include <NDIR_I2C.h>

//in BME280 use
#include "SparkFunBME280.h"

BME280 mySensorB; //Uses I2C address 0x76 (jumper closed)


NDIR_I2C mySensor(0x4D); //Adaptor's I2C address (7-bit, default: 0x4D)

// Environemntal variables
int humLevel = 95.0;   // highest observed valuse 84 = 100%
int ppmLevel = 700;

// Relay PIN
int co2Pin = 2;
int humidityPin = 3;
int co2LEDstatus = 8;
int humidityLEDstatus = 7;


void setup()
{
  Serial.begin(9600); // Open serial connection to report values to host
  Serial.println("Starting up");
  // set the digital pin as output:
  pinMode(co2Pin, OUTPUT);
  pinMode(humidityPin, OUTPUT);
  pinMode(humidityLEDstatus, OUTPUT);
  pinMode(co2LEDstatus, OUTPUT);
  delay(1000);

  //CO2 Begin
  if (mySensor.begin()) {
    Serial.println("Wait 10 seconds for sensor initialization...");
    delay(10000);
  } else {
    Serial.println("ERROR: Failed to connect to the sensor.");
    while (1);
  }

  //BME280 USE
  mySensorB.setI2CAddress(0x76); //Connect to a second sensor
  if (mySensorB.beginI2C() == false) Serial.println("Sensor B connect failed");

  Serial.println("Starting up");
  // set the digital pin as output:
  pinMode(co2Pin, OUTPUT);
  pinMode(humidityPin, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  delay(1000);
}

void loop()
{
  //CO2 Begin

  if (mySensor.measure()) {
    Serial.print("CO2 Concentration is ");
    Serial.print(mySensor.ppm);
    Serial.println("ppm");
  } else {
    Serial.println("Sensor communication error.");
  }
  
  //BME280 Begin
  Serial.print(" Humidity: ");
  Serial.print(mySensorB.readFloatHumidity() + 10);

  Serial.print(" Pressure: ");
  Serial.print(mySensorB.readFloatPressure(), 0);

  Serial.print(" Temp: ");
  //Serial.print(mySensorB.readTempC(), 2);
  Serial.print(mySensorB.readTempF(), 2);

  Serial.println();

  // CO2 sensor ON-OFF statement
  if (mySensor.ppm >= ppmLevel) {
    digitalWrite(co2Pin, LOW);
    delay(1000);
    digitalWrite(8, LOW);
  }
  else {
    digitalWrite(co2Pin, HIGH);
    delay(1000);
    digitalWrite(8, HIGH);
  }
  delay(10000);

  // Humidity ON-OFF statment

  if (mySensorB.readFloatHumidity() +10 <= humLevel)
  {
    (digitalWrite(humidityPin, LOW));
    delay(1000);
    (digitalWrite(7, LOW));
  }
  else {
    (digitalWrite(humidityPin, HIGH));
    delay(1000);
    (digitalWrite(7, HIGH));
  }
  delay(10000);
  Serial.println(millis()/1000);
}

Still I did not understand why as the power source is 12v 1200ma and max current draw is 600ma at 5v.

The nominal draw of a relay is not the same as the instantaneous amount that it draws just as it is turned on. It can also cause a significant back EMF when it is turned off. Your power supply may sag a bit when the relay turns on but the more likely problem is the back EMF caused by the collapsing magnetic field in the coil when the relay is turned off. You need a diode across the relay to block that, otherwise it will give the Arduino serious indigestion.

The represented circuit is a near exact copy of how the circuit is wired.

What? Where?
"near exact" means that your circuit isn't the same as whatever one you derived it from, in which case it's going to be hard to figure out whether your circuit is correct as-is.

You still have the duplicated block of code in setup().

Pete

Thank you for your input Pete,

I believe the EMF situation when the relay closes is a huge factor in the problem.

The schematic was only off in the placement of the relay in relation to the Arduino. (to the left instead of the right) I have since rewired a separate 3.3v "source" from the Arduino to the top of the breadboard which powers both sensors. The schematic is now exactly how it is wired.

Attached is the new schematic.

As for the duplicated code block, that came from messing around and changing the variable names from the "blink without delay" sketch. They used to be named ledPin1 and ledPin2. They have been removed.

I will check back in once I install some diodes.

68 Ω is too small for the LEDs, use at least 220 Ω

Thank you larryD, I will switch those out immediately.

Also I found I have a few 1N4007 diodes laying around. From my research, I am lead to believe to wire the diode in parallel.

LINK to diode(s) here:

Current wiring is as follows. Is this correct?

Do I need a higher spec diode or will this suffice?

Do I need a diode between the output pins of the Arduino (pin 2 & pin 3 in this case) and the 2channel relay?

Revised schematic is attached.

Not a schematic, but a confusing picture (Fritzing usually is).

I see a BME280, powered with 3.3volt, but connected to 5volt I2C lines.
That Amazon module you linked to does not have an onboard level translator, so you can't do that.

I see something like a WeMos D1 module with relay, with the reset line connected to 5volt and data lines connected to the Arduino. What is it really.
Leo..

Excessive use of the delay() function is to simplify the sketch for debugging.

The delays I see in there are too short for human notice but long enough that the code spends way more cycles on delay than the rest.

Make 1 char trace writes just showing a symbol to show what branches where taken. It's a trail to the scene of the crash....

You can build in your own breakpoints, make the user hit a key or button to continue..... they'd have to notice those.

Yes, please post actual circuit diagram. So not Fritzing or other spaghetti type mess, and showing what you REALLY have wired. Not "almost".

Still my money is on the relays and power supply. This comment is the smoking gun:

profk007:
its almost as if the Arduino gets takes one last reading from the sensor(s), acts accordingly... but fails to loop and take another reading. Hence getting stuck performing its last action with the relay(s)

That's apparently an edit from 3 May, almost a week after originally posted. DON'T DO THIS. Just post a new comment so the people that have replied already, monitor the thread, and are trying to help actually see it (no-one is ever looking back at old messages of a thread they replied to already, they will only see new messages). Same for later attachment of images, just post a NEW reply. Edits are OK for correcting typos.

Now for the relay:

  • how much power can your power supply deliver?
  • do you have any decoupling caps/filtering caps/flyback diodes either on the relay module or externally installed?
  • is it always upon switching on or off a relay? Any chance that both relays are switched on at the same time?

wvmarle:
Yes, please post actual circuit diagram. So not Fritzing or other spaghetti type mess, and showing what you REALLY have wired. Not "almost".

Still my money is on the relays and power supply. This comment is the smoking gun:
That's apparently an edit from 3 May, almost a week after originally posted. DON'T DO THIS. Just post a new comment so the people that have replied already, monitor the thread, and are trying to help actually see it (no-one is ever looking back at old messages of a thread they replied to already, they will only see new messages). Same for later attachment of images, just post a NEW reply. Edits are OK for correcting typos.

Now for the relay:

  • how much power can your power supply deliver?
  • do you have any decoupling caps/filtering caps/flyback diodes either on the relay module or externally installed?
  • is it always upon switching on or off a relay? Any chance that both relays are switched on at the same time?

Hello sir,

I am still finding my way around working this forum, thank you for your patience thus far.

I am working on a way to purify water using a biological organism and it is important to keep the system within parameters. That has not been happening, and it is quite frustrating as the window of opportunity gets smaller as each day passes and the organism ages when out of spec.

  1. The power supply is a 12v 1200 ma non switching AC-DC converter and by utilizing a DC-DC buck converter am powering the Arduino and relays. The sensors are powered by 3.3v from the Arduino.

  2. I am now utilizing a diode (1N007) wired in parallel between the power source and relay as someone pointed out this could very well be the problem. However, I'm not even too sure this wired correctly. (please see attached spaghetti diagram). This is the only diode I am currently using. I had the system continue overnight which was a first, but I have caught the sketch hanging even as I am typing this reply.

  3. Both relays do switch on and off often, but with the use of the delay() function there is a certain amount of offset built into the sketch, which is 10s currently. Last reading from serial monitor before the sketch hangs appears to be when the "humidity relay" SHOULD switch on, but does not.

System functioned for multiple hours last night, but for only 30 minutes this morning before needing a reset. No changes have been made to the circuit since the addition of the diode.

Additional info:
Driving current for the each relay is 60ma at 5v, (2-channel module)
Co2 sensor uses 60ma at 3.3v per reading
BME280 sensor uses 1ma at 3.3v per reading

In itself, this doesn’t look good.

  1. The power supply is a 12v 1200 ma non switching AC-DC converter and by utilizing a DC-DC buck converter am powering the Arduino and relays

The 12V/200mA should be ok, but filtering, and not isolating the relay supply (caps, diode etc ) from the Arduino input is a significant point of concern.
What are you driving with the relays? How are those devices connected?

lastchancename:
In itself, this doesn’t look good.The 12V/200mA should be ok, but filtering, and not isolating the relay supply (caps, diode etc ) from the Arduino input is a significant point of concern.
What are you driving with the relays? How are those devices connected?

Hello sir,

I have added a flyback diode between the 5v and ground pins of the relay. As for driving the relays, jumper wire is connected directly from the Arduino to the relay pins. Would these require diodes as well?

Up until just yesterday I did not realize the relays could cause such trouble. Any advice is appreciated.

The problem appears to be with the relay trying to switch on - this may cause a power drop. Try adding a large sized cap (470 uF or more) to stabilise the power. That it's with one relay and not with the other is pure coincidence, no two relays are exactly the same.

Secondly, try isolating the power supplies, by using a completely separate power supply dedicated to the Arduino. Depending on your relay modules (with optocouplers?) this can be 100% isolated, in other cases you still have to connect grounds. Use battery power or an old 5V mobile phone charger that just powers the Arduino.