Issues with Millis function and sensors

I’m currently new using Arduino, and this is my first program. I have developed a autodosing system using arduino Nano which include the following components:

-3 peristaltic pumps (DC-12V/ea)
-1 PH sensor (PH4502C)
-1 (one) EC sensor
-2 (two) water pumps (AC)
-6 channel relay board
-Blue Serial IIC/I2C/TWI 2004 204 20X4 Character LCD Module Display

I had include a LCD display to shown the sensors readings and also display with graphics any activation on the peristaltic pumps. The PH sensor have been established to 7.00 as the base value, but additional .30 has been included to create a bundaries, meaning that if the PH readings get .30 below or over 7.00 (6.70 to 7.30) the peristaltic pumps and one of the water pumps, get activated by a relay system during 8 seconds to make the appropriate dosing to the water reservoir. The other water pump get activated every 10 minutes, for 1 minute, for water circulation purposes.

After several running and tests on the program, I have notice the following issues:

1-The sensors (PH and EC) readings jumps over values when the sensors have been introduced to the water reservoir.
2-The program stop running after 30 minutes (LCD clear all text or the LCD readings get freeze)
3-The graphic in the LCD when the PH sensor is below 6.70, get stock and it not clear away once it is calibrated.

I have been using the Millis function to address any timing matter, but for some reason some sensor’s reading failures start to showing up in this program

I include the program to open a discussion and have any feed back from the Arduino Forum.

/////////////////////////////////////////////////////////////////////////////////////
////////////////////////////EC Sensor Library////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

#include "DFRobot_EC.h"
#include <EEPROM.h>
#define EC_PIN A1
float voltage,ecValue,temperature = 25;
DFRobot_EC ec;


/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////LCD Library///////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include "Arduino.h"


const byte switchState = 0;
const int pump1 = 2;           //for PH down
const int pump2 = 3;           //for nutrients (EC / PPM)
const int pump3 = 4;           //for PH up
const int pump4 = 5;           //for nutrients circulation
const int pump5 = 6;           //Seedling circulation pump
//const int pump6 = 7;           //Seedling circulation pump
//const int lamps = 7;          //Lamps
//const int fans = 8;           //cooling fan (5v)


/////////////////////////////////////////////////////////////////////////////////////
/////////////////////PH Sensor Values and Set-up/////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

float calibration_value = 21.34-.18; // .68 Here we attend the calibration adding or deducting values
int phval = 0;
unsigned long int avgval;
int buffer_arr[10], temp;
int ph_Read = A7;


////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////PUMPS Values//////////////////////////////////////
          ///////////////////////////////////////////////////////////

unsigned long prev_Time_1 = 0;
unsigned long prev_Time_2 = 0;
unsigned long prev_Time_3 = 0;
unsigned long prev_Time_4 = 0; //Circulation each dosing
unsigned long prev_Time_5 = 0;
//unsigned long prev_Time_6 = 0; //Circulation each 60 min

const unsigned long inter_on = 8000;
const unsigned long inter_off = 32000;
const unsigned long inter_circulation_on = 60000;
const unsigned long inter_circulation_off = (60000*10);
const unsigned long inter_seedling_on = 60000;
const unsigned long inter_seedling_off = (60000*10);

byte pump1_state = HIGH;
byte pump2_state = HIGH;
byte pump3_state = HIGH;
byte pump4_state = HIGH;
byte pump5_state = HIGH;
//byte pump6_state = HIGH;

byte customChar0[8] = {  //Circulation//
  0b01110,
  0b10001,
  0b10001,
  0b10000,
  0b10000,
  0b10001,
  0b10001,
  0b01110
};
byte customChar1[8] = {  //Seedling//
  0b01110,
  0b10001,
  0b01001,
  0b00100,
  0b00010,
  0b10001,
  0b10001,
  0b01110
};
byte customChar2[8] = {  //Arrow Down//
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b11111,
  0b01110,
  0b00100
};
byte customChar3[8] = { //Arrow UP//
  0b00100,
  0b01110,
  0b11111,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100
};

