Frequency/Pulse Measurement

Hi Everyone,

I've read through a few previous posts on measuring frequency on the arduino through the analog pins using the attachinterrupt() function but am still having trouble understanding what the code should look like.

I'm going to be measuring the output of an anemometer, which gives a high or low signal as shown in this picture:

The problem I'm having is that the high and low signals are not of the same period so it's causing me some confusion as to how I should go about coding it.

The frequency of pulses is 1Hz per 2.5mph, so a safe maximum value of frequency might be 40Hz (= a period of 0.025s)

Another issue I'm going to have to solve is because i'm data logging, so I'll be performing a single read of the wind speed and then putting the arduino on standby for an hour before powering up and taking another reading. Any help with this is much appreciated!

Thanks Again

I've read through a few previous posts on measuring frequency on the arduino through the analog pins using the attachinterrupt() function but am still having trouble understanding what the code should look like.

Attachinterrupts() only work on digital input pins 2 and/or 3 for a standard arduino board, not analog pins. Trying to measure the frequency of a single via analogRead() would be a very complex software method and wouldn't have anything to do with using interrupts, so I'm confused.

Lefty

If you are measuring such a low frequency, it pays to use an interrupt + timer: use a free-running timer that overflows to a counter. Poll the pin connected to the input pin on the rising edge (or falling edge), at beginning of the measurement.

On the first rising edge, zero the counter. On the n'th rising edge, stop the timer and the external interrupt. The reading of counter::TCNTx would be the number of ticks it has taken over n cycles -> you get the frequency / mph.

Okay thanks for the replies, is it sensible that I should try doing this via the digital pins and attachinterrupt() rather than using the analog pins and analogread()?

if so, how do I use the attachinterrupt() for this case?

Thanks

Yes, it would be difficult, given the digital nature of the signal.

The sketch should read something like this:

  initialize the timer but don't turn it on yet  
  wait for the signal to go low; //assuming you are starting with falling edge
  //now the signal has gone low
  turn on the timer; //counting starts now
  while (n) continue; //wait until the desired number of cycles have passed
  stop the timer; //now the number of cycles has passed
  read the counters;

Now, this approach is essentially polling so if you have other timing sensitive tasks, it will not work.

In that case, you can turn the whole thing into an interrupt drive approach - the same basic thought process.

The pseudocode of dhenry works when there is wind and the anemometer generate pulses. If there is little or worse no wind his pseudocode will block.

Read - http://arduino.cc/en/Reference/AttachInterrupt - and replace blink() with count()

robtillaart:
The pseudocode of dhenry works when there is wind and the anemometer generate pulses. If there is little or worse no wind his pseudocode will block.

Read - attachInterrupt() - Arduino Reference - and replace blink() with count()

Thanks for this, I was having trouble understanding dhenry.

I was also thinking of using "pulsein()" to measure the length of the pulses (as they also vary with wind speed), would this be a suitable method? would it cause any problems?

Thanks for this, I was having trouble understanding dhenry.

Your not alone. :wink:

Lefty

I was also thinking of using "pulsein()" to measure the length of the pulses (as they also vary with wind speed), would this be a suitable method? would it cause any problems?

But you need a pulse to measure, so for very low speeds it might time out before you get your pulse. And does timeout means 0 pulse or 1 pulse that is not finished yet?

robtillaart:

I was also thinking of using "pulsein()" to measure the length of the pulses (as they also vary with wind speed), would this be a suitable method? would it cause any problems?

But you need a pulse to measure, so for very low speeds it might time out before you get your pulse. And does timeout means 0 pulse or 1 pulse that is not finished yet?

Okay, say if I'm doing:

pulsein(6, HIGH, 1000)

this will give the pulse length of a High reading from pin 6, but will timeout after 1000ms, will it still time out if the initial signal is High and doesn't change?

I have some discussion here about measuring frequency, and period:

Measuring period (and inverting it to get a frequency) is more useful for low frequencies, because if you try to "count" and only one or two counts come in a second, the error amount will be high.

Some stuff about interrupts:

