Arduino Nano conundrum

I have a weird issue with a system I built.
It is built on the Arduino Nano.
The design is a Solar panel water pump controller.
It has two one wire sensors to measure the cold water into the panel and another on the hot water out of the panel. The program uses a 5 degree differential before triggering the pump.
There is a light sensor that disables pumping during the night.
A display registers the status of the light, temps, and whether the pump is active or not.
Built into this is another piece moves a ball valve into either an open or closed position.
Relays control the pump and ball valve.

When I originally benched this system, it worked fine and has subsequently been tweeked to perform better.
When the unit powers on, it ensures the ball valve is closed. The light status is checked and if it is over a specific value, the ball valve opens.
The temp sensors are probed and depending on the results the pump will flush the panel until the inlet and outlet of the panel are identical.
The problem I experience is this controller goes into a weird state and hangs. However one of the red LEDs flashes very fast. You cannot reset the board. A full power cycle is required, and process starts again.
The freezing can happen within five minutes to two hours. Very random.
Recently another issue popped up and the temperature sensors started to intermittently fail to respond.
The relay unit is separated from the Nano.
The relays have emf diodes in place across the power supply. I stuck 1000mfd caps across the relay power supply.
4k7 pull up resistors in the data lines.
I recently changed the power supply to an external 9vdc to use the onboard regulator.
I put into the code a watch dog timer which works fine on the bench when I simulate a sensor or code hang.
I changed my delay() to millis.
All of this has helped zilch.
My temp sensors are on 10m cables and my LCD display on a 2m cable. This may be my problem.
I dropped a scope onto the power supply and there is some minor noise around 50mv.
There is no other equipment around that would generate noise.
The strange thing, is this issue becomes apparent when the light sensor enables the pump.
However on a cloudy and insufficient heat and the pump might not be triggered.
It is a bizarre issue.
Any thoughts.

Do you think it might help if you posted your sketch ?

Could be a hardware issue or a software issue or both.

1 Like

I am guessing that this is the biggest difference with your bench setup.

Seems to be an error a lot of people make. Proper EMC testing is expensive and time consuming so outside of commercial projects people find out by trial and error.

TTL level signals are intended to be used on a PCB, and even then with limitations in noisy environments. Running cables off-board direct to the CPU (or other digital electronics) is effectively connecting a large antenna: a really bad idea.

Any signals going off board need to be suitably filtered, and digital signals need to go through line drivers like RS485 etc.

Hello teqlove86

Welcome back.

Post your sketch, well formated, with well-tempered comments and in so called
code tags "<CODE/ >" and schematic to see how we can help.

Have a nice day and enjoy coding in C++.

Replaced the Nano, and same issue.

That was my suspicion, as it is the only variable.
I had the sensor cables running along the copper pipe. Thinking that the pipe maybe picking up stray noise, I took them off.
What might be a contribution to this issue is the area where it is installed has a metal corrugated roof. Could be a cause of noise.

/********************************************************************/
//
// All digital pins must have 4K7 ohm pullup resistors to the suppy voltage.
// All digital pins must have a 100nF capacitor as close to the board to ground (0v).
// Power supply must be ground (0v) to earth.
// 100nF capacitor across the 5V & 3v3 supply line to ground (0V).
// 100Nf capacitor across the relay input pins and 5v pins to ground (0V). 
//
// First we include the libraries
#include <OneWire.h> 
#include <DallasTemperature.h>
#include <SPI.h>
#include <LiquidCrystal_I2C.h> // includes the LiquidCrystal Library 
#include <avr/wdt.h> // Watchdog library
/********************************************************************/
// Data wire is plugged into pin 2 on the Arduino 
#define ONE_WIRE_BUS 2 
/********************************************************************/
// Setup a oneWire instance to communicate with any OneWire devices  
// (not just Maxim/Dallas temperature ICs) 
OneWire oneWire(ONE_WIRE_BUS); 

/********************************************************************/
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

/********************************************************************/ 
//Set up relay first output
int relay8 = 8; // Pump Relay module IN1
int relay9 = 9; // Ball Valve Relay module IN1
volatile byte relayState = HIGH;
int flushPump = 0; // Initialize flushpump variable
int flushLoop = 8; // Initialize flushLoop variable
int panelFlush = 0; // Initialize panelFlush timer variable
int ballValveCycleTime = 15000; // Initialize the ballValvecycleTime variable
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);
// Solar Panel Flush value 5 seconds
int SensorDifferential = 5; // Initialize SensorDifferential variable. Difference between in/out sensors
int ldrPin = A0; // select the input pin for LDR
int ldrValue = 0; // variable to store the value coming from the ldr sensor
int maxLdrValue = 600 ; // variable to enable pumping to start
int overRidePin = A1; // If this pin is low, then we can pump
int overRideValue = 0;
int lastSensor0 = 0;
int lastSensor1 = 0;
unsigned long time_now;
int programDelayTime = 1000;
int RESET_PIN = 3;
int BV_STAT = 0 ;