void setup()
{
  Serial.begin(9600);
  ec.begin();
  while(!Serial);
  lcd.begin();
  lcd.createChar(0, customChar0); //Arrow UP//
  lcd.createChar(1, customChar1); //Arrow Down//
  lcd.createChar(2, customChar2); //Circulation//
  lcd.createChar(3, customChar3); //Seedling// 
  lcd.backlight();
  lcd.setCursor(2, 1);
  lcd.print("/./.ROOMMATE././");
  lcd.setCursor(2, 2);
  lcd.print("/////DOSING/////");
  delay(2000);
  lcd.clear();

  //pinMode(switchPHDWN,INPUT);
  digitalWrite(pump1,HIGH);
  pinMode(pump1,OUTPUT);
  digitalWrite(pump2,HIGH);
  pinMode(pump2,OUTPUT);
  digitalWrite(pump3,HIGH);
  pinMode(pump3,OUTPUT);
  digitalWrite(pump4,HIGH);
  pinMode(pump4,OUTPUT);
  digitalWrite(pump5,HIGH);
  pinMode(pump5,OUTPUT);
  //digitalWrite(pump6,HIGH);
  //pinMode(pump6,OUTPUT);
   }

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

  ////////EC Sensor Lecture///////////
  {
    static unsigned long timepoint = millis();
    if(millis()-timepoint>1000U)                  //time interval: 1s
    {
      timepoint = millis();
      voltage = analogRead(EC_PIN)/1024.0*5000;   // read the voltage
      Serial.print("voltage:");
      Serial.print(voltage);
      //temperature = readTemperature();          // read your temperature sensor to execute temperature compensation
      ecValue =  ec.readEC(voltage,temperature);  // convert voltage to EC with temperature compensation
      Serial.print("  temperature:");
      Serial.print(temperature,1);
      Serial.print("^C  EC:");
      Serial.print(ecValue,2);
      Serial.println("ms/cm");
    }
    ec.calibration(voltage,temperature);
 }
 
  ////////////PH Sensor Lecture////////////////
  
  for (int i = 0; i < 10; i++)
  {
    buffer_arr[i] = analogRead(A7);
    delay(100);
  }
  for (int i = 0; i < 9; i++)
  {
    for (int j = i + 1; j < 10; j++)
    {
      if (buffer_arr[i] > buffer_arr[j])
      {
        temp = buffer_arr[i];
        buffer_arr[i] = buffer_arr[j];
        buffer_arr[j] = temp;
      }
    }
   }
  avgval = 0;
  for (int i = 2; i < 8; i++)
    avgval += buffer_arr[i];
  float volt = (float)avgval * 6.00 / 1024 / 9;  //5.0 volts
  float ph_act = -5.70 * volt + calibration_value;
  Serial.print(" PH= ");
  Serial.print(ph_act);
  Serial.print("  ");
  Serial.println(millis());
  
  ////////////////////////////////////////////////////////////////////////////
  ///////////////////////////CALIBRATION//////////////////////////////////////
          ///////////////////////////////////////////////////////////
  
  float Set_PH = 7.0;    
  float Dose_PHAdj =.30;   

  float Set_EC = 1.5;
  float Dose_ECAdj =.20;
  
  ////////////////////////////////////////////////////////////////////////////
  /////////////////////////LCD DISPLAY INFORMATION////////////////////////////
          ///////////////////////////////////////////////////////////

 lcd.setCursor(0,0);
 lcd.print("PH Level=");
 lcd.setCursor(10,0);
 lcd.print(ph_act);
 lcd.setCursor(0,1);
 lcd.print("EC Level=");
 lcd.setCursor(10,1);
 lcd.print(ecValue);
 lcd.setCursor(0,2);
 lcd.print("PH Volt=");
 lcd.setCursor(9,2);

 if((pump5_state == HIGH) &&
   (current_Time - prev_Time_5 >= inter_seedling_off))
   {
    pump5_state = LOW;
    prev_Time_5 = current_Time;
    digitalWrite(pump5,pump5_state);
    Serial.print("PUMP5_ON!!Seedling");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(19,0);
    lcd.write((byte)1);  
   }
   else if
   ((pump5_state == LOW) &&
   (current_Time - prev_Time_5 >= inter_seedling_on))
   {
    pump5_state = HIGH;
    prev_Time_5 = current_Time;
    digitalWrite(pump5,pump5_state);
    Serial.print("PUMP5_OFF!!");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(19,0);
    lcd.print(" "); 
   }

  ////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////Circulation/////////////////////////////////
          ///////////////////////////////////////////////////////////

 if((pump4_state == HIGH) &&
   (current_Time - prev_Time_4 >= inter_circulation_off))
   {
    pump4_state = LOW;
    prev_Time_4 = current_Time;
    digitalWrite(pump4,pump4_state);
    Serial.print("PUMP4_ON!!Seedling");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(19,1);
    lcd.write((byte)0);  
   }
   else if
   ((pump4_state == LOW) &&
   (current_Time - prev_Time_4 >= inter_circulation_on))
   {
    pump4_state = HIGH;
    prev_Time_4 = current_Time;
    digitalWrite(pump4,pump4_state);
    Serial.print("PUMP4_OFF!!");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(19,1);
    lcd.print(" "); 
   }
   
