Flow sensor library

Hey guys,
Not sure if it will even work as the spec sheet says 5v but wanted to try anyway. New to libraries and such and hoped someone might give this a look to find out whats needed.

------> http://www.adafruit.com/products/828
------> http://www.adafruit.com/products/833

Thanks


// which pin to use for reading the sensor? can use any pin!
#define FLOWSENSORPIN D2

// count how many pulses!
volatile uint16_t pulses = 0;
// track the state of the pulse pin
volatile uint8_t lastflowpinstate;
// you can try to keep time of how long it is between pulses
volatile uint32_t lastflowratetimer = 0;
// and use that to calculate a flow rate
volatile float flowrate;
// Interrupt is called once a millisecond, looks for any pulses from the sensor!
SIGNAL(TIMER0_COMPA_vect) {
  uint8_t x = digitalRead(FLOWSENSORPIN);
  
  if (x == lastflowpinstate) {
    lastflowratetimer++;
    return; // nothing changed!
  }
  
  if (x == HIGH) {
    //low to high transition!
    pulses++;
  }
  lastflowpinstate = x;
  flowrate = 1000.0;
  flowrate /= lastflowratetimer;  // in hertz
  lastflowratetimer = 0;
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
  }
}

void setup() {
   Spark.variable("liters",liters)
   pinMode(FLOWSENSORPIN, INPUT);
   digitalWrite(FLOWSENSORPIN, HIGH);
   lastflowpinstate = digitalRead(FLOWSENSORPIN);
   useInterrupt(true);
}

void loop()                     // run over and over again
{
  // if a plastic sensor use the following calculation
  // Sensor Frequency (Hz) = 7.5 * Q (Liters/min)
  // Liters = Q * time elapsed (seconds) / 60 (seconds/minute)
  // Liters = (Frequency (Pulses/second) / 7.5) * time elapsed (seconds) / 60
  // Liters = Pulses / (7.5 * 60)
  float liters = pulses;
  liters /= 7.5;
  liters /= 60.0;

/*
  // if a brass sensor use the following calculation
  float liters = pulses;
  liters /= 8.1;
  liters -= 6;
  liters /= 60.0;
*/
  delay(100);
}

Hello,
Pins D0, D1, D3, D4, D5 and D6 on the Core are 5V tolerant. You can attach the output of the sensor to one of these pins.

1 Like

I don’t recommend you use the Adafruit code as it interferes with the timer0 delay code. I have used a similar hall effect sensor and took a different approach using a 1 sec sampling perior in loop() along with using a falling edge interrupt for the water pulse counter. Here is my (untested on Spark) suggested sketch:

unsigned long oldTime = 0;
volatile unsigned int WaterPulseCount = 0;

// conversion from pps to litres, plastic sensor (485 for metal)
const float pulsesPerLiter = 450;

// Spark Digial Pin D2
#define WATER_SENSOR_PIN	D2		// Water sensor using pin D2

// Define Spark variable - not sure "float" type works so define as INT
// so decimal is shifted left with * 100 (so xx.yy becomes xxyy)
int liters = 0;

void setup()
{
  Spark.variable("liters",&liters, INT);

  // Set Digital pin WATER_SENSOR_PINT to INPUT mode and set
  // interrupt vector (water flow sensor) for FALLING edge interrupt
  pinMode(WATER_SENSOR_PIN, INPUT_PULLUP);
  attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING) ;
}


void loop()
{
  unsigned long t;

  t = (millis() - oldTime);
  if(t >= 1000)    			// Only process counters once per second
  {
    //Read water sensor pulse count and process
    if (WaterPulseCount != 0)		// Do nothing if water is not flowing!
    {
    detachInterrupt (WATER_SENSOR_PIN);	// Disable water flow interrupt to read value
    //Calculate litres and adjust for 1 sec offset, if any
    liters = (WaterPulseCount / pulsesPerLiter) * (t / 1000) *100;
    oldTime = millis();				// Reset base delay time
    WaterPulseCount = 0;			// Reset the water pulse counter
    attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING);
    }
  }
}

This leaves timer0 untouched and is just as accurate. Because I don’t believe that “float” is implemented in Spark.variable(), I added a * 100 multiplication to the liters calculation to essentially “shift” the decimal point left by 2. So a liters value of 1234 represents 12.34. This can be removed if the accuracy is not required.