void setup(void) 
{
  // Configure auto reset
  //digitalWrite(RESET_PIN, HIGH);
  //pinMode(RESET_PIN, OUTPUT);
 // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display }
 // Start up the library
 sensors.begin();
 lcd.init();
 lcd.backlight(); 
 wdt_disable(); //Disable WDT
 
 // start serial port 
  Serial.begin(115200); 
  Serial.println("Goodwitch Systems - Solar Pump Control - 2.8.0"); 
 
 // Start up the library 
 
 pinMode(LED_BUILTIN, OUTPUT);
 lcd.clear();
 lcd.setCursor(0,0);
 lcd.print("Goodwitch Systems");
 lcd.setCursor(0,1);
 lcd.print("Solar Pump Control");
 lcd.setCursor(0,2);
 lcd.print("Version: 2.8.0");
 delay(2000);
 lcd.clear();
 delay(3000);
 wdt_enable(WDTO_8S); // options: WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S }
 // Force the ball valve to close regardless, as the previous state may have left the valve open.
 // The default relay state is the ball valve to close, so it may reset to the closed state
 // Serial.println("started 8 second Watchdog timer");
 pumpOff();
 ballValveClose(); 
}
 
void loop(void) 
{ 
 wdt_reset(); // confirm to watchdog timer that all is well 
 //Serial.println("Reset Watchdog Timer - 0");
 digitalWrite(LED_BUILTIN, HIGH);    // turn the LED On
 // call sensors.requestTemperatures() to issue a global temperature 
 // request to all devices on the bus 
 /********************************************************************/
 //Serial.print(" Requesting temperatures..."); 
 sensors.requestTemperatures(); // Send the command to get temperature readings 
 
 // Serial.println("DONE"); 
 /********************************************************************/
 //Sensor1 is the COLD sensor Inlet
 
 int Sensor1 = round(sensors.getTempCByIndex(1));
 //int lastSensor1 = Sensor1;
 // Take the output sensor and add the differntial value as the switch on value.
 // Sensor0 is the HOT sensor Outlet
 //int lastSensor0 = Sensor0;
 int Sensor0 = round(sensors.getTempCByIndex(0)) + SensorDifferential;
 //int Sensor0 = round(sensors.getTempCByIndex(0));
 // You can have more than one DS18B20 on the same bus.  
 // 0 refers to the first IC on the wire 
 
 // Check for the sensor failure

// This section tests the sensors continously.
 // Should a sensor fail, then the system will shutdown the pump immediately
 // This section is a problem when a sensor does not respond and invokes the watchdog. 
 // Better to use the existing value

 // If the sensor returns a value of -127, then the read failed.
 // We take the last sensor reading and use that as it does not matter
 // if the sensor value stays the same, as long as we have a reasonable value
 if ( Sensor0 == -127 ) {
    Sensor0 = lastSensor0 ;
  } else { 
    lastSensor0 = Sensor0;
 }
 // If the sensor returns a value of -127, then the read failed.
 // We take the last sensor reading and use that as it does not matter
 // if the sensor value stays the same, as long as we have a reasonable value
 if ( Sensor1 == -127 ) {
    lastSensor1 ;
    Sensor1 = lastSensor1;
  } else {
    lastSensor0 = Sensor0 ;
 }
    
    //Serial.println("Temperature sensor has failed");
    //lcd.clear();
    //lcd.setCursor(0,0);
    //lcd.print("Temperature Sensor");
    //lcd.setCursor(0,1);
    //lcd.print("Failure!!");
    //flushPump=0; // Reset flushPump back to zero
    //pumpOff();
    //digitalWrite(relay9, HIGH); // We directy shutdown the ball valve instead of going to the function.
    //while (true) {
      // Flash diagnostics. 2 x 2 second flashes, sensor failure
      //digitalWrite(LED_BUILTIN,LOW);delay(500); 
      //digitalWrite(LED_BUILTIN,HIGH);delay(2000);
      //digitalWrite(LED_BUILTIN,LOW);delay(500);
      //digitalWrite(LED_BUILTIN,HIGH);delay(2000);
      //digitalWrite(LED_BUILTIN,LOW);delay(5000);
    //}
 
  lcd.setCursor(0,0);
  lcd.print("Temp Out: ");
  lcd.print(sensors.getTempCByIndex(1));
  lcd.print("  ");
  //lcd.print(Sensor1);
  lcd.setCursor(0,1);
  lcd.print("Temp  In: ");
  lcd.print(sensors.getTempCByIndex(0));
  lcd.print("  ");
  //lcd.print(Sensor0);
  lcd.setCursor(0,2);
  lcd.print("Differential: ");
  lcd.print(SensorDifferential);
  lcd.setCursor(19,2); //Heart Beat
  lcd.print("*"); //Heart beat character

  ldrValue = analogRead(ldrPin); // read the value from the sensor
  //Serial.println(ldrValue); //prints the values coming from the sensor on the screen
  //Serial.print("Sensor Out: ");
  // Serial.print(round(sensors.getTempCByIndex(1))); // Why "byIndex"? 
  // Serial.print(" / In: ");
  // Serial.println(round(sensors.getTempCByIndex(0))); // Why "byIndex"? 
  //Serial.print("Sensor Differential: ");
  //Serial.println(SensorDifferential); // Why "byIndex"? 
  //Serial.print("Flush pump: ");
  //Serial.println(flushPump); // Why "byIndex"? 
  display_ldr(); 
  overRideValue = analogRead(overRidePin);
  // Serial.print("Overide: ");
  // Serial.println(overRideValue);

  // Here we provide for an override button to switch the pump on manually.
  if ( overRideValue < 10 ) {
      ballValveOpen();
      pumpOn();
      ballValveClose();
      } else {
      // Here we check the light level as we don't want the pump to run at night.
      if ( ldrValue > maxLdrValue ) {
        //Serial.print("LDR Enable: ");
        //Serial.println(ldrValue);
        // Enable ball valve
        ballValveOpen();
        if ( Sensor1 > Sensor0 ) {
           display_ldr();
           pumpOn();
           flushPump = 1;
           } else if (Sensor1 <= Sensor0 ) {
           display_ldr();
           pumpOff();
           } else {
           display_ldr();
           pumpOff();
        } // End nested if
    } else {
        display_ldr();
        pumpOff();
        //Serial.println("Pump Off ");
         // Close ball valve
        ballValveClose();
      } // End if
      //delay(250);
    time_now = millis(); 
     while(millis() < time_now + programDelayTime){
        //wait approx. [period] ms
    }
  }
 wdt_reset(); //Reset the watchdog
 //Serial.println("Reset Watchdog Timer - 1");
 // while(1); //Watchdog timer should get triggered here
 digitalWrite(LED_BUILTIN, LOW);
  lcd.setCursor(19,2); //Heart beat
  lcd.print(" "); //Heart Beat field clear
} // End loop
////////////////////////////////////////////////////////////////////////////////////////// 
void pumpOn() {
 // Pin for relay module set as output
 pinMode(relay8, OUTPUT);
 digitalWrite(relay8, LOW);
 digitalWrite(LED_BUILTIN, LOW);    // turn the LED off
 lcd.setCursor(0,3);
 lcd.print("Pump: On ");
 //Serial.println("Pump On "); 
 wdt_reset(); //Reset the watchdog
 //Serial.println("Reset Watchdog Timer - 2");
}

