Something is terribly wrong with my code

A friend and I have been working on a bottle filling machine using Arduino and sensor. It was working fine until the reading coming from the sensor started kind off sometimes hanging (visible on the screen) leading to overflow and underflow sometimes. Even some garbage is sometimes printed on the screen. When we try to calibrate it to fill 1Ltr, sometimes its 1, sometimes 1.5, sometimes 0.5. Why could that be? We are using it with a I2C 16x2 LCD screen and a 4x3 matrix keypad. We got the code sample online and below is the slightly modified version of the flow part used in our code.

while(totalMilliLitres < finalValue)
          {
            digitalWrite(SolenoidPumpPin, HIGH);
            if ((millis() - oldTime) > 1000) 
            
              {
              detachInterrupt(sensorInterrupt);
              flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
              oldTime = millis();
              flowMilliLitres = (flowRate / 60) * 1000;
              totalMilliLitres += flowMilliLitres;
              unsigned int frac;
              lcd.setCursor(10, 1);
              lcd.print(totalMilliLitres);
              pulseCount = 0;
              }
              attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
          }
          digitalWrite(SolenoidPumpPin, LOW);
          //VolumeSet = 0;
          totalMilliLitres = 0;
          /*else 
          {
              digitalWrite(SolenoidPumpPin, HIGH);
              VolumeSet = 0;
          }*/
        
        }


full code pls

1 Like

here you go

//screen and keyboard code starts
#include <Keypad.h>
#include <LiquidCrystal_I2C.h> 
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); 

#include<stdio.h>
const int ROW_NUM = 4; 
const int COLUMN_NUM = 3; 
char keys[ROW_NUM][COLUMN_NUM] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte pin_rows[ROW_NUM] = {9,8,7,6}; 
byte pin_column[COLUMN_NUM] = {5,4,3}; 
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

char volume[4];
byte volumeCount = 0;
bool edit = 0;
int finalValue = 0;
//screen and keyboard code ends

//flow sensor and other machinery code starts

int flowsensor = 2; // Sensor Input
int sensorInterrupt = 0;
unsigned int SetPoint = 400;
String code = "";
float calibrationFactor = 10;
volatile byte pulseCount = 0;
float flowRate = 0.0;
unsigned int flowMilliLitres = 0;
unsigned long totalMilliLitres = 0, VolumeSet = 0;
unsigned long oldTime;

int SolenoidPumpPin=11; //was 11 with original design

// constants won't change. They're used here to set pin numbers:
const int buttonPin1 = 12;     // the number of the pushbutton pin for start flow

// variables will change:
int buttonState1 = 0;         // variable for reading the pushbutton status

void pulseCounter() {
 
  pulseCount++;
}

//flow sensor and other machinery code ends

void setup() 
{
  // screen code starts
lcd.init(); 
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Volume        ml");
   lcd.setCursor(0, 1); 
   lcd.print("Filled        ml");
   // screen code ends


  //sensor code starts
  pinMode(SolenoidPumpPin, OUTPUT);
  digitalWrite(SolenoidPumpPin, LOW); //Switch Solenoid ON

totalMilliLitres = 0;
  pinMode(flowsensor, INPUT);
   digitalWrite(flowsensor, HIGH); 
attachInterrupt(sensorInterrupt, pulseCounter, FALLING); // Setup Interrupt

   //sensor code ends

}


