Help with a function that magically crashes the arduino?

Hi all

Hopefully an easy one here, but one that's had me scratching my head for a day now.

I have a simple application that does the following 3 things:
1.) Fades an LED up and down, with a 50 millis delay. This will eventually be a status LED.
2.) Captures a bunch of data from various sensors, and sends it over a 433Mhz LoRa radio to a RasPi, with a 10 minute delay.
3.) Test whether the soil moisture of a nearby plant is below a threshold percent, and if so, turn on a relay that controls a water pump. This is on a 1000 millis delay.

Simple enough. However this third function, Pump(), the one that controls the water pump, is causing a hell of a lot of problems. As soon as I call this function in my main loop, the arduino cycles twice and then crashes.

Here's the code with the function commented out:

//Arduino Raspberry Pi wireless Comunnication through LoRa - SX1278
//Sending Soil Moisture values from Arduino through Radio head LoRa without ACK

#include <Wire.h>
#include <SPI.h> //Import SPI library 
#include <RH_RF95.h> // RF95 from RadioHead Library 
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#include <avr/wdt.h> // WDT library (added Jan 30)

#define RFM95_CS 10 //CS if Lora connected to pin 10
#define RFM95_RST 9 //RST of Lora connected to pin 9
#define RFM95_INT 2 //INT of Lora connected to pin 2

// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 434.0

//set the sea level pressure?
#define SEALEVELPRESSURE_HPA (airPressure + 1)

#define UP 0
#define DOWN 1

Adafruit_BME280 bme;

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);


const byte pwmLED = 3;
int relay = 4;
volatile byte relayState = LOW;

// constants for min and max PWM
const int minPWM = 0;
const int maxPWM = 255;
// State Variable for Fade Direction
byte fadeDirection = UP;
// Global Fade Value
// but be bigger than byte and signed, for rollover
int fadeValue = 0;
// How smooth to fade?
byte fadeIncrement = 5;


int moistureLimit = 40;
int soilMoistureValue; //realtime value from sensor (analog)
int soilMoisturePercent; //digital mapped percent of moisture
int airTemperature; // air temp
int airPressure; // air pressure
int altitude; //altitude
int airHumidity; //air humidity
int lightVal;
int lightPercent;


const int AirValue = 600;   //resistance value of the air
const int WaterValue = 310;  //resistance value of water
const int BrightSun = 1100;   //value of LightVal in a bright day
const int DarkNight = 25;  //value of LightVal in a dark room

unsigned long startTime = 0;
unsigned long fadeInterval = 50; //LED Fade Interval
//unsigned long sensorInterval = 15000; //Interval test
unsigned long sensorInterval = 600000; //Interval for sending data to Raspi over Lora
unsigned long pumpInterval = 1000; //Interval between checking soil moisture and turning pump on and off
bool timeFlag = false;

unsigned long previousFadeMillis;
unsigned long previousSensorMillis;
unsigned long previousPumpMillis;

void setup()
{

  //Initialize Serial Monitor
  Serial.begin(9600);

  //wdt reset initialize
  wdt_enable(WDTO_1S); //added Jan 30

  // Reset LoRa Module
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  analogWrite(pwmLED, fadeValue);

  // Pin for relay module set as output
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);

  //Initialize LoRa Module
  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);
  }


  //Set the default frequency 434.0MHz
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }

  //Initialize the BME280 temp/pressure/humidity sensor
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  rf95.setTxPower(22, false); //Transmission power of the Lora Module

  //call Sensor once at 0 seconds
  Values();
  Sensor();
}

void Values() {
  soilMoistureValue = analogRead(A0);  // Soil Moisture Value
  soilMoisturePercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100); // Soil Moisture Percent
  airTemperature = bme.readTemperature(); // Air Temperature Value
  airPressure = bme.readPressure() / 100.0F; // Air Pressure Value
  altitude = bme.readAltitude(SEALEVELPRESSURE_HPA); // Approximate Altitude
  airHumidity = bme.readHumidity(); // Air Humidity Value
  lightVal = analogRead(A1); // Raw Light Sensor
  lightPercent = map(lightVal, DarkNight, BrightSun, 0, 100); // Soil Moisture Percent
}

void Fade(unsigned long thisMillis) {

  if (thisMillis - previousFadeMillis >= fadeInterval) {
    // yup, it's time!
    if (fadeDirection == UP) {
      fadeValue = fadeValue + fadeIncrement;
      if (fadeValue >= maxPWM) {
        // At max, limit and change direction
        fadeValue = maxPWM;
        fadeDirection = DOWN;
      }
    } else {
      //if we aren't going up, we're going down
      fadeValue = fadeValue - fadeIncrement;
      if (fadeValue <= minPWM) {
        // At min, limit and change direction
        fadeValue = minPWM;
        fadeDirection = UP;
      }
    }
    // Only need to update when it changes
    analogWrite(pwmLED, fadeValue);

    // reset millis for the next iteration (fade timer only)
    previousFadeMillis = thisMillis;
  }
}