void pumpOff() {
 // Pin for relay module set as output
  pinMode(relay8, OUTPUT);
  digitalWrite(relay8, HIGH);
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off
  lcd.setCursor(0,3);
  lcd.print("Pump: Off ");
  //Serial.println("Pump Off ");
  wdt_reset(); //Reset the watchdog
  //Serial.println("Reset Watchdog Timer - 3");
 
}

void flushPipe() {
  if( flushPump == 1 ){
     // Once we get the signal to power off the pump we sleep for 10 seconds to give the panel time to flush any residual hot water from the pipes.
     //Serial.println("Panel Flush Delay: ");
     //Serial.println(panelFlush);
     //while (flushLoop < panelFlush ) {
        //flushLoop = flushLoop + 1;
      while (flushLoop > panelFlush ) {
        flushLoop = flushLoop - 1;
        lcd.setCursor(0,0);
        lcd.print("Temp Out: ");
        lcd.print(sensors.getTempCByIndex(1));
        lcd.setCursor(0,1);
        lcd.print("Temp  In: ");
        lcd.print(sensors.getTempCByIndex(0));
        lcd.setCursor(10,3);
        lcd.print(" Flush:   ");
        lcd.setCursor(18,3);
        lcd.print(flushLoop);
        //Serial.print("Pump Off in: "  );
        //Serial.println( flushLoop );
        time_now = millis(); 
        while(millis() < time_now + programDelayTime){
             //wait approx. [period] ms
             wdt_reset(); //Reset the watchdog
             //Serial.println("Reset Watchdog Timer - 4");
        }
      } // End while loop
     flushPump=0; // Reset flushPump back to zero
     flushLoop=8; // Reset flushLoop back to 8
     lcd.clear();
  } // End If statement
  pumpOff();

}

