Flow sensor without interrupt

Hi guys,

I would like to use a flow sensor but the only sketchs I found in internet are with an interrupt.
Unfortunately the interrupt create me a problem on my Arduino Yun (I know the interrupt is different between Uno and Yun and I managed it), but still my sketch freezes when I use the interrupt.

So I wonder if there is a way to monitor the flow with a flow sensor without an interrupt?

Here the sketch I use for the flow sensor witch works, but when I put this code into my full sketch after a few moment t just freeze.
I am sure it is an interrupt problem as when I comment it the sketch work… but not the sensor…

Is it possibile to use the flow sensor without an interrupt?

// reading liquid flow rate using Seeeduino and Water Flow Sensor from Seeedstudio.com
// Code adapted by Charles Gantt from PC Fan RPM code written by Crenn @thebestcasescenario.com
// http:/themakersworkbench.com http://thebestcasescenario.com http://seeedstudio.com
#include <LiquidCrystal.h>

volatile int NbTopsFan; //measuring the rising edges of the signal
int Calc;                               
int hallsensor;    //The pin location of the sensor is pin 2
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

void rpm ()     //This is the function that the interupt calls 
{ 
  NbTopsFan++;  //This function measures the rising and falling edge of the 

//hall effect sensors signal
} 
// The setup() method runs once, when the sketch starts
void setup() //
{ 
  pinMode(hallsensor, INPUT); //initializes digital pin 2 as an input
  Serial.begin(9600); //This is the setup function where the serial port is 
  lcd.begin(16,2);

//initialised,
  attachInterrupt(0, rpm, RISING); //and the interrupt is attached on pin 2 (INT0=2)
} 
// the loop() method runs over and over again,
// as long as the Arduino has power
void loop ()    
{
  NbTopsFan = 0;	//Set NbTops to 0 ready for calculations
  sei();		//Enables interrupts
  delay (1000);	        //Wait 1 second
  cli();		//Disable interrupts
  Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate 

//in L/hour 
  Serial.print (Calc, DEC); //Prints the number calculated above
  Serial.println (" L/hour\r\n"); //Prints "L/hour" and returns a  new line
  
  lcd.setCursor(0, 0);
  lcd.print("Flusso: ");
  //lcd.setCursor(0, 1);
  lcd.print(Calc, DEC);
  lcd.println(" L/h            ");
}

If you are using Arduino YUN PIN2 defenetly is not interrupt 0 but interrupt 1. So make ure you are attachInterrupt(1, rpm, RISING);

You will have to post your complete code, or at least a reduced version of it which documents the problem.

Using interrupts to count pulses from a hall sensor flow meter is an appropriate use. I think you are better trying to find out why the interrupt is freezing your program and fixing the root cause than trying to read from the sensor with polling. Depending upon what else is going on in the loop you are likely to miss pulses.

Your interrupt pulse counting routine uses delay() to count pulses for a second and disables interrupts. These two calls could be problems for something else in the program.

To count pulses for a second, you use a millis() timer. See the blink without delay example in the 02 Digital examples in the IDE. There are many, many posts on this board about not using delay(). If you use that method, you then can disable interrupts for a brief period while you do the calculation and then reset them for when the program continues.

My fault, I published the original code before my adaptation for Yun.

Here my code :

#include <DHT.h>                           //For DHT22 & AM2302 library
#include <OneWire.h>                       //For DS18B20
#include <LiquidCrystal.h>
#include <Bridge.h>
#include <HttpClient.h>

#define DHTPIN 3                           //DHT22
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
float h = 0;
float t = 0;

const byte DS18B20_Pin = 4;                //DS18B20 Signal pin on digital 4
OneWire ds(DS18B20_Pin);                   // on digital pin 4

int Calc;                                  //Sensore flusso
volatile int NbTopsFan;                    //measuring the rising edges of the signal
int hallsensor;                            //The pin location of the sensor is 2 (int0 on Yun = Pin 2)
void rpm ()                                //This is the function that the interupt calls 
{ 
  NbTopsFan++;                             //This function measures the rising and falling 
                                           //edge of the hall effect sensors signal
} 

unsigned long ora = 0;
unsigned long ultimaEsecuzione = 0;
long intervalloEsecuzione = 10000;

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);


void setup()
{  
  // ***For Flow sensor*****************************************
  pinMode(hallsensor, INPUT);              //initializes digital pin 2 as an input
  attachInterrupt(1, rpm, RISING);         //and the interrupt is attached
  // ***********************************************************
  
  // Bridge takes about two seconds to start up
  // it can be helpful to use the on-board LED
  // as an indicator for when it has initialized
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Bridge.begin();
  
  Serial.begin(9600); 
  lcd.begin(16, 2);
  dht.begin();                             //DHT22
  
  while (!Serial); // wait for a serial connection

 }


void loop()
{
 ora = millis();
  
dht22();
ds18b20();
//flusso();
emoncms_async();

delay(1000);                              //just to slow down the output it's easier to read

}
void dht22()
{
  h = dht.readHumidity();
  t = dht.readTemperature();
  
  Serial.print(F("Umidita dentro casa : \t "));
  Serial.print(h);
  Serial.println(F(" % "));
  Serial.print(F("Temp. dentro casa : \t "));
  Serial.print(t);
  Serial.println(F(" c "));              
  
  lcd.print(F("Home  Hum  Tank"));
  lcd.setCursor(0,1);
  lcd.print(t);
  lcd.print(F("c "));
  lcd.print(h);
  lcd.print(F("% "));
}
void ds18b20()
{
  float temperature = getTemp();     
  Serial.print(F("Temp. acqua :            "));
  Serial.print(temperature);
  Serial.println(F(" c"));
  Serial.println(F(" "));

  lcd.print(temperature);
  lcd.println(F("c"));
}

