Measuring frequency using pulsein - strange values

Hi,

I am using the code below to measure the frequency output of a square wave from an astable oscillator. The design is ultimately to measure capacitance based on (Arduino Capacitance Meter Circuit Diagram and Code). The measurement is fine until I get the range of around 1Hz. It works perfectly at 2.7Hz (220uF cap) but gives odd readings at 1.3Hz (470uF cap) - the loop repeatedly produces 3.12, 2.16, and inf as the readout (I have verified the signal on a scope and it looks fine -see attached images).

Hopefully it is something obvious but it has been bugging me for a couple of hours!

Thanks in advance,

unsigned long ontime;                    
unsigned long offtime;
unsigned long period;
float frequency;
float capacitance;

void setup()
{
    pinMode(8,INPUT);            //pin 8 as signal input
    Serial.begin(9600);
}

void loop()
{
    noInterrupts();
    ontime = pulseIn(8,HIGH);
    offtime = pulseIn(8,LOW);
    interrupts();

    period = ontime+offtime;
    frequency = 1000000.0/period;
    capacitance = 1 * (1.4427*1000000000)/(2545*frequency);   //calculating the Capacitance in nF
    Serial.println(frequency);
    Serial.flush();
}

Do you need to do this?

capacitance = 1.0 * (1.4427*1000000000)/(2545.0*frequency);

No, not to measure frequency but it will be ultimately using the frequency measurement to determine capacitance.

No, I meant: do you need to add the '.0' that I added in two places?

I see, sorry. I can do that but the more immediate problem is the frequency measurement is not working at around 1.2 Hz.

Problems around 1 Hz, makes me think you need to increase the timeout on your calls to pulseIn().

ontime = pulseIn(8,HIGH); offtime = pulseIn(8,LOW);

Paul

I have used a different approach using interrupts based on this thread - https://forum.arduino.cc/index.php?topic=64219.30

It seems more stable (and more accurate based on a comparison with oscilloscope measurements).

Thank you Martyn

This calculation:

    period = ontime+offtime;
    frequency = 1000000.0/period;
    capacitance = 1 * (1.4427*1000000000)/(2545*frequency);

may very well be causing problems due to the limited precision of a float. The "inf" you're seeing points to this as potential issue. It sometimes helps to make a more direct calculation, without storing intermediates:

float capacitance = 0.566876 * (ontime + offtime);

You can make the whole calculation MUCH more efficient (much shorter code and much faster) by calculating pF and using integer math only (at a cost of some precision - works until just over 4000 µF):

unsigned long capacitance = 567 * (ontime + offtime);

Serial.flush() is unnecessary, as are the noInterrupts() and interrupts() calls, but it seems pulseIn() is not affected.

But there is another issue: the pulseIn() function times out after 1 second! So that may be part of the problem you see. The offtime takes three half cycles to be measured: it's called the moment onTime returns (so the signal is low), waits for it to become high (just about half a cycle), then waits until it becomes low again (another half cycle) and then it measures the pulse (half a cycle). At 1 Hz that's 1.5 seconds total.

To measure such long pulses you may try to use pulseInLong() instead (I also only learned about that one just now looking at the source!). Mind that you must keep interrupts running for that one to work, as switching off interrupts messes with the millis() and micros() counters, and the latter is used by the pulseInLong() function to measure the pulse length.

Thanks for the comprehensive answer. It must be a timeout issue as you pointed out. I will try the more direct approach to the calculation.

Martyn