void loop() 
{

  buttonState1 = digitalRead(buttonPin1);
  
  char key = keypad.getKey();
  
  if(key) // check if any key was pressed
  {
    if(key == '*') // if * was pressed switch to edit mode
    {
        lcd.setCursor(0,0); // set your cursor at columnt 0, row 0
        lcd.clear();//new
        lcd.print("Enter volume: ");
        edit = true;
        lcd.setCursor(0,1); // set your cursor to second row 
        volumeCount = 0;
        volume[0] = '0';
        volume[1] = '0';
        volume[2] = '0';
        volume[3] = '0';
    }
    
    if(edit && volumeCount < 4 && key != '*' && key != '#') // enter edit mode
    {
        volume[volumeCount] = key; // save key to a char array
        lcd.setCursor(volumeCount,1);  // set your cursor to the next position
        lcd.print(volume[volumeCount]); // print the pressed button to lcd
        volumeCount++; // increment the array index (cursor position)
    }
    
    if(volumeCount == 4 || key == '#') // array.length == 3 OR you pressed #
    {
      if (key == '#' && volumeCount != 4)
      {
        volume[volumeCount] = '\0';
        edit = false; // disable edit mode

        volumeCount = 0; // reset your counter
        //lcd.setCursor(0,0);
        lcd.clear();//new

        lcd.setCursor(0, 0); 
        lcd.print("Volume        ml");
        lcd.setCursor(0, 1); 
        lcd.print("Filled        ml");
        lcd.setCursor(10, 0);
        
        lcd.print(volume); //new
        finalValue = atoi(volume); // save your entered value for further usage
        //volume[0] = '0';
        //volume[1] = '0';
        //volume[2] = '0';
      }
      else
      {
        edit = false; // disable edit mode

        
        volumeCount = 0; // reset your counter
        //lcd.setCursor(0,0);
        lcd.clear();//new
        
        lcd.setCursor(0,0);
        lcd.clear();//new

        lcd.setCursor(0, 0); 
        lcd.print("Volume        ml");
        lcd.setCursor(0, 1); 
        lcd.print("Filled        ml");
        lcd.setCursor(10, 0);
        
        lcd.print(volume); //new
        finalValue = atoi(volume); // save your entered value for further usage
        //volume[0] = '0';
        //volume[1] = '0';
        //volume[2] = '0';

                  
        }
      }
        
    }

    //sensor and other machine code starts
    buttonState1 = digitalRead(buttonPin1);
        if (buttonState1 == HIGH)
        {            
          lcd.clear();//new
            
            lcd.setCursor(0,0);
            lcd.clear();//new
    
            lcd.setCursor(0, 0); 
            lcd.print("Volume        ml");
            lcd.setCursor(0, 1); 
            lcd.print("Filled        ml");
            lcd.setCursor(10, 0);
            
            lcd.print(volume);
            //delay(100);//needed with 12v adaptor

          
          //pulse_freq = 0;
          //flow = 1.4 * pulse_freq;
          //VolumeSet = finalValue;
          
          while(totalMilliLitres < finalValue)
          {
            digitalWrite(SolenoidPumpPin, HIGH);
            if ((millis() - oldTime) > 1000) 
            
              {
              detachInterrupt(sensorInterrupt);
              flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
              oldTime = millis();
              flowMilliLitres = (flowRate / 60) * 1000;
              totalMilliLitres += flowMilliLitres;
              unsigned int frac;
              lcd.setCursor(10, 1);
              lcd.print(totalMilliLitres);
              pulseCount = 0;
              }
              attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
          }
          digitalWrite(SolenoidPumpPin, LOW);
          //VolumeSet = 0;
          totalMilliLitres = 0;
          /*else 
          {
              digitalWrite(SolenoidPumpPin, HIGH);
              VolumeSet = 0;
          }*/
        
        }

          
          
          /*while(flow<=(finalValue))//+1 to match the figures and be on the safe side
          {
            digitalWrite(SolenoidPumpPin, LOW);  
            lcd.setCursor(10, 1);
            int finalflow = flow; //just so we can print it in int format without decimal
            lcd.print(finalflow);
            flow = 1.4 * pulse_freq;
          }
          digitalWrite(SolenoidPumpPin, HIGH);
          lcd.setCursor(10, 1);
          //int finalflow = flow; //required only if we are printing finalflow in next line
          lcd.print(volume); //for hack sake and visuals sake we will print volume here instead of final flow
        }*/
  //sensor and other machinery code ends
  
  
  
}

