Interrupts Problem with Flow sensor

I try to write code including flow sensor, pressure sensor and pump. I wrote the code. But When I use interrupt , code stop. I used functions in " void loop()" . I moved the interrupt code ( flow_control) between void setup and void loop. But I can see outputs in serial monitor but I cannot see on lcd. Could you help me fix the problem ?

 #include <Wire.h> //I2C lib
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
 // LCD lib
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

const int pot_pin = A0;
const int pump_pwm= 3;

int press_pin =A1;

//flowmeter parameters
int flowPin = 2;  // input pin on arduino D2

double flowRate;   // value intented to calculate
double flowR; // flow value in lt
double totalFlow; // total output of flow from system

byte sensorInterrupt = 0; // interrupt 0 on D2 pin Arduino Nano

volatile int count; ////integer needs to be set as volatile to ensure it updates correctly during the interrupt process. 

int pot_init= 0;
int pump_init= 0;
int percentValue =0;



void setup() {
 
  
  
  lcd.begin(20,4);  // A4 - A5 connection SDA - SCL
  lcd.backlight();
  Serial.begin(9600); 
   
  pinMode( flowPin,INPUT); // Set D2 pin as an input
  
  attachInterrupt(sensorInterrupt,Flow,RISING); // Configures interrupt 0 ( pin D2 on Arduino Nano ) to run function "Flow" 
}

void flow_control(void) {
  
  count = 0; // reset counter so it could start counting from 0
  
  interrupts(); // enables interrupts on arduino nano
  delay(1000); // wait 1000 msec
  noInterrupts(); // disable interrupts on arduino nano
  
   
  //calculation for flowmeter 
  
  flowR = (count*8.93);   // 112 pulse/lt 423.84 pulse /gallon 
  flowRate= flowR*60;     // convert seconds to minutes, new unit is ml/minutes
  flowRate= flowRate/1000; // convert ml to liters, new unit is lt/minutes
  
  totalFlow += flowR;
  
  // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");       // Print tab space

    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");        
    Serial.print(totalFlow/1000);
    Serial.println("L");
  
    lcd.setCursor(0,2);
  lcd.print("Flow: ");
    lcd.setCursor(8,2);
  lcd.print(flowRate);
  lcd.print("lt/min");
  
  lcd.setCursor(0,3);
  lcd.print("Total: "); 
  lcd.setCursor(8,2);
  lcd.print(totalFlow/1000);
  lcd.print("lt");
 
  
  
  
}

void Flow(void) 
{
  count++; // every time this function is called, increment  "count" by 1
}

void loop() {
  
  pressure_cal(); 
  pump_control();
  flow_control();
  lcd_control();
}


  
void pressure_cal(void) {

  float sensorVoltage = analogRead(press_pin);   // sensor voltage A0
  float psi = ((sensorVoltage-102)/204)*25;  // Offset    0 PSI= 0.5V=102 unit, 50 PSI= 2.5, 100 PSI= 4.5V, 1 PSI= 0.04V
  
  // calibration 
  float bar = psi*(0.0689475729);           // Conversion PSI to BAR


  lcd.setCursor (0,1);
  lcd.print (psi);
  lcd.print (" PSI");

  lcd.setCursor ( 10,1);
  lcd.print(bar);
  lcd.print( " BAR");

  //lcd.setCursor(17,1);
  //lcd.print(sensorVoltage);

  Serial.println (sensorVoltage);
  Serial.println(bar);
  Serial.println (psi);

  delay (100);
}

void pump_control(void)