If you use the hardware timers (as mentioned in my page above) you can trigger on either the leading or trailing edge which would eliminate the problem of the "up" side being longer than the "down" side.

Thanks Nick,

I'll give these pages a read tonight and see how I get on! I've been looking at the pulseIn() function to try and read frequency, but starting to warm towards using a combination of attachInterrupt(), millis() and detatchInterrupt() functions.

I'll be attempting to read and log the values of three other sensors on the same system as this: 2 thermistors (already programmed) 1 analog reading from a set of strain gauges, and then this anemometer. I'm just hoping the interrupt won't cause issues with reading data from the other sensors... like half way through reading a thermistor value, the interrupt gets called :S

Would detatchinterrupt() stop this from happening?

  • Heim

How are you reading the sensors? Interrupts? Analog?

2 Thermistors are simple analogread:

  int therm0 = analogRead(A0);                  //1. thermistor input on Analog pin 0
  float volt0 = therm0 * (5 / 1023.0);            //2. conversion to Voltage
  float temp0 = ((volt0 + 10.281)/0.0458)-273.15; //3. calculates temperature using temp/voltage relationship then adding 273.15Klvn to convert

the strain gauges I can see as being a similar method using an analogread, but I'll cross that bridge when I come to it.

The anemometer will be this one with an interrupt I'm trying to sort out.

The idea is that, every hour (or half hour), the arduino will powerup (from standby), read the two temperatures, the windspeed, and the strain gauge reading. Log all 4 readings with a timestamp onto a datalogger and then go onto standby again till it next powers up.

I'll check back tomorrow!

  • Heim

Interrupts won't trouble an analog read. That's a hardware function.

The idea is that, every hour (or half hour),

That might be a long time, why not measure continuously and write an average every timeslot. That way you could detect peaks esp. in the windspeed.

Or is the Arduino running on batteries? [why not on windenergy ?]

I'm hoping to run it off batteries eventually. But anyway, here's some of the code I have at the moment:

const byte LED = 13;
const byte BUTTON = 2;

// Interrupt Service Routine (ISR)
void pinChange ()
{
Serial.println(millis());
  if (digitalRead (BUTTON) == HIGH)
    digitalWrite (LED, HIGH);
  else
    digitalWrite (LED, LOW);
}  // end of pinChange

void setup ()
{
  Serial.begin(9600);
  pinMode (LED, OUTPUT);  // so we can update the LED
  digitalWrite (BUTTON, HIGH);  // internal pull-up resistor
  attachInterrupt (0, pinChange, CHANGE);  // attach interrupt handler

}  // end of setup

void loop ()
{
//Start Temperature Measurement:  
  int therm0 = analogRead(A0);                  //1. input on Analog pin 0
  float volt0 = therm0 * (5 / 1023.0);            //2. conversion to Voltage
  float temp0 = ((volt0 + 10.281)/0.0458)-273.15; //3. temperature calc 0 
    int therm1 = analogRead(A1);                  //1. input on Analog pin 1
  float volt1 = therm1 * (5 / 1023.0);            //2. conversion to Voltage
  float temp1 = ((volt1 + 10.281)/0.0458)-273.15; //3. temperature calc 1 
   Serial.println(temp1);
//End Temperature Measurement
}

Both the temperature measurement and the pin interrupt run okay by themselves, but when I try the above sketch with both of them in the same sketch. The void.Loop() runs continuously until the interrupt, after the interrupt it stops reporting the temperature to the serial out.

The void.Loop() runs continuously until the interrupt, after the interrupt it stops reporting the temperature to the serial out.

Likely because you are trying to do serial output in the interrupt handler. Serial output uses interrupts, which are disabled during your interrupt service routine. The buffer is full, so Serial.print() blocks until there is room. Since interrupts are disabled, no data ever gets shifted out, so no room is ever made available, so Serial.print() keeps waiting.

Okay nice... I took the serial print out of the interrupt and the two pieces of code seem to be working alongside each other fine now. Would a millis() function in the interrupt cause the program to stop working? like... with an overuse of timers or something?!

  • Heim