Flow Meter in GUI doesn't work

Hello All,

So I am working on a project that uses an Arduino for the brunt of my operation for the different components I am used. I have 3 motors that pump water from one place to another and then some motorized ball valves that open up to drain the water back to where the pumps are. Then I have 2 ultrasonic sensors that I use to measure the depth level of the water in each container. I also have flow meters hooked up to each pump and each valve making for a total of 5 flow meters.

My question is that I have everything else working but when introducing the Flow meter code into my Arduino code it will stop the serial printing of data due to the interrupt and it never leaving the ISR for counting pulses to calculate the flow data.

The thing that encompasses all of this is a rasperrypi that I've made a GUI in using the tkinter library in python. That part isn't really having issues. I will post both my arduino code and python code below and I would appreciate any feedback that will allow me to measure the flow meter data and still allow me to use the other functions in the code since they are being utilized in the GUI to open these valves or turn on these pumps. Thank you

Arduino:

//Variables for Pumps & Valves
int receivedChar;
int receivedChar1;
boolean newData = false;
int count = 0;

//Variables for Flow Meters
volatile int count1;


//Pins for sensors
const int trigPin = 51;
const int echoPin = 50;
const int trigPin1 = 53;
const int echoPin1 = 52;

//Pins for FlowMeters
const int flowPin = 2;

//Variables for Sensors
long duration;
int distance;
long duration1;
int distance1;

//Variables for Flow Meters
double flowRate;

//Function to setup pins
void setup() 
{

  Serial.begin(9600);

  pinMode(3, OUTPUT); //Pump 1
  pinMode(5, OUTPUT); //Pump 2
  pinMode(6, OUTPUT); //Pump 3
  pinMode(7, OUTPUT); //Geist Valve
  pinMode(8, OUTPUT); //Quarry Valve
  pinMode(trigPin, OUTPUT); //Ultrasonic Trig Pin
  pinMode(echoPin, INPUT); //Ultrasonic Echo Pin
  pinMode(trigPin1, OUTPUT); //Ultrasonic Trig Pin
  pinMode(echoPin1, INPUT); //Ultrasonic Echo Pin
  pinMode(flowPin, INPUT_PULLUP); //Flow meter pin
  attachInterrupt(0, Flow, RISING); //Configure interrupt to run Flow function
    
}//end setup

//Main loop
void loop() 
{
  recvInfo();
  lightLED(); //Function for motors
  ultrasonicSensor(); //Geist sensor function
  ultrasonicSensor1(); //Quarry sensor function
  count1 = 0; //count variable for flow meters
  
  interrupts(); //Enable interrupts
  delay(250); //short delay
  noInterrupts(); //Disable Interrupts
  
  
  flowRate = (count1 * 2.25); //Take pulses and multiply by 2.25mL
  flowRate = flowRate * 60; //Convert seconds to minutes
  flowRate = flowRate / 1000; //Convert mL to Liters (L / Min)
  
  Serial.println(flowRate); //Print flowRate to Serial
  Serial.flush();
}//end loop


void recvInfo() 
{

  while (Serial.available() > 0) 
  {

    receivedChar = Serial.read();
    newData = true;
    count++;
    
    if(count == 2)
    {
    newData = false;
    }//end if
  
  }//end while
  
}//end recvInfo()

//Motor function
void lightLED() 
{

  int led = (receivedChar - '0');

    if(newData == true) 
    {
      digitalWrite(led, HIGH);
    }//end HIGH if
    if(newData == false)
    {
     digitalWrite(led, LOW);
     count = 0;
    }//end LOW if
  
  
}//end lightLED()

void ultrasonicSensor()
{
  //Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);

  //Sets the trigPin on HIGH state for 10 ms
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  //Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);

  //Calculating distance
  distance = duration*0.034/2;

  //Prints the distance to the Serial Monitor
  //Serial.print("Distance: ");
  Serial.println(distance);
  delay(250);
  Serial.flush();
 
}//end ultrasonicSensor()

void ultrasonicSensor1()
{
  //Clears the trigPin
  digitalWrite(trigPin1, LOW);
  delayMicroseconds(2);

  //Sets the trigPin on HIGH state for 10 ms
  digitalWrite(trigPin1, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);

  //Reads the echoPin, returns the sound wave travel time in microseconds
  duration1 = pulseIn(echoPin1, HIGH);

  //Calculating distance
  distance1 = duration1*(0.034/2);

  //Prints the distance to the Serial Monitor
  //Serial.print("Distance1: ");
  Serial.println(distance1);
  delay(250);
  Serial.flush();
 
}//end ultrasonicSensor1()

//Function for flow meters
void Flow()
{
  count1++; //Every time this function is called, increment count1 by 1
}

Python:

from tkinter import *
import serial
import time
import threading

ser = serial.Serial('/dev/ttyACM0', 9600)