You are using a nano with a 328 uC on it?
There is a lot of multiplication and division going on after you start your pump.

This might take a couple hundred clocks to complete. IDK if 15-20 milliseconds makes a difference there. Same with the print to lcd. Were I doing this, at run time, I'd turn on the pump, monitor flow rate until target met, then turn off the pump, then I'd handle everything else when the pump wasn't running.

Here it is had to upload it again after removing redundant lines

//screen and keyboard code starts
#include <Keypad.h>
#include <LiquidCrystal_I2C.h> 
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); 

#include<stdio.h>
const int ROW_NUM = 4; 
const int COLUMN_NUM = 3; 
char keys[ROW_NUM][COLUMN_NUM] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte pin_rows[ROW_NUM] = {9,8,7,6}; 
byte pin_column[COLUMN_NUM] = {5,4,3}; 
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

char volume[4];
byte volumeCount = 0;
bool edit = 0;
int finalValue = 0;
//screen and keyboard code ends

//flow sensor and other machinery code starts

int flowsensor = 2; // Sensor Input
int sensorInterrupt = 0;
unsigned int SetPoint = 400;
String code = "";
float calibrationFactor = 10;
volatile byte pulseCount = 0;
float flowRate = 0.0;
unsigned int flowMilliLitres = 0;
unsigned long totalMilliLitres = 0, VolumeSet = 0;
unsigned long oldTime;

int SolenoidPumpPin=11; 

// constants won't change. They're used here to set pin numbers:
const int buttonPin1 = 12;     // the number of the pushbutton pin for start flow

// variables will change:
int buttonState1 = 0;         // variable for reading the pushbutton status

void pulseCounter() {
 
  pulseCount++;
}

//flow sensor and other machinery code ends

void setup() 
{
  // screen code starts
lcd.init(); 
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Volume        ml");
   lcd.setCursor(0, 1); 
   lcd.print("Filled        ml");
   // screen code ends


  //sensor code starts
  pinMode(SolenoidPumpPin, OUTPUT);
  digitalWrite(SolenoidPumpPin, LOW); //Switch Solenoid ON

totalMilliLitres = 0;
  pinMode(flowsensor, INPUT);
   digitalWrite(flowsensor, HIGH); 
attachInterrupt(sensorInterrupt, pulseCounter, FALLING); // Setup Interrupt

   //sensor code ends

}


