Go Down

### Topic: Frequency Counter Library (Read 134052 times)previous topic - next topic

#### Stoni

#30
##### Oct 17, 2013, 03:03 pm
Sorry, I forgot to mention it ... you are right, I am using this library: http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/. And I am using a Arduino Duemilanove.

The frequency I'd like to measure are under 10kHz. Do you have an example code in which one or more timers are disabled? I tried to look for an other library, but all of them are using the 3 timers ... so I would be really glad if you can help me out!

#### dc42

#31
##### Oct 17, 2013, 03:20 pm
1. What will be the approximate frequency, and how accurately do you need to measure it?

2. Will the input be a 5V square wave, or would you like to use the built-in analog comparator to allow much smaller input signals?
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

#### Stoni

#32
##### Oct 17, 2013, 03:27 pm
The frequency will be between 85 and 255Hz.
I am using a pulse Generator which gives sqare waves with a maximum of 5V.

#### robtillaart

#33
##### Oct 17, 2013, 07:30 pm
Code: [Select]
`The frequency will be between 85 and 255Hz. I am using a pulse Generator which gives sqare waves with a maximum of 5V.`
then using an interrupt might be the easiest way - check attachInterrupt example
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### dc42

#34
##### Oct 18, 2013, 12:03 am
Try this:

Code: [Select]
`// Frequency counter sketch, for measuring frequencies low enough to execute an interrupt for each cycle// Connect the frequency source to the INT0 pin (digital pin 2 on an Arduino Uno)volatile unsigned long firstPulseTime;volatile unsigned long lastPulseTime;volatile unsigned long numPulses;void isr(){  unsigned long now = micros();  if (numPulses == 0)  {    firstPulseTime = now;  }  else  {    lastPulseTime = now;  }  ++numPulses;}void setup(){  Serial.begin(19200);}// Measure the frequency over the specified sample time in milliseconds, returning the frequency in Hzunsigned int readFrequency(unsigned int sampleTime){  numPulses = 0;                      // prime the system to start a new reading  attachInterrupt(0, isr, RISING);    // enable the interrupt  delay(sampleTime);  detachInterrupt(0);  return (numPulses < 2) ? 0 : (1000000UL * (numPulses - 1))/(lastPulseTime - firstPulseTime);}void loop(){  unsigned int freq = readFrequency(1000);  Serial.println(freq);  delay(1000);}`
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

#### dc42

#35
##### Oct 18, 2013, 10:50 amLast Edit: Oct 18, 2013, 11:07 am by dc42 Reason: 1
Here is an improved version of the frequency counter sketch. There were a couple of problems with the previous version:

- when you attach the interrupt, you can get an immediate interrupt if this input is already high. This resulted in some jitter in the frequency reading. So I now ignore the first interrupt.

- if the pulse count (i.e. frequency multiplied by the sample time in seconds) was greater than about 4000 then the calculation would overflow. So I have changed it to use floating point calculation instead. This also give a more precise result when the number of cycles counted is low.

Code: [Select]
`// Frequency counter sketch, for measuring frequencies low enough to execute an interrupt for each cycle// Connect the frequency source to the INT0 pin (digital pin 2 on an Arduino Uno)volatile unsigned long firstPulseTime;volatile unsigned long lastPulseTime;volatile unsigned long numPulses;void isr(){  unsigned long now = micros();  if (numPulses == 1)  {    firstPulseTime = now;  }  else  {    lastPulseTime = now;  }  ++numPulses;}void setup(){  Serial.begin(19200);    // this is here so that we can print the result  pinMode(3, OUTPUT);     // put a PWM signal on pin 3, then we can connect pin 3 to pin 2 to test the counter  analogWrite(3, 128);}// Measure the frequency over the specified sample time in milliseconds, returning the frequency in Hzfloat readFrequency(unsigned int sampleTime){  numPulses = 0;                      // prime the system to start a new reading  attachInterrupt(0, isr, RISING);    // enable the interrupt  delay(sampleTime);  detachInterrupt(0);  return (numPulses < 3) ? 0 : (1000000.0 * (float)(numPulses - 2))/(float)(lastPulseTime - firstPulseTime);}void loop(){  float freq = readFrequency(1000);  Serial.println(freq);  delay(1000);}`
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

#### robtillaart

#36
##### Oct 18, 2013, 10:56 am
Very good sample DC42,
another argument to use float division is that integer division truncates.