:smile: (btw… also from Canada!)

Thanks guys!

Im playing around with it now, will report back on how it goes.

Peekay thank you! Helped me a ton. Let me know if you get a chance to test.

Sure is the great WHITE north this year

2 Likes

canada7764, my water sensor is tied up in my basement on the hot water output of my gas heater so I will test will a square wave generator, which is how I developed the original code. Will get back to you when I get results.

Oh, and I LOVE white so much, especially in Ottawa (NOT!) :wink:

canada7764, it seems I left out the code for the ISR for the water sensor!! Here is the full code that compiles correctly. The Serial.print code can be removed. I added it for simpler debugging.

/*
    Water flow sensor test sketch

*/


unsigned long oldTime = 0;
volatile unsigned int WaterPulseCount = 0;

// conversion from pps to litres, plastic sensor (485 for metal)
const float pulsesPerLiter = 450;

// Spark Digial Pin D2
#define WATER_SENSOR_PIN	D2		// Water sensor using pin D2

// Define Spark variable - not sure "float" type works so define as INT
// so decimal is shifted left with * 100 (so xx.yy becomes xxyy)
int liters = 0;


//-----------------------------------------------------------------------------
// Water Sensor interrupts
//-----------------------------------------------------------------------------
void WaterPulseCounter(void)
{
	// Increment the water pulse counter
	detachInterrupt (WATER_SENSOR_PIN) ;
	++WaterPulseCount;
	attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING) ;
}


void setup()
{
  Serial.begin(115200);
  
  Spark.variable("liters",&liters, INT);

  // Set Digital pin WATER_SENSOR_PINT to INPUT mode and set
  // interrupt vector (water flow sensor) for FALLING edge interrupt
  pinMode(WATER_SENSOR_PIN, INPUT_PULLUP);
  attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING) ;
}


void loop()
{
  unsigned long t;

  t = (millis() - oldTime);
  if(t >= 1000)    			// Only process counters once per second
  {
    //Read water sensor pulse count and process
    if (WaterPulseCount != 0)		// Do nothing if water is not flowing!
    {
    detachInterrupt (WATER_SENSOR_PIN);	// Disable water flow interrupt to read value
    //Calculate litres and adjust for 1 sec offset, if any
    liters = (WaterPulseCount / pulsesPerLiter) * (t / 1000) *100;
    oldTime = millis();				// Reset base delay time
    WaterPulseCount = 0;			// Reset the water pulse counter
    attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING);
    Serial.print("WaterPulseCount= ");
    Serial.print(WaterPulseCount);
    Serial.print(", liters= ");
    Serial.println(liters);
    }
  }
}

Cheers!

1 Like

peekay,

I forget things all the time (added the routine) but thanks for posting. Just finished installing on greenhouse irrigation and gonna test accuracy now.

If only you could see the 13’ banks iv made here in Alberta.

Thanks

Dude, those are walls now, not banks!

:wink:

Going way off topic now!

3 Likes

canada7764,

I got the code working and running solidly with a few caveats. First, some of my code must have been written WAY too late at night so I fixed my own bugs. Seconds, the Spark Cloud API is not quite ready for prime time. That is, the FLOAT and DOUBLE types are not parsed correctly by the Cloud API so a GET request will get garbage. I ended up using a FLOAT for liters and then converted it to a STRING for the Spark.variable. Another oddity I experienced is that I could not use digital pin D2 as it would not work! I changed over to D3 and all was fine so I have to do some digging on that issue. So, here is the code for your enjoyment:

/*
    Water flow sensor test sketch

*/


unsigned long oldTime;
volatile unsigned int WaterPulseCount = 0;

// conversion from pps to litres, plastic sensor (485 for metal)
const float pulsesPerLiter = 450;

// Spark Digial Pin D3 (D2 did not work)
#define WATER_SENSOR_PIN	D3	// Water sensor digital pin

// Define Spark variable - not sure "float" type works so define as INT
// so decimal is shifted left with * 100 (so xx.yy becomes xxyy)
float liters = 0;
char liters_S[6];