{
  
  // read the analog in value:
  pot_init = analogRead(pot_pin);
  // map it to the range of the analog out:
  pump_init = map(pot_init, 0, 1023, 50, 230);  //  duty cycle between %20 - %90: speed control , duty cycle between %0 - %20: turned off  , duty cycle between %90 - %100: full speed
  // map pump speed percent of full scale
  percentValue = map (pump_init, 50, 230,0,100);
  // change the analog out value:
  analogWrite(pump_pwm, pump_init);
 
  // print the results to the Serial Monitor:
  Serial.print("\t Speed Input = ");
  Serial.print(pot_init);
  Serial.print("\t Speed Output = ");
  Serial.print(pump_init);
  Serial.print("\t Pump Speed Percentage = ");
  Serial.println(percentValue);
  
  lcd.setCursor(2,0);         
  lcd.print("Speed: ");
  lcd.setCursor(8,0);         
  lcd.print("%");         
  lcd.setCursor(9,0);         
  lcd.print(percentValue); 
  lcd.print("     ");         

 //  delay after the last reading:
  delay(2);


}

But When I use interrupt , code stop.

What does that mean? Does it freeze?

But I can see outputs in serial monitor but I cannot see on lcd.

If you still get output on the serial interface, how can you tell us that the code stops?

Do you see nothing on the LCD? Does the LCD work without the interrupt?

What circuit is connected to the interrupt pin (D2)?

I2C doesn't work with interrupts disabled - as you do in your code. Serial also not but it apparently can buffer and handle the transmission later (when the interrupts are enabled - during the delay(1000) part).

Disable interrupts ONLY to copy your count variable into another variable, then enable them again, and use the copy of count to produce your output.

wvmarle:
Disable interrupts ONLY to copy your count variable into another variable, then enable them again, and use the copy of count to produce your output.

Pardon the hijack, but I have a similar problem. The flow meter programme works fine but I cannot get a proper result when I try to incorporate it into the main project with temperature readings, LCD display, SD recording, datafeed, tralala.
I have wondered if there is simply too much stuff going on and that I should use a Pro Mini just for the flow which feeds the result to Mega.

Nick_Pyner:
Pardon the hijack, but I have a similar problem. The flow meter programme works fine but I cannot get a proper result when I try to incorporate it into the main project with temperature readings, LCD display, SD recording, datafeed, tralala.
I have wondered if there is simply too much stuff going on and that I should use a Pro Mini just for the flow which feeds the result to Mega.

Well, if your program is like the OP, with delays, with printing stuff every time through the loop, I am not surprised.

I assume you are not doing that, so, are there functions that don't need to be done every "loop"? How often are temp readings necessary? Do you do data feed every "loop" or only when change occurs? Could change the data feed to send the number of duplicate values this xmission represents, instead of every loop.

Paul

Paul_KD7HB:
Well, if your program is like the OP, with delays, with printing stuff every time through the loop, I am not surprised.

No delays, but yes, it does print every time. So maybe having a ProMini just for flow is not such a bad idea.

Do you do data feed every "loop" or only when change occurs? .

Not so sure about that. It doesn't take into account of what happens when the changes do occur - which is usual. I have considered using ESP32 but I suspect there won't be much to gain as the real problem lies with the peripherals.

Serial prints are slow, SD writes are slow. An ESP32 isn't going to help here.

Do you really need to print every single time loop() runs? If it's for a human to read, 1-2 times a second is normally enough. That alone will make the program much more responsive.

When using interrupts for your flow meter this should be not a problem at all, unless the interrupts from Serial and SD affect it to the extent that you start missing pulses. If so, consider connecting your flow meter to one of the timer/counter registers (preferably TCNT1 as that's the 16-bit one), as that counting happens completely in hardware. You'll definitely not miss any counts. This works for all AVR processors, I don't know if the ESP processors have any similar option.

I didn't mention that the loop is one second. I want the print at this rate for live graphs from the temp sensors. I will take your comments on board, but I now realise that OP's flow code is not the same as mine. Further, while the flow meters are very accurate overall, readings at one second intervals are so erratic that they are unreadable, and I think I will abandon that and take averages for flow and power over ten second intervals, while still keeping the temps as they are..

You should never disable interrupts for more than a few microseconds.

You should interact with an ISR using short critical sections:

  noInterrupts ();
  count = 0 ;
  interrupts ();

  delay (1000) ;
  noInterrupts () ;
  int my_count = count ;
  interrupts ();

OK and karma. I will use the Pro Mini, and Mega's loop proceeds on receipt of flow signal from Pro Mini

1 Like