Suddenly changes in pulse

I’m reading a pulse from a flow meter, with the following code:

void loop()
{
  duration = pulseIn(pin, HIGH, 1000);
  secperliter = ((float)duration*5400)/1000000;
  litersec = 1 / secperliter;
  Serial.println(duration);
  Serial.println(litersec);
  delay(1000);
}

My problem is that now and then (approximately in 5% of the readings) the reading is very wrong. If the pulse duration is steady at 300-320 microseconds, then suddenly I get one reading of 3000 and then back to 320 on the next reading.

The flow meter have 3 wires:

  • GND, connected to GND on Arduino
  • 5V, connected to 5V on Arduino
  • Pulse, connected to the pin that read the pulse on the Arduino

In addition do I have a 2K2 resistor between the 5V and the pulse wire.

Are there anything I can do to make this more stable so I avoid the worst false readings?

I would first check the wiring , if you can try it with a very short length of wire connecting the sensor to see if the problem could be in the connections.

If that doesn’t help and you have access to an oscilloscope, have a look to see if the pulses are clean ( you want to look for the pulse to rise steeply from 0 to nearly 5v , no noise or ringing, and the pulse to steeply drop back down to 0.

You may want to double check that it needs that pull-up resistor, perhaps post a link to the datasheet for your sensor.

You can filter out data that is outside a reasonable threshold but first see if you can eliminate it.

If( duration < BAD_DATA_THRESHOLD){
  secperliter = ((float)duration*5400)/1000000;
  litersec = 1 / secperliter;
  Serial.println(duration);
  Serial.println(litersec);
  delay(1000);
}

Thank you for the reply.

This is the flow meter I'm using: http://www.swissflow.com/en/SF800/Flow_Meter_Specifications. The pull-up resistor is shown in the wiring schematics for the meter, but I will give it a shot without the resistor. The length of the wires from the meter to the Arduino is not more than 10cm. so I don't hope that is what causing the problem, as it will be difficult to get them any shorter.

Unfortunately I don't have access to an oscilloscope. I have thought about buying one for a long time. I'm not sure I want to invest in a full-blown unit though. How are those small multimeters with build in scope?, like this one: http://cgi.ebay.com/UNI-T-UT81B-SCOPEMETER-MULTI-METER-OSCILLOSCOPE-DMM-USB_W0QQitemZ350085122542QQcmdZViewItem?hash=item350085122542&_trkparms=72%3A570%7C39%3A1%7C66%3A2%7C65%3A12&_trksid=p3286.c0.m14.l1318. Is that good enough for simple tasks like checking the output pulse from a flow meter?

I can't comment on that meter/scope but perhaps someone here has some experience with it or something similar.

But at the data rates of that flow meter you could use a soundcard as a scope. There is a discussion on this here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1217011894/9

Wouldn't you be better setting up an interrupt to occur when there is a change in pin state? Then you only need compare the difference between millis from the last pulse and only when a pulse occurs. you could even sleep the arduino between pulses if you are running from battery to reduce current more.

In your current setup, if the pulse occurs just after the timeout for pulsein occurs you won't 'see' it. I think this is where your problem occurs... Either that or try using as short a delay as possible and understand there is going to be errors so you would need to set up some sort of averaging to reject or filter out missed pulses

Wouldn't you be better setting up an interrupt to occur when there is a pulse? I think this is where your problem occurs

I don't think he's counting pulses, he is using the frequency (as determined by the pulse period) to get the flow rate. Assuming that the flow rate changes relatively slowly, it is sufficient to take readings every second. so no problem if pulses are missed and no advantage in using an interrupt unless something else needs to be processed at the same time.

using an interrupt is like using a trigger on a scope... it gives you a good reference point to start from where you don't have to worry about timeouts or how often your code is able to check the pin.. you just idle and wait for it.. then once it comes in, compare the duration of the pulse.

What does pulsein do if the pin is already high? Does it wait for it to fall low again or does it immediately count it?

If you don't want to deal with interrupts, What is the range you expect the flow rate to be? If the only thing you care about doing in your code is reading that pulse... set the timeout as high as possible... then the arduino will sit and wait for the pulse

using an interrupt is like using a trigger on a scope... it gives you a good reference point to start from where you don't have to worry about timeouts or how often your code is able to check the pin.. you just idle and wait for it.. then once it comes in, compare the duration of the pulse.

What does pulsein do if the pin is already high? Does it wait for it to fall low again or does it immediately count it?

If you don't want to deal with interrupts, What is the range you expect the flow rate to be? If the only thing you care about doing in your code is reading that pulse... set the timeout as high as possible... then the arduino will sit and wait for the pulse

pulseIn , as used in the code above, will only start timing when the pin goes high. If the pin is already high when pulseIn is called, it will first wait to go low. So it will always measure the next complete pulse.

The advantage of interrupts is in applications where one must either catch every transition, or where the measurements must happen at the same time that the sketch is running some other code. But for the application here, pulseIn should work just as well as an interrupt and is much easier to impliment.

Guys, thank you for taking your time to help me with this.

I will try doing the reading by using interrupt and see if that helps. I will keep you posted.....

If you do use millis() for this, wrap it in cli() and sei():

cli();
pulseTime = millis();
sei();

Otherwise you could experience the same bogus pulse problem if you are unlucky enough to have a timer0 overflow occur in the middle of the millis() calculation.

  • Ben

As indicated in the first post, the pulse durations are around 300 microseconds so millis() is out of the question, but wrapping pulseIn() in the cli sei is a good idea

Ah, good point. Please pardon the momentary stupidity!

Ben, you are so prolific in posting great solutions to all kinds of problems here, one shouldn't be surprised that a little detail gets missed every once and a while ;)