/////////////////////////////////////////////////////////////////////////////
 ////////////////////////////Pump1_PH DOWN////////////////////////////////////
          ///////////////////////////////////////////////////////////
        
  if((ph_act >= (Set_PH+Dose_PHAdj)) && 
    (pump1_state == HIGH) &&
    (current_Time - prev_Time_1 >= (inter_off)))
    {
    pump1_state = LOW;
    prev_Time_1 = current_Time;
    digitalWrite(pump1,pump1_state);
    Serial.print("PUMP1_ON!!PH DOWN");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(18,0);
    lcd.write((byte)2);
    }
    else if
      ((pump1_state == LOW) &&
      (current_Time - prev_Time_1 >= inter_on))
      {    
      pump1_state = HIGH;
      prev_Time_1 = current_Time;
      digitalWrite(pump1,pump1_state);
      Serial.print("PUMP1_OFF");
      lcd.setCursor(18,0);
      lcd.print(" ");
      }

/////////////////////////////////////////////////////////////////////////////
 ////////////////////////////Pump3_PH UP////////////////////////////////////
          ///////////////////////////////////////////////////////////
        

  if((ph_act <= (Set_PH-Dose_PHAdj)) && 
    (pump3_state == HIGH) &&
    (current_Time - prev_Time_3 >= (inter_off)))
    {
    pump3_state = LOW;
    prev_Time_3 = current_Time;
    digitalWrite(pump3,pump3_state);
    Serial.print("PUMP1_ON!!PH DOWN");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(17,0);
    lcd.write((byte)3);
    }
    else if
      ((pump3_state == LOW) &&
      (current_Time - prev_Time_3 >= inter_on))
      {    
      pump3_state = HIGH;
      prev_Time_3 = current_Time;
      digitalWrite(pump3,pump3_state);
      Serial.print("PUMP1_OFF");
      lcd.setCursor(17,0);
      }


 ////////////////////////////////////////////////////////////////////////////
 /////////////////////////////Pump2_EC UP////////////////////////////////////
         ///////////////////////////////////////////////////////////

  if((ecValue <= (Set_EC-Dose_ECAdj))&& 
    (pump2_state == HIGH) &&
    (current_Time - prev_Time_2 >= inter_off))
    {
    pump2_state = LOW;
    prev_Time_2 = current_Time;
    digitalWrite(pump2,pump2_state);
    Serial.print("PUMP2_ON!!EC UP");
    Serial.print("-");
    Serial.println(millis());
    lcd.setCursor(18,1);
    lcd.write((byte)3);
    }
    else if
      ((pump2_state == LOW) &&
      (current_Time - prev_Time_2 >= inter_on))
      {
      pump2_state = HIGH;
      prev_Time_2 = current_Time;
      digitalWrite(pump2,pump2_state);
      Serial.print("PUMP1_OFF");
      lcd.setCursor(18,1);
      lcd.print(" ");
      }
 }
  1. consider using some kind of filter. I'd use, in this case, a Kalman Filter but a rolling average filter will work.

  2. Put some serial prints in your loop() to confirm there is an actual stoppage or some other thing be doing.

  3. nothing for you on 3.

You could simplify your code, and make it easier to debug with an array of pumps, and possibly a struct for each device’s parameters…

1 Like

Random behaviors come sometimes from power issues. How did you wire everything?

You are summing 6 values (index 2 to 7), your formula seems weird to calculate voltage

Thanks I will try to do that

and don´t forget to mention a time controlled FSM.

Thanks Idahowalker, I will take a look and apply your suggestions

Thanks J-M-L I will try to bring a schematic for to explain the connections