class Window(Frame):

    def __init__(self, master = None):
        Frame.__init__(self, master)

        self.master = master
        self.init_window()

    #Window Function
    def init_window(self):

        self.master.title("GUI")
        self.pack(fill=BOTH, expand=1)

        #Start/Stop Pump 1 button on GUI                   
        pump1 = Button(self, text="Pump 1", command=self.Pump1)
        pump1.place(x=10, y=100)

        #Start/Stop Pump 2 button on GUI
        pump2 = Button(self, text="Pump 2", command=self.Pump2)
        pump2.place(x=150, y=100)
        
        #Start/Stop Pump 3 button on GUI
        pump3 = Button(self, text="Pump 3", command=self.Pump3)
        pump3.place(x=290, y=100)
        
        #Open/Close Geist Valve on GUI
        GeistValve = Button(self, text="Geist", command=self.Valve1)
        GeistValve.place(x=10, y=150)
        
        #Open/Close Quarry Valve on GUI
        QuarryValve = Button(self, text="Quarry", command=self.Valve2)
        QuarryValve.place(x=150, y=150)
        
        #Input Box for Ultrasonic Sensor (Geist1)
        serial_data1 = ser.readline(4)
        Sensor1 = Text(self, width=4, height=1)
        Sensor1.place(x=10, y=180)
        Sensor1.insert(END, serial_data1)
        
        #update Sensor1 Value
        def update_Sensor1():
            serial_data1 = ser.readline(4)
            Sensor1.delete("1.0","end")
            Sensor1.insert(END, serial_data1)
            Sensor1.after(1000,update_Sensor1)
        Sensor1.after(1000,update_Sensor1)
        
        #Input Box for Ultrasonic Sensor (Geist2)
        serial_data2 = ser.readline(8)
        Sensor2 = Text(self, width=4, height=1)
        Sensor2.place(x=150, y=180)
        Sensor2.insert(END, serial_data2)
        
        #update Sensor2 Value
        def update_Sensor2():
            serial_data2 = ser.readline(8)
            Sensor2.delete("1.0", "end")
            Sensor2.insert(END, serial_data2)
            Sensor2.after(1000,update_Sensor2)
        Sensor2.after(1000,update_Sensor2)
        
        #Input Box for Flow Meter 1
        #serial_data5 = ser.readline(12)
        #FlowMeter1 = Text(self, width=4, height=1)
        #FlowMeter1.place(x=10, y=210)
        #FlowMeter1.insert(END, serial_data5)
        
        #update FlowMeter1 Value
        #def update_FlowMeter1():
        #    serial_data5 = ser.readline(12)
        #    FlowMeter1.delete("1.0", "end")
        #    FlowMeter1.insert(END, serial_data5)
        #    FlowMeter1.after(1000,update_FlowMeter1)
        #FlowMeter1.after(1000,update_FlowMeter1)
        
        
        #Quit button on GUI
        quitButton = Button(self, text="Quit", command=self.client_exit)
        quitButton.place(x=350, y=270)

    
    #Function to exit window when quit button is pressed
    def client_exit(self):
        exit()

    #Function for starting pump 1
    def Pump1(self):
        ser.write('4'.encode())

    #Function for starting pump 2
    def Pump2(self):
        ser.write('5'.encode())

    #Function for starting pump 3
    def Pump3(self):
        ser.write('6'.encode())
        
    #Function for opening Geist Valve
    def Valve1(self):
        ser.write('7'.encode())
        
    #Function for opening Quarry Valve
    def Valve2(self):
        ser.write('8'.encode())

root = Tk()
root.geometry("400x300") #GUI size

app = Window(root)

root.mainloop()

That method of counting pulses absolutely guarantees that you will miss pulses.

You have interrupts turned off most of the time. Yet, you expect to send and receive serial data with interrupts disabled. That is NOT going to happen.

count1 is incremented by the ISR, and used by loop(). Yet, it is not declared volatile, so loop() has no idea that the variable was updated by other code.

Leave interrupts on ALL the time, except for the VERY brief time you make a copy of count1 and reset it to 0.

//Pins for FlowMeters
const int flowPin = 2;

So your intention is to simply measure the total quantity of water flowing in the whole system, without being interested in the flow though the individual sensors. Is that correct?

This seems crazy

  interrupts(); //Enable interrupts
  delay(250); //short delay
  noInterrupts(); //Disable Interrupts

Do what @PaulS said in the last line of Reply #1

...R

PaulS:
That method of counting pulses absolutely guarantees that you will miss pulses.

You have interrupts turned off most of the time. Yet, you expect to send and receive serial data with interrupts disabled. That is NOT going to happen.

count1 is incremented by the ISR, and used by loop(). Yet, it is not declared volatile, so loop() has no idea that the variable was updated by other code.

Leave interrupts on ALL the time, except for the VERY brief time you make a copy of count1 and reset it to 0.

So you are saying to do something like this in the main loop:

recvInfo();
  lightLED(); //Function for motors
  ultrasonicSensor(); //Geist sensor function
  ultrasonicSensor1(); //Quarry sensor function
  noInterrupts(); //Disable Interrupts
  count1 = 0; //count variable for flow meters
  
  interrupts(); //Enable Interrupts
  
  
  flowRate = (count1 * 2.25); //Take pulses and multiply by 2.25mL
  flowRate = flowRate * 60; //Convert seconds to minutes
  flowRate = flowRate / 1000; //Convert mL to Liters (L / Min)
  
  Serial.println(flowRate); //Print flowRate to Serial
  Serial.flush();
}//end loop

You are pointing in the right direction but all this code does is to lose whatever number was in count1 by setting the value back to zero

 noInterrupts(); //Disable Interrupts
  count1 = 0; //count variable for flow meters
 
  interrupts(); //Enable Interrupts

You need something like

 noInterrupts(); //Disable Interrupts
  latestCount1 = count1;
  count1 = 0; //count variable for flow meters
 
  interrupts(); //Enable Interrupts

...R