//-----------------------------------------------------------------------------
// Water Sensor interrupts
//-----------------------------------------------------------------------------
void WaterPulseCounter(void)
{
	// Increment the water pulse counter
	//detachInterrupt (WATER_SENSOR_PIN) ;
	WaterPulseCount++;
	//attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING) ;
}


void setup()
{
  Serial.begin(9600);
  
  Spark.variable("litersS", &liters_S, STRING);

  // Set Digital pin WATER_SENSOR_PINT to INPUT mode and set
  // interrupt vector (water flow sensor) for FALLING edge interrupt
  pinMode(WATER_SENSOR_PIN, INPUT);
  attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING) ;
  oldTime = millis();
}


void loop()
{
  unsigned long t;
  static unsigned int pc;

  t = (millis() - oldTime);
  if(t >= 1000)    			// Only process counters once per second
  {
    //Read water sensor pulse count and process
    if (WaterPulseCount != 0)		// Do nothing if water is not flowing!
    {
    detachInterrupt (WATER_SENSOR_PIN);	// Disable water flow interrupt to read value
    //Calculate litres and adjust for 1 sec offset, if any
    liters = (WaterPulseCount / pulsesPerLiter) * (t / 1000);
    oldTime = millis();				// Reset base delay time
    pc = WaterPulseCount;
    WaterPulseCount = 0;			// Reset the water pulse counter
    attachInterrupt(WATER_SENSOR_PIN, WaterPulseCounter, FALLING);

    sprintf(liters_S, "%4.3f", liters);
    
    Serial.print("WaterPulseCount= ");
    Serial.print(pc);
    Serial.print(", liters= ");
    Serial.print(liters,3);
    Serial.print(", liters_S= ");
    Serial.println(liters_S);
    }
  }
}

:smile:

Glad you guys got this working! Sorry about the floats not being parsed correctly thing, the API and cloud services are definitely still evolving, especially with community support and bug reports like this :slight_smile:

– I poked the firmware guys again about this one, we’ll post back here when it’s fixed.

edit: okay, I have a fix for this for doubles with Spark.variable, it’s on staging now, and it’ll be included in our next production rollout.

@Dave got a fix in for floating point endianness today. Should be deployed to the Cloud by early next week.

Thanks guys! I always look forward to each new release :smile:

1 Like

Greetings Spark Community! I’am a computer programming student here in Canada. I’am using a Flow Rate Sensor the same product @canada7764 posted at the beginning. I have tried using the code provided by @peekay123 it compiles great and seems to be working! The issue is viewing the results… I have tried to use the Cloud APi to view it via the web, it is connecting but not showing the results. Can someone Please help!! am i doing this correctly? I just want to view the amount of water flowing through the sensor… :frowning:

Thank you for your time

@Clarke, I’m from Ottawa, where are you? I removed the link from your post because it contained your Core’s token and ID! If you post your code, I can give you some advice (hopefully) :stuck_out_tongue:

@peekay123 Thanks for taking the time out of your day to reply! :smiley: I’am from Barrie, just north of Toronto a second semester programming student. Also i appreciate you taking the link out, wasn’t sure if i should post it or not lol. For my code i was actually using what you posted Feb of 2014 with Variable " litersS " ( most resent code ) as a test and then was going to write some code to change it from litres to millilitres and just play around with the code making changes and learning from trial and error etc. But as of right now just trying to get something to work. I have used an Arduino with bluetooth for the same purpose and it worked. Just now switching to the Spark Core because its so awesome I’am having some trouble and not much mentoring at school being such a new platform.

@Clarke, if just viewing the results is what you need, the code I posted prints to the Serial port (USB). All you need is to open a terminal on your PC and monitor the COM port created by the connected Core. :smiley:

@peekay123 Well that was simple enough, worked great! As you can probably guess by now, i’am a total rookie when it comes to this. When trying to view the results via Cloud API using Spark.variable(“litersS”, &liters_S, STRING); https://api.spark.io/v1/devices/ID/litersS/?access_token= It does get connected, but does not display the results. Would you be able to help me, as to how to go about getting it to work. :smiley:

Have a Great weekend! Its gonna be a cold one!

@Clarke, I need to see your code to be able to help you :stuck_out_tongue:

@peekay123 This is the code ( your code ) lol :smile: I have been trying

I have been using Variable " liters_S "

Example Request ( It does gets connected but does not display results )