void loop() 
{

  buttonState1 = digitalRead(buttonPin1);
  
  char key = keypad.getKey();
  
  if(key) // check if any key was pressed
  {
    if(key == '*') // if * was pressed switch to edit mode
    {
        lcd.setCursor(0,0); // set your cursor at columnt 0, row 0
        lcd.clear();//new
        lcd.print("Enter volume: ");
        edit = true;
        lcd.setCursor(0,1); // set your cursor to second row 
        volumeCount = 0;
        volume[0] = '0';
        volume[1] = '0';
        volume[2] = '0';
        volume[3] = '0';
    }
    
    if(edit && volumeCount < 4 && key != '*' && key != '#') // enter edit mode
    {
        volume[volumeCount] = key; // save key to a char array
        lcd.setCursor(volumeCount,1);  // set your cursor to the next position
        lcd.print(volume[volumeCount]); // print the pressed button to lcd
        volumeCount++; // increment the array index (cursor position)
    }
    
    if(volumeCount == 4 || key == '#') // array.length == 3 OR you pressed #
    {
      if (key == '#' && volumeCount != 4)
      {
        volume[volumeCount] = '\0';
        edit = false; // disable edit mode

        volumeCount = 0; // reset your counter
        //lcd.setCursor(0,0);
        lcd.clear();//new

        lcd.setCursor(0, 0); 
        lcd.print("Volume        ml");
        lcd.setCursor(0, 1); 
        lcd.print("Filled        ml");
        lcd.setCursor(10, 0);
        
        lcd.print(volume); //new
        finalValue = atoi(volume); // save your entered value for further usage
        //volume[0] = '0';
        //volume[1] = '0';
        //volume[2] = '0';
      }
      else
      {
        edit = false; // disable edit mode

        
        volumeCount = 0; // reset your counter
        //lcd.setCursor(0,0);
        lcd.clear();//new
        
        lcd.setCursor(0,0);
        lcd.clear();//new

        lcd.setCursor(0, 0); 
        lcd.print("Volume        ml");
        lcd.setCursor(0, 1); 
        lcd.print("Filled        ml");
        lcd.setCursor(10, 0);
        
        lcd.print(volume); //new
        finalValue = atoi(volume); // save your entered value for further usage
        //volume[0] = '0';
        //volume[1] = '0';
        //volume[2] = '0';

                  
        }
      }
        
    }

    //sensor and other machine code starts
    buttonState1 = digitalRead(buttonPin1);
        if (buttonState1 == HIGH)
        {            
          lcd.clear();//new
            
            lcd.setCursor(0,0);
            lcd.clear();//new
    
            lcd.setCursor(0, 0); 
            lcd.print("Volume        ml");
            lcd.setCursor(0, 1); 
            lcd.print("Filled        ml");
            lcd.setCursor(10, 0);
            
            lcd.print(volume);


          
          while(totalMilliLitres < finalValue)
          {
            digitalWrite(SolenoidPumpPin, HIGH);
            if ((millis() - oldTime) > 1000) 
            
              {
              detachInterrupt(sensorInterrupt);
              flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
              oldTime = millis();
              flowMilliLitres = (flowRate / 60) * 1000;
              totalMilliLitres += flowMilliLitres;
              unsigned int frac;
              lcd.setCursor(10, 1);
              lcd.print(totalMilliLitres);
              pulseCount = 0;
              }
              attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
          }
          digitalWrite(SolenoidPumpPin, LOW);
          //VolumeSet = 0;
          totalMilliLitres = 0;

        
        }

          
          
  
  
  
}

Who's 328uC and what's its problem?

Which Arduino do you have?

Nano, 5V. I get it, you saying its processor is too slow for it?

There's a whole bunch of Nanos. Do you have a link of the page where you bought it?

Not related but is there a good reason the "attachInterrupt(sensorInterrupt, pulseCounter, FALLING);" if outside the "is ((millis() - oldTime) > 1000)" clause but with the same indentation ?

I earlier had it within the if statement, it made no difference

Procured these some time back, I couldn't tell where

code uploads when I select "old bootloader"

Ok I don't want to confuse you then.
Instead focus on what you should be doing when you need to run the pump.
How long should the pump run?
How do you know when it's run that long?

1 Like

I moved the pump start line just before the while loop starts, but the hanging is still there leading to over flow

Go back one post, help me with those questions.

1 Like

i don't know what's happening, I try to edit my posts, then they just vanish. Can you still see my last post?

It's probably just the code.

Let's try an experiment:

  1. Make a new sketch
  2. Don't worry about calibration, the lcd, or the keypad
  3. Just use the pump, the flowmeter, and the relay with your Nano
  4. When the program begins, have it run the pump for something like 100 pulses
  5. Then wait 5 seconds
  6. Then run again
  7. Make sure you are getting the same amount of water each time
  8. Post the code when it works

No, but I'm sure there's a reason that can be figured out later.

Hi, @mountainrock
Welcome to the forum.

Can we please have a circuit diagram?
An image of a hand drawn schematic will be fine, include ALL power supplies, component names and pin labels.

Can you try a 10K pullup on the flow sensor output, the internal pullups may not be strong enough.
How much wire have you between the flow sensor and the Nano?

Can you post some images of your project, so we can see your component layout?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Do you literally mean it worked, was working fine until one day it was no longer working?

Focus on what changed.

If it is the same software, you should be chasing hardware geese…

a7