void display_ldr() {
  //Serial.println(ldrValue);
  lcd.setCursor(10,3);
  lcd.print("Light:  ");
  lcd.setCursor(17,3);
  lcd.print(ldrValue);
  wdt_reset(); //Reset the watchdog
  //Serial.println("Reset Watchdog Timer - 5");
}

void ballValveOpen() {
 //Serial.println(BV_STAT);
 pinMode(relay9, OUTPUT);
 digitalWrite(relay9, LOW);
 if ( BV_STAT == 1) {
    BV_STAT = 2;
    lcd.clear();
    lcd.print("Ball Valve Opening");
    time_now = millis();
    while(millis() < time_now + ballValveCycleTime){
        //wait approx. [period] ms
        lcd.setCursor(0,1);
        lcd.print((time_now + ballValveCycleTime) - millis());
        lcd.print("  ");
        wdt_reset(); //Reset the watchdog
        //Serial.println("Reset Watchdog Timer - 6");
     }
//Serial.println(BV_STAT);
lcd.clear();
 } 
 lcd.setCursor(17,1);
 lcd.print("V:O");
 BV_STAT = 2;
}

void ballValveClose() {
  //Serial.println(BV_STAT);
  if ( BV_STAT == 0 or BV_STAT == 2 ) {
    BV_STAT = 1;
    //Serial.println(BV_STAT);
    pinMode(relay9, OUTPUT);
    digitalWrite(relay9, HIGH);
    lcd.clear();
    lcd.print("Ball Valve Closing");
    time_now = millis();
    while(millis() < time_now + ballValveCycleTime) {
      lcd.setCursor(0,1);
      lcd.print((time_now + ballValveCycleTime) - millis());
      lcd.print("  ");
        wdt_reset(); //Reset the watchdog
        //Serial.println("Reset Watchdog Timer - 7");
    }

    lcd.setCursor(17,0);
    lcd.print("  ");
    lcd.clear();
    lcd.setCursor(17,1);
    lcd.print("V:X");
    } else if ( BV_STAT == 1 ) {
    lcd.setCursor(17,1);
    lcd.print("V:X");
  }
}

How much current do those relays draw?

90ma.

That's 180mA for both. Too much for the poor nano

This is quite similar to a project I did. I also used a pair of DS18b20 temp sensor's at about that distance.
I found them to be very finicky about how they are wired at those distances. Reflections on the bus turned out to be the biggest problem. Since it appears you have access to an oscilloscope that is the best way to "tune" the bus by adjusting resistor values so that the reflections don't interfere with the signal.

Below are a few tips I collected from various post's on the forum.

//  My tips for reliable DS18B20 bus:
//
//    Don't use parasite power if possible, its much less robust.
//
//    Use the standard multidrop connection, not a star network, 4k7 pullup at each end of the bus, 
//    add a 100nF decoupling capacitor between Vcc and ground at each sensor and a 100 ohm series resistor between Arduino pin and the bus.
//
//    Do not connect the bus ground to anything except the Arduino, sensors and decoupling caps
//
//  That should maximum the chance of good signaling. Ideally use twin-core shielded cable, or two twisted pairs (signal+ground, 5V+ground). 
//  Ribbon cable can work if the signal wire is sandwiched between two ground wires
//  to shield it.

These are relay modules the relay trigger is via an opto isolator

Yes but there is a 5V connection that draws current from the nano when the coils are energized.
You said 90mA, for two thats 180mA. That's too much

Thanx to all for he pointers. Some very useful information that I applied.

  1. The suggestion not to use a star configuration. I added another digital pin and separated the two sensors.
  2. Changed the resistors from 4k7 to 2k2 and added a 100 ohm resistor in series with the data pin.
    Still testing, but it has become a lot more stable. I also restored the external 5vdc power supply nd we are looking good.
    Thanx to all and have a good festive season.
1 Like

That by itself will have gone a long way to improving things. Let us know how it goes!

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