void Sensor() {
  //debugging
  Serial.print("Soil Moisture Value: ");
  Serial.println(soilMoistureValue);

  if (soilMoisturePercent > 100)
  {
    Serial.print("Soil Moisture Percentage: ");
    Serial.println("100 %");
  }
  else if (soilMoisturePercent < 0)
  {
    Serial.print("Soil Moisture Percentage: ");
    Serial.println("0 %");
  }
  else if (soilMoisturePercent > 0 && soilMoisturePercent < 100)
  {
    Serial.print("Soil Moisture Percentage: ");
    Serial.print(soilMoisturePercent);
    Serial.println("%");
  }

  Serial.print("Temperature: ");
  Serial.print(airTemperature);
  Serial.println("*C");

  Serial.print("Pressure: ");
  Serial.print(airPressure);
  Serial.println("hPa");

  Serial.print("Approx. Altitude: ");
  Serial.print(altitude);
  Serial.println("m");

  Serial.print("Humidity: ");
  Serial.print(airHumidity);
  Serial.println("%");

  Serial.print("Light Percent: ");
  Serial.print(lightPercent);
  Serial.println("%");

  Serial.println();

  //end debugging

  char buf[80] = {0}; //80 byte message
  sprintf(buf, "%d|%d|%d|%d|%d|%d", soilMoisturePercent, airTemperature, airPressure, altitude, airHumidity, lightPercent); //can add in new variables here, but don't forget to add another|%d
  rf95.send((uint8_t *)buf, 80); // send integer measured value as C-string, six byte packet
}

void TimeSensor(unsigned long thisMillis) {

  if (thisMillis - previousSensorMillis >= sensorInterval) {
    //call sensor function here
    Sensor();
    // reset millis for the next iteration (sensor timer only)
    previousSensorMillis = thisMillis;
  }

}

void Pump(unsigned long thisMillis) {
  if (thisMillis - previousPumpMillis >= pumpInterval) {

    //debugging
    Serial.print("Soil Moisture Percentage: ");
    Serial.print(soilMoisturePercent);
    Serial.println("%");
    Serial.println(soilMoistureValue);
    //end debugging

    if (soilMoisturePercent <= moistureLimit) {
      startWatering();
    } else {
      stopWatering();
    }
    // reset millis for the next iteration (pump timer only)
    previousPumpMillis = thisMillis;
  }
}

void startWatering() {
  digitalWrite(relay, LOW);
  Serial.println("pumping water now");
  delay(100);
}

void stopWatering() {
  digitalWrite(relay, HIGH);
  Serial.println("stopping pumping water now");
  delay(100);
}

void loop()
{
  unsigned long currentMillis = millis();

  Values();
  Fade(currentMillis);
//  Pump(currentMillis);
  TimeSensor(currentMillis);

  wdt_reset(); //wdt reset - added Jan 30

}

Any ideas on what could be causing this? I'm honestly at a loss for options here!

Cheers
ZF

i don't see a "Pump" function in the file you posted.

However this third function, Pump(), the one that controls the water pump, is causing a hell of a lot of problems. As soon as I call this function in my main loop, the arduino cycles twice and then crashes.

I would say it is interference from the pump. We see this so many times here. People expect to run a motor without taking any precautions with the power supply decoupling and noise suppression.

Most likely caused by either the pump or the relay, does the problem go away if you disconnect the relay from pin 4?

david_2018:
Most likely caused by either the pump or the relay, does the problem go away if you disconnect the relay from pin 4?

It absolutely does!

So it does sound like it's some sort of EMI issue with the relay. I really don't know much about interference of this sort, any ideas on how to start solving it?

What specific relay are you using, and how is it connected to the arduino? Hopefully you are not trying to power the relay from the arduino.

Another test you can do is to connect the relay, but leave the pump disconnected, and see if it is the relay or the pump itself that is causing the problem.

david_2018:
What specific relay are you using, and how is it connected to the arduino? Hopefully you are not trying to power the relay from the arduino.

Another test you can do is to connect the relay, but leave the pump disconnected, and see if it is the relay or the pump itself that is causing the problem.

This is legitimately fascinating, I didn't stop to consider that the issue could be interference!

So the relay itself is SRD-05VDC-SL-C 5V, its connected with jumpers to pin4, gnd, and vcc of a breadboard. The pump is powered via an external 5v power unit.

However absolutely worth mentioning is that this whole arduino circuit is currently running as a prototyping on a breadboard next to the plant that I'm auto-watering... which happens to be sitting next to a speaker that has a massive fucking magnet in it...

I probably should test this away from the speaker. I'll also give it a shot without the pump attached and see whats what.

This absolutely gives me a good direction to go in search of a fix!

Unless your speaker magnet is moving, the Arduino could care less.

Paul

Paul_KD7HB:
Unless your speaker magnet is moving, the Arduino could care less.

I think he means the plant.

First thing to check is have you got a reverse biased diode across the relay.
Then look to see how it is powered, is it drawing too much current, do you have a relay driver, if so what sort, if not you might have found your problem.