Maastricht Netherlands
Offline
Newbie
Karma: 0
Posts: 34
|
 |
« on: November 25, 2011, 09:26:00 am » |
Arduino frequency counter factsHere is a frequency counter for the Arduino which measure the period and pulse width, it was needed for a pedelec legalisation device and a scale interface. Look for the latest version here: http://www.avdweb.nl/arduino/frequency-period-counter.htmlThe period is measured instead of the frequency; this is done to save program space. The frequency can be calculated with 1/period; however this will include the float library which takes a lot of memory. Thus the frequency calculation is left out of the library code.- These values are available: frequency, period, pulseWidth, pulseWidthLow, elapsedTime and level.
- The frequency counter can be used in two ways:
With an interrupt triggered by the input signal. Polled regularly with the poll() instruction in a loop. - Take a debounce time of about 10ms if the frequency comes from a mechanically switch.
- The measurement can be done in milli seconds or micro seconds.
F requency counter example#include <Streaming.h> #include <FreqPeriodCounter.h> const byte freqPin = 3; #define debounceTime_ms 10 FreqPeriodCounter freqPeriodCounter(freqPin, millis, debounceTime_ms); void setup(void) { Serial.begin(9600); } void loop(void) { freqPeriodCounter.poll(); Serial << freqPeriodCounter.period << endl; } Frequency counter library/* FreqPeriodCounter * Version 25-11-2011 * Copyright (C) 2011 Albert van Dalen http://www.avdweb.nl * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses.
<------------- period ------------> pulseWidth _____________ ______________ || || || || || || pulseWidthLow || || ______________|| ||__________________|| ||______________ periodCount 0 1 transientTime ^ ^ ^ ^ level 1 0 1 0 debounceTime <--> <--> <--> <--> <- elapsedTime -> */ #include "FreqPeriodCounter.h"
// debounceTime in msec if msec_usecNot=1 else in usec
FreqPeriodCounter::FreqPeriodCounter(byte pin, bool msec_usecNot, unsigned debounceTime): time(0), transientTime(0), elapsedTime(0), pulseWidth(0), pulseWidthLow(0), period(0), periodCount(0), level(0), lastLevel(0), pin(pin), msec_usecNot(msec_usecNot), debounceTime (debounceTime) { }
bool FreqPeriodCounter::poll() { if(msec_usecNot) time = millis(); else time = micros(); elapsedTime = time - transientTime; level = digitalRead(pin); if((level != lastLevel) & (elapsedTime > debounceTime)) { lastLevel = level; transientTime = time; if(level == HIGH) { pulseWidthLow = elapsedTime; period = pulseWidth + pulseWidthLow; if(periodCount++ > 1) { periodCount = 0; return true; // return true if a complete period is measured } } else pulseWidth = elapsedTime; } return false; }
unsigned int FreqPeriodCounter::hertz() { if (timeFunctionPtr == micros) return 1000000/period; else return 1000/period; }
#ifndef FREQPERIODCOUNTER_H #define FREQPERIODCOUNTER_H
/* FreqPeriodCounter * Version 25-11-2011 * Copyright (C) 2011 Albert van Dalen http://www.avdweb.nl * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses. */
#include <WProgram.h>
class FreqPeriodCounter { public: FreqPeriodCounter(byte pin, bool msec_usecNot, unsigned debounceTime); bool poll();
unsigned long period, pulseWidth, pulseWidthLow, elapsedTime; bool level; protected: unsigned long time, transientTime; unsigned debounceTime; byte periodCount, pin; bool lastLevel, msec_usecNot; };
#endif
|
|
|
|
« Last Edit: January 19, 2012, 10:45:40 am by avandalen »
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 86
Posts: 9360
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #1 on: November 25, 2011, 05:27:38 pm » |
Thanks for sharing,
What is the range it can measure? What is its accuracy? (can be improved by counting multiple periods of course)
|
|
|
|
|
Logged
|
|
|
|
|
Maastricht Netherlands
Offline
Newbie
Karma: 0
Posts: 34
|
 |
« Reply #2 on: December 18, 2011, 02:04:40 pm » |
Hi The lowest time with polling is about 40us -> 25kHz. The longest time is 50 days....
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 15
|
 |
« Reply #3 on: January 16, 2012, 12:06:31 pm » |
why is not all of the required code included?
maybe it's just because I'm new, but I frequently find that many "included" libraries that I simply don't have.
"WProgram.h" is referenced but not included in this one, for example, and "streaming.h"
When I search for Streaming.h I find several, but they then each include some other library that I don't have (LOG.h, or whatever...)
at some point I guess my libraries will include so much random stuff that I'll have better luck with downloaded sketches?
|
|
|
|
|
Logged
|
|
|
|
|
Maastricht Netherlands
Offline
Newbie
Karma: 0
Posts: 34
|
 |
« Reply #4 on: January 16, 2012, 01:15:32 pm » |
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 86
Posts: 9360
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #5 on: January 16, 2012, 02:08:10 pm » |
The period is measured instead of the frequency; this is done to save program space. The frequency can be calculated with 1/period; however this will include the float library which takes a lot of memory. Thus the frequency calculation is left out of the library code. One can calculate the frequency also by doing integer math. If one expresses the time in micros then the frequency is: ... period = micros() - start; long freq = 1000000L/period; Serial.print("freq: "); Serial.println(freq); ... if one wants to add 3 decimals (1 and 2 decimal are similar) ... period = micros() - start; long freq = 10000000000L/period; // note the extra 000 Serial.print("freq: "); Serial.print(freq/1000); Serial.print('.'); Serial.print(freq%1000); ...
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 311
Posts: 35470
Seattle, WA USA
|
 |
« Reply #6 on: January 16, 2012, 06:27:05 pm » |
Wprogram.h is included in Arduino by default. With versions 0023 and earlier, that is. With 1.0, that file was renamed to Arduino.h. The conditional/unconditional inclusion is how you can tell if a library is compatible with 1.0. Conditional is; unconditional is not.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 15
|
 |
« Reply #7 on: January 16, 2012, 08:26:50 pm » |
Thanks! I've been able to get some data logged, and something odd is emerging. with a fairly large sample size (hundreds of data) there seem to be some discrete "favorite" values. Out of 1000 or so measurements, there are only about 8 discrete values, and they reach out to 5 digits behind the decimal point. weird, huh!? I'm measuring the frequency of the AC electricity, so the measurement is around 60Hz. I have a real time monitor set up on a Digital multimeter, and also have historical data, so I know sort of how the frequency behaves (and it's not by jumping from one discrete value to another). a favorite seems to be 60.024 (about 20% of all values are 60.024HZ , lol). When plotted in excel it seems to have a distinct upper and lower bound (say 59.953 to 60.0421), and in between it leaps around almost at random is there something I can adjust to make it more granular of a measurement?
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 86
Posts: 9360
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #8 on: January 18, 2012, 01:54:16 pm » |
and something odd is emerging. pictures?
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 15
|
 |
« Reply #9 on: January 18, 2012, 03:45:49 pm » |
not sure how to post a graph... here's a small excerpt of the data. In its repetitiveness of the smae values over and over it is very representative of the whole dataset. 59.9952 60.0096 60.0096 60.024 60.0096 60.024 59.9952 60.024 59.9808 60.0096 59.9952 60.024 60.0096 59.9377 59.9664 60.0528 60.0096 59.9233 60.0096 59.9952 59.9952 59.9952 59.9808 59.9952 59.9952 60.0096 59.9952 60.024 60.0096 60.024 59.9952 59.9952 59.9808 59.952 60.0096 60.0096 60.0096 60.0096 59.9952 59.9808 60.0096 59.9808 59.952 59.9808 59.9377 59.9952 60.024 60.0096 60.024 60.0096 60.0096 59.9664 60.0096 59.952 59.9952 60.0096 59.9952 60.0096 59.9952 59.9952 60.0096 59.9377 60.024 60.0096 59.9808 59.9952 60.024 60.024 60.0096 59.9952 60.024 60.024 60.024 60.024 60.0096 60.0096 60.024 59.9664 59.952 59.9808 59.9377 60.024 60.024 60.024 59.952 59.952 60.024 60.0096 59.952 59.952 59.9952 59.9952 60.0096 60.0096 60.0096 60.024 60.0096 60.024 60.0096 60.0096 60.0096 59.9377 59.9664 59.9664 60.0096 59.9808 59.9952 60.0096 59.9952 59.9952 59.9952 59.9377 60.0096 59.9952 60.024 59.9808 59.9664 59.9952 60.0096 60.0096 59.9952 59.9808 59.9808 60.0096 60.024 60.0096 59.9808 59.9664 60.0096 60.0673 59.952 59.952 60.024 60.0096 59.9952 59.9952 60.0096 60.024 60.0096 60.0096 60.0096 60.024 60.0096 60.024 60.024 60.024 59.952 60.024 59.9952 59.9952 60.024 59.9952 59.9664 59.9952 59.9808 60.0096 59.9952 60.0096 60.0096 59.9952 59.9808 60.024 60.0096 60.0096 59.9664 59.9664 59.9808 59.9377 60.0096 60.024 60.024 60.0384 59.9952 59.9952 60.0096 60.0096 59.9808 60.024 59.9664 59.9952 59.9952 60.0096 60.024 60.024 60.024 59.9808 59.952 59.9664 59.9377 60.0096 59.9664 60.024 60.0096 59.9808 59.9664 59.9664 59.9664 59.9664 59.9952 60.0096 60.024 60.024 59.952 59.9952 60.024 60.024 59.9952 60.024 60.0096 59.9952 60.024 59.9808 60.024 59.9664 59.9808 59.952 59.9664 59.952 59.9952 60.0096 59.9377 59.952 59.9664 59.9377 60.0096 60.024 59.9664 59.952 59.9952 60.024 59.9377 60.024 60.024 60.024 59.9808 59.952 59.9808 59.9664 59.952 59.9664 59.9664 59.9808 60.0096 59.9952 60.0096 59.9664 59.9808 59.9952 60.0096 59.9664 59.952 60.0096 60.024 59.9664 59.952 59.9952 60.0096 59.9952 59.952 60.0384 59.952 59.9377 60.0096 60.0096 59.9664 60.024 59.9952 59.9952 60.0096 60.024 59.9664 59.952 59.9377 59.9952 60.0096 60.024 60.0096 59.9808 59.9952 60.0096 60.024 59.9952 59.9952 60.0096 59.9664 59.9377 59.952 60.0096 60.024 59.9664 60.0096 60.0096 60.0096 59.9664 60.0096 59.9664 59.9664 59.9377 59.952 59.952 59.9664 59.9377 60.0096 60.024 59.9808 59.9664 59.9952 60.024 59.952 59.952 60.0096 60.0096 60.0096 60.0096 59.9952 60.0096 60.024 60.024 60.0096 60.024
|
|
|
|
|
|
Logged
|
|
|
|
|
Maastricht Netherlands
Offline
Newbie
Karma: 0
Posts: 34
|
 |
« Reply #10 on: January 19, 2012, 07:25:40 am » |
The period is measured instead of the frequency; this is done to save program space. The frequency can be calculated with 1/period; however this will include the float library which takes a lot of memory. Thus the frequency calculation is left out of the library code. One can calculate the frequency also by doing integer math. If one expresses the time in micros then the frequency is: ... period = micros() - start; long freq = 1000000L/period; Serial.print("freq: "); Serial.println(freq); ... if one wants to add 3 decimals (1 and 2 decimal are similar) ... period = micros() - start; long freq = 10000000000L/period; // note the extra 000 Serial.print("freq: "); Serial.print(freq/1000); Serial.print('.'); Serial.print(freq%1000); ... Hi Rob, I thanks! I have added a function hertz() now, see also changed the website: http://www.avdweb.nl/arduino/hardware-interfacing/frequency-period-counterint FreqPeriodCounter::hertz() { if (timeFunctionPtr == micros) return 1000000/period; else return 1000/period; }
|
|
|
|
|
Logged
|
|
|
|
|
Maastricht Netherlands
Offline
Newbie
Karma: 0
Posts: 34
|
 |
« Reply #11 on: January 19, 2012, 08:14:24 am » |
I'm measuring the frequency of the AC electricity, so the measurement is around 60Hz. I have a real time monitor set up on a Digital multimeter, and also have historical data, so I know sort of how the frequency behaves (and it's not by jumping from one discrete value to another). a favorite seems to be 60.024 (about 20% of all values are 60.024HZ , lol). When plotted in excel it seems to have a distinct upper and lower bound (say 59.953 to 60.0421), and in between it leaps around almost at random is there something I can adjust to make it more granular of a measurement?
That's not really nice, I want the library improve further if possible.
1. Printing is not allowed during the measurement. Maybe you can store the data in an array (memory of the Arduino), and later print it out? 2. If you have used polling, try interrupt operation instead of polling.
|
|
|
|
« Last Edit: January 19, 2012, 10:38:37 am by avandalen »
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 86
Posts: 9360
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #12 on: January 22, 2012, 06:22:10 am » |
here's a small excerpt of the data. In its repetitiveness of the smae values over and over it is very representative of the whole dataset. Repeating output values are probably caused by the fact that you are reaching the limits of the accuracy. Test: Copy the numbers to a speadsheet in colum A Sort that colum from low - high Make colum B : "=A2-A1" extended for the whole colum A There will appear 2 distinct values : 0 and 0,0144 (+- 0,0001) which means the resolution the (current) algorithm produces is 0,0144, so printing with more than 2 decimals makes no sense If you want more decimals you need to do a numerical analysis of the algorithm (and hardware sample freq/timinig/adc precision etc)). Hope this helps,
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 15
|
 |
« Reply #13 on: January 25, 2012, 09:05:22 pm » |
That's not really nice, I want the library improve further if possible.
1. Printing is not allowed during the measurement. Maybe you can store the data in an array (memory of the Arduino), and later print it out? 2. If you have used polling, try interrupt operation instead of polling.
I think something may be getting lost in between languages or something. I really did not mean to be unkind or "not nice" in any way. I think I am simply not smart enough to use the interrupt operation. I keep getting error messages when trying to compile, but I am using an Arduino Mega 2560, so maybe it wasn't written for that platform. Or, it could just be that I am really new to all this and just haven't learned enough yet.
|
|
|
|
|
Logged
|
|
|
|
|
Newcastle, NSW, Australia
Offline
Newbie
Karma: 0
Posts: 32
Just a mechanic
|
 |
« Reply #14 on: February 04, 2012, 08:54:05 pm » |
Hi, is there any way with this library to get Hertz in a decimal? I need accuracy up to about 850Hz, to calculate engine RPM. Having hertz only as a whole number is reducing the accuracy.
Thanks!
|
|
|
|
|
Logged
|
|
|
|
|
|