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!
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.
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?
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.
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.
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?
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?
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.
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.
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?
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'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?!