float getTemp()
{
  //returns the temperature from one DS18S20 in DEG Celsius
  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) 
  {
    //no more sensors on chain, reset search
    ds.reset_search();
    return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) 
  {
    Serial.println(F("CRC is not valid!"));
    return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) 
  {
    Serial.print(F("Device is not recognized"));
    return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);                           // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);  
  ds.write(0xBE); // Read Scratchpad


  for (int i = 0; i < 9; i++)                  // we need 9 bytes
  {
    data[i] = ds.read();
  }

  ds.reset_search();

  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB);         //using two's compliment
  float TemperatureSum = tempRead / 16;

  return TemperatureSum;                       

}
void emoncms_async()
  {
  // Initialize the client library
  Process p;
  
  if (ora - ultimaEsecuzione > intervalloEsecuzione) {
 
    String url = F("http://emoncms.org/input/post.json?***={dhttemp:");
    url += t;
    url += F(",dhthum:");
    url += h;
    url += F("}&apikey=***&node=0");
 
    p.runShellCommandAsynchronously("curl \"" + url + "\"");
 
 
    ultimaEsecuzione = ora;
  }
}
void flusso()
{
  NbTopsFan = 0;	         //Set NbTops to 0 ready for calculations
  sei();		         //Enables interrupts
  delay (1000);	                 //Wait 1 second
  cli();		         //Disable interrupts
  Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate 
                                 //in L/hour 
  Serial.print (Calc, DEC);      //Prints the number calculated above
  Serial.println (F(" L/hour\r\n"));  //Prints "L/hour" and returns a  new line
  
  /*
  lcd.setCursor(0, 0);
  lcd.print("Flusso: ");
  //lcd.setCursor(0, 1);
  lcd.print(Calc, DEC);
  lcd.println(" L/h            ");
*/
}

I usually start from a sketch I found on internet and then try to adapt it for my need as I am not able to write mine, for now.

Thank you to everyone who try to help me.

You can not leave global interrupts disabled with cli() when you leave void flusso(). It will block many things including Serial printing. To see this, try this sketch with cli() commented out and then remove the //.

void setup() {
Serial.begin(9600);
}
void loop() {
  //cli();
  Serial.println("I require interrupts enabled to work!");
  Serial.println("cli()disables interrupts and blocks me.");
  delay(1000);
}

Instead of using sei() and cli() use attachInterrupt(1, rpm, RISING) and detachInterrupt(1,rpm,RISING)

Cattledog I changed as you suggest but I have one new error, maybe I did something wrong?

I only changed in void flusso as following I used 0 instead of 1 because 0 is pin 2 on Yun):

void flusso()
{
  NbTopsFan = 0;            //Set NbTops to 0 ready for calculations
  //sei();              //Enables interrupts
  //delay (1000);                   //Wait 1 second
  //cli();              //Disable interrupts
  attachInterrupt(0, rpm, RISING);
  detachInterrupt(0, rpm, RISING);
  Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate 
                                 //in L/hour 
  Serial.print (Calc, DEC);      //Prints the number calculated above
  Serial.println (F(" L/hour\r\n"));  //Prints "L/hour" and returns a  new line
  
  /*
  lcd.setCursor(0, 0);
  lcd.print("Flusso: ");
  //lcd.setCursor(0, 1);
  lcd.print(Calc, DEC);
  lcd.println(" L/h            ");
*/
}

But it gave me error: Arduino:1.5.8 (Mac OS X), Scheda:"Arduino Yún"

flusso.ino: In function 'void flusso()': flusso.ino:8:33: error: too many arguments to function 'void detachInterrupt(uint8_t)' In file included from /Users/iMatteo/Documents/Arduino/libraries/DHT/DHT.h:4:0, from Progetto_Yun_prova_emoncms.ino:1: /Applications/Arduino 1.5.8.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:142:6: note: declared here void detachInterrupt(uint8_t); ^ Errore durante la compilazione

You have to leave the delay(1000) in between the attach and detach interrupts so that it will collect counts over the one second. I was wrong about the syntax of detachInterrupt it should be as below

attachInterrupt(0, rpm, RISING);
delay(1000);
detachInterrupt(0);

Using delay is not the best way to do this, but it should work, and you can optimize once you get the program working.

Thank you, this evening I will try it and let you know the result.

You said that delay wasn't the best way, should I use millis instead?

Thank you for your help.

You said that delay wasn't the best way, should I use millis instead?

Yes, and you should NOT be detaching and attaching the interrupt handler. Leave it attached and counting all the time. Once a second, copy the data the ISR has accumulated and reset the variables that the ISR uses.

If the copy operation is non-atomic, disable (not detach) all interrupts while you do the copy operation, and then enable (not attach) all interrupts. noInterrupts() and interrupts() could be useful.

Wooo... Sorry PaulS i'm a noob, could you be more explicit? Could you write me down an example for me to understand what you mean?

Thank you