(you just beat me
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### Stoni

#37
##### Oct 18, 2013, 11:00 am
Oh great! Thanks alot!!
This Frequency counter works really really good for me! Now I can move on   ...

#### dc42

#38
##### Oct 18, 2013, 11:36 am
One thing I found while testing this is that the PWM frequency on pin 3 is not 488.28Hz as documented at http://playground.arduino.cc/Main/TimerPWMCheatsheet, it is in fact 490.20Hz. This makes sense, since timers 1 and 2 on the Uno are configured in phase-correct PWM mode, in which the timer counts from 0 to 255 and then back again, giving 510 steps not 512. The PWM frequency on pin 5 (controlled by timer 0 in fast PWM mode) is 976.57Hz as documented.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

#### venu5056

#39
##### Oct 27, 2013, 10:27 am
i have a small question for u..that is it possible to measure the freq of the sine wave using arduino...

#### dc42

#40
##### Oct 27, 2013, 12:19 pm
To measure the frequency of a sine wave, you can either convert it to something resembling a square wave using additional hardware, or you can use the built-in analog comparator. I have found that the analog comparator is extremely sensitive and you need good wiring layout to avoid getting spurious counts due to noise.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

#### dariq88

#41
##### Dec 17, 2013, 09:39 pmLast Edit: Dec 17, 2013, 09:50 pm by dariq88 Reason: 1
hello!
I tried to modify the library freqcounter for arduino leonardo, but does not start, can you give me a hand to find errors?
Thank

Ps sorry for my English

Code: [Select]
`#include <FreqCounter.h>unsigned long FreqCounter::f_freq;volatile unsigned char FreqCounter::f_ready;volatile unsigned char FreqCounter::f_mlt;volatile unsigned int FreqCounter::f_tics;volatile unsigned int FreqCounter::f_period;volatile unsigned int FreqCounter::f_comp;void FreqCounter::start(int ms) {#if defined (__AVR_ATmega32U4__)//(__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || (__AVR_ATmega1280__)    TIMSK0 &=~(1<<TOIE0);       // disable Timer0  //disable  millis and delay    delayMicroseconds(50);      // wait if any ints are pending        f_period=ms;        if (f_comp ==0) f_comp=1;  // 0 is not allowed in del us    // hardware counter setup ( refer atmega32u4)    TCCR1A=0;                  // reset timer/counter1 control register A    TCCR1B=0;                 // reset timer/counter1 control register A    TCNT1=0;             // counter value = 0 TCNT3=0;    // set timer/counter1 hardware as counter , counts events on pin T1 ( arduino pin 12)    // normal mode, wgm10 .. wgm13 = 0        TCCR1B |=  (1<<CS10) ;//CLOCK ESTERNO su fronte di salita    TCCR1B |=  (1<<CS11) ;    TCCR1B |=  (1<<CS12) ;        // timer3 setup / usato per la generazione del tempo di lettura    TCCR3A=0;    TCCR3B=0;        // timer3 presaler set to 64 / timer3 clock = 16Mhz / 64 = 250.000 Hz    TCCR3B &= ~(1<<CS30) ;    TCCR3B |=  (1<<CS31) ;    TCCR3B |=  (1<<CS32) ;    //setta il timer3 to CTC(Clear Timer on Compare)  Mode with OCR3A is top counter value (arrivato a OCR3A si resetta)    TCCR3A &= ~(1<<WGM30) ;    TCCR3A &= ~(1<<WGM31) ;    TCCR3A |=  (1<<WGM32) ; TCCR3A &= ~(1<<WGM33) ;    OCR3A = 249;                // CTC divider by 250      f_ready=0;                  // reset period measure flag    f_tics=0;                   // reset interrupt counter    GTCCR = (1<<PSRASY);        // reset presacler counting (perchÃ¨ resettarlo?)    TCNT3=0;                    // timer3=0    TCNT1=0;                    // Counter1 = 0        TIMSK3 |=(1<<OCIE3A);       // enable Timer3 Interrupt (interrupt di Timer/Counter3 Compare Match A)                                    // External clock source on T1 pin. Clock on rising edge.    TCCR1B |= (1<<CS12) | (1<<CS11) | (1<<CS10);        //   start counting now        #endif}//******************************************************************//  Timer3 Interrupt Service is invoked by hardware Timer3 every 1ms = 1000 Hz//  16Mhz/64/250 = 1000 Hz//  here the gatetime generation for freq. measurement takes place: //ISR(TIMER3_COMPA_vect) { // multiple 2ms = gate time = 100 msif (FreqCounter::f_tics >= FreqCounter::f_period) {                                     // end of gate time, measurement ready   // GateCalibration Value, set to zero error with reference frequency counter    //  delayMicroseconds(FreqCounter::f_comp); // 0.01=1/ 0.1=12 / 1=120 sec    delayMicroseconds(FreqCounter::f_comp);    TCCR1B = TCCR1B & ~7;   // Gate Off  / Counter T1 stopped    TIMSK3 &= ~(1<<OCIE3A);     // disable Timer3 Interrupt(timer del gate)    TIMSK0 |=(1<<TOIE0);     // enable Timer0 again // millis and delay    FreqCounter::f_ready=1;             // set global flag for end count period                                            // calculate now frequeny value    FreqCounter::f_freq=0x10000 * FreqCounter::f_mlt;  // mult #overflows by 65636    FreqCounter::f_freq += TCNT1;       // add counter1 value    FreqCounter::f_mlt=0;        }    FreqCounter::f_tics++;             // count number of interrupt events    if (TIFR1 & 1) {           // if Timer/Counter 1 overflow flag    FreqCounter::f_mlt++;               // count number of Counter1 overflows    TIFR1 =(1<<TOV1);         // clear Timer/Counter 1 overflow flag    }    // PORTB = PORTB ^ 32;   // int activity test}`

#### dariq88

#42
##### Jan 03, 2014, 05:32 pm
Now the library also works for leonardo
Code: [Select]
`#include "FreqCounter.h"volatile unsigned long FreqCounter::f_freq;volatile unsigned char FreqCounter::f_ready;volatile unsigned char FreqCounter::f_mlt;volatile unsigned int FreqCounter::f_tics;volatile unsigned int FreqCounter::f_period;volatile unsigned int FreqCounter::f_comp;void FreqCounter::start(int ms) {#if defined (__AVR_ATmega32U4__)    f_period=ms/2;    f_ready=0;                  // reset period measure flag    f_tics=0;                   // reset interrupt counter        if (f_comp ==0) f_comp=1;  // 0 is not allowed in del us     // hardware counter setup ( refer atmega32u4)    TCCR1A=0;                  // reset timer/counter1 control register A    TCCR1B=0;                 // reset timer/counter1 control register A    TCNT1=0;               // counter value = 0     // set timer/counter1 hardware as counter , counts events on pin T1 ( arduino leonardo pin 12)    // normal mode, wgm10 .. wgm13 = 0        TCCR1B |=  (1<<CS10) ;//CLOCK ESTERNO su fronte di salita    TCCR1B |=  (1<<CS11) ;    TCCR1B |=  (1<<CS12) ;        // timer0 setup / usato per la generazione del tempo di lettura    TCCR0A=0;    TCCR0B=0;        // timer3 presaler set to 256 / timer3 clock = 16Mhz / 256 = 62.500 Hz    TCCR0B = (1<<CS02);     //setta il timer0 to CTC(Clear Timer on Compare)  Mode with OCR3A is top counter value (arrivato a OCR3A si resetta)     TCCR0A = (1<<WGM01);  // CTC mode, normal (no Output compare)     GTCCR |= (1<<PSRASY);  // reset prescaler (undocumented bit in mega32u4?)     TCCR0B = (1<<CS02);  // timer0 on clk/256 == 16MHZ / 256 = 62500hz..     OCR0A = 124;  // 125 counts of 62500 Hz before an output compare interrupt...     TCNT1 = 0;     TCNT0 = 0;     TIMSK0 = (1<<OCIE0A);    #endif }//******************************************************************//  Timer3 Interrupt Service is invoked by hardware Timer3 every 1ms = 1000 Hz//  16Mhz/256/124 = 500 Hz (corretto con il dimezzamento del period)//  here the gatetime generation for freq. measurement takes place: //ISR(TIMER0_COMPA_vect) { // multiple 2ms = gate time = 100 msif (FreqCounter::f_tics >= FreqCounter::f_period) {                                      // end of gate time, measurement ready    // GateCalibration Value, set to zero error with reference frequency counter    //  delayMicroseconds(FreqCounter::f_comp); // 0.01=1/ 0.1=12 / 1=120 sec     delayMicroseconds(FreqCounter::f_comp);    TCCR1B = TCCR1B & ~7;    // Gate Off  / Counter T1 stopped     TIMSK0 &= ~(1<<OCIE0A);    // disable Timer3 Interrupt(timer del gate)    //TIMSK0 |=(1<<TOIE0);      // enable Timer0 again // millis and delay    FreqCounter::f_ready=1;             // set global flag for end count period                                            // calculate now frequeny value    FreqCounter::f_freq=0x10000 * FreqCounter::f_mlt;  // mult #overflows by 65636    FreqCounter::f_freq += TCNT1;      // add counter1 value    FreqCounter::f_mlt=0;        }    FreqCounter::f_tics++;            // count number of interrupt events    if (TIFR1 & 1) {          // if Timer/Counter 1 overflow flag    FreqCounter::f_mlt++;               // count number of Counter1 overflows    TIFR1 =(1<<TOV1);        // clear Timer/Counter 1 overflow flag    }    }`

#### robtillaart

#43
##### Jan 03, 2014, 06:52 pm
Thanks for fixing Leonardo support,

TCCR1B=0;                    // reset timer/counter1 control register A

mismatch between code and comment

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### dariq88

#44
##### Jan 03, 2014, 07:59 pm
Ops,probably there are others mismatch, sorry

Go Up