Frequency Counter Library

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.

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

#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 ms
if (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
}

Now the library also works for leonardo

#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 ms
if (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
    }
    
}

Thanks for fixing Leonardo support,

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

mismatch between code and comment :slight_smile:

Ops,probably there are others mismatch, sorry :stuck_out_tongue_closed_eyes:

I use the frequency library on both Mega ADK ( modified library) and Nano board.
When i measure a precise 1.000.000 Hz signal I get 1.000.169 on the display.
I try to correct this with f_comp but it seems that i can only increase the displayed reading.
How can I decrease the reading to 1.000.000 ??

Thanks for a nice frequency library. Very usefull.

Hello dc42.

I just tested your improved version of a frequency counter sketch (Reply#35).
Frequency Counter Library - Science and Measurement - Arduino Forum .
It works great!. Is is possible to modify it to read frequencies between 1Hz to 3Hz. So far, I can measure with your code frequencies over 2.99Hz.

Thank you.
Palliser

Can I detect a guitare sound frequency with it?

Can anyone help me?

I have a bipolar signal from 40mVp to 4Vp (it has 2Kohm impedance too as it comes from an inductance). I want to measure his frecuency. I tried all configurations possible withouth succesful.

My first approach was plug into V+ and V- in an operational with open loop (so i have an square output and a single edge detector with a timer will measure). The output is not consistent due to the small voltage of the signal i guess.

I tried a transistor with the signal attached to the base and collector so it enables. It does not work either. The solution with the biestable is not possible due to the small Voltage of the signal when low frecuencies.

Thanks in advance.

Hi!

I'm trying to measure frequency, and display always return on decimal place less. It should show 26640, but show only 2664. I also tryed to increase/decrease frequency, but same error occur.

I'm using FreqCounter library.

This is the code:

#include <FreqCounter.h>


unsigned long frq;
int cnt;
int pinLed=13;

void setup() {
  pinMode(pinLed, OUTPUT);

  Serial.begin(115200);        // connect to the serial port

  Serial.println("Frequency Counter");
}


void loop() {

  // wait if any serial is going on
  FreqCounter::f_comp=10;   // Cal Value / Calibrate with professional Freq Counter
  FreqCounter::start(100);  // 100 ms Gate Time

  while (FreqCounter::f_ready == 0) 

  frq=FreqCounter::f_freq;
  Serial.print(cnt++);
  Serial.print("  Freq: ");
  Serial.println(frq);
  delay(20);
  digitalWrite(pinLed,!digitalRead(pinLed));  // blink Led

}

Please help !

BR !

Mladen

while (FreqCounter::f_ready == 0)

is this really what you meant ?
or is the ; missing

while (FreqCounter::f_ready == 0) ;

the difference is effectively a different loop

while (FreqCounter::f_ready == 0)
{
frq=FreqCounter::f_freq;
}

or

while (FreqCounter::f_ready == 0) {}
frq=FreqCounter::f_freq;

Hmm...

I didn't notice missing ; since compiled without error. But I have found yet another post with similar problem. I'll try your both proposal. Thank you.

kurtommy:
There is a workoround for use with servo library?

I have not yet tried this code yet, so if it doesn't work I am sorry! When I thought of a workaround, I was thinking external. I found the liked below chip on adafruit that takes an I2C signal and can create PWM without using the AtMel's PWM. As long as the communications clock is not disabled or messed up, something like this might work for you.

Hi,

I am trying to make that library work with the leonardo / Micro but can't figure it out. I replaced the code below in the FreqCounter.cpp found here : http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-frequency-counter-library/

Does anybody actually ever sucessed to measure frequency using TIMER 3 on a Leonardo?

dariq88:
Now the library also works for leonardo

#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 ms
if (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
    }
   
}

I'm also having trouble with the Frequency Counter examples, and have tried most of the suggestions within
this thread (and others). The #if and #endif lines were commented out within the Frequency.cpp file, however
the problem still exists.

The error message that is displayed when trying to upload the code is, "redefinition of 'long unsigned int frq' "

I've attached a screen shot of the entire log of errors which also shows the code version that I'm using.
The error might be caused by the board which is the Dcduino Mega 2560.

I do have an authentic Arduino Mega 2560 at home, which I'll try this evening (not sure of the chipset at the moment)

Is this message consistent with the incorrect Arduino board/chipset, or outdated .CPP file? Otherwise, I don't see any
problem with the code?

// Frequency Counter Lib example

/*
  Martin Nawrath KHM LAB3
  Kunsthochschule f¸r Medien Kˆln
  Academy of Media Arts
  http://www.khm.de
  http://interface.khm.de/index.php/labor/experimente/	
 */
#include <FreqCounter.h>


unsigned long frq;
int cnt;
int pinLed=13;

void setup() {
  pinMode(pinLed, OUTPUT);

  Serial.begin(115200);        // connect to the serial port

  Serial.println("Frequency Counter");

}



void loop() {

  // wait if any serial is going on
  FreqCounter::f_comp=10;   // Cal Value / Calibrate with professional Freq Counter
  FreqCounter::start(100);  // 100 ms Gate Time

  while (FreqCounter::f_ready == 0) 

  frq=FreqCounter::f_freq;
  Serial.print(cnt++);
  Serial.print("  Freq: ");
  Serial.println(frq);
  delay(20);
  digitalWrite(pinLed,!digitalRead(pinLed));  // blink Led

}

I was able to successfully measure frequency using the following code on the Dcduino. I would
expect this to work on the Mega as well.

#include <FreqMeasure.h>

double sum=0;
int count=0;
float frequency;

void setup() 
{
  Serial.begin(57600);
  FreqMeasure.begin();
}


void loop() 
{
  if (FreqMeasure.available()) 
    {

    // average several reading together
    sum = sum + FreqMeasure.read();
    count = count + 1;
    
    if (count > 30) {
      float frequency= FreqMeasure.countToFrequency(sum / count);
      Serial.println(frequency);
      sum = 0;
      count = 0;
      delay(100);
    }
  }
}

I also am trying to use the library on a Blend Micro (Leonardo + Bluetooth LE chip), and no luck. I double-checked the pin assignments to connect the signal to Counter1, but it never counts any pulses. It works great on a Pro Trinket.

Hi,

please, someone can use the Frequecy Counter Library with Arduino Leonardo (ATmega32u4)?? I read some threads but nobody have been able to use it :cry:

I need to measure the frequency that comes from an external circuit.

Thanks!

I think you should start a new thread specific to your application. What frequency range? What is the signal like, is it low voltage AC, a DC squarewave, 0-12V?

I need to measure a signal with a frequency in the order of 500KHz-600KHz. The amplitude is about 1V, but about this point I can add a level shifter.

Currently, I am using a code below for the Yun (by Nick Gammon) but I cannot measure signal with frequency above 250KHz. How can I extend the range?

// Frequency timer using input capture unit
// Author: Nick Gammon
// Date: 31 August 2013

// Input: Pin D4 on YUN Bill Gilbert 20141015_13:44 Works

#include "Bridge.h"
#include "Console.h"

volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;

// timer overflows (every 65536 counts)
ISR (TIMER1_OVF_vect) 
{
  overflowCount++;
}  // end of TIMER1_OVF_vect

ISR (TIMER1_CAPT_vect)
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = ICR1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;
  
  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)
    overflowCopy++;
  
  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
    {
    startTime = (overflowCopy << 16) + timer1CounterValue;
    first = false;
    return;  
    }
    
  finishTime = (overflowCopy << 16) + timer1CounterValue;
  triggered = true;
  TIMSK1 = 0;    // no more interrupts for now
  }  // end of TIMER1_CAPT_vect
  
void prepareForInterrupts ()
  {
  noInterrupts ();  // protected code
  first = true;
  triggered = false;  // re-arm for next time
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  
  TIFR1 = bit (ICF1) | bit (TOV1);  // clear flags so we don't get a bogus interrupt
  TCNT1 = 0;          // Counter to zero
  overflowCount = 0;  // Therefore no overflows yet
  
  // Timer 1 - counts clock pulses
  TIMSK1 = bit (TOIE1) | bit (ICIE1);   // interrupt on Timer 1 overflow and input capture
  // start Timer 1, no prescaler
  TCCR1B =  bit (CS10) | bit (ICES1);  // plus Input Capture Edge Select (rising on D8)
  interrupts ();
  }  // end of prepareForInterrupts
  

void setup () 
  {
      // initialize serial communication:
  Bridge.begin();
  Console.begin(); 

  pinMode(5,INPUT); 
 
  while (!Console){
    ; // wait for Console port to connect.
  }
  Console.println("You're connected to the Console!!!!");
   delay(1000); 
  
  Console.begin();       
  Console.println("Frequency Counter");
  // set up for interrupts
  prepareForInterrupts ();   
  } // end of setup

void loop () 
  {
  
  // wait till we have a reading
  if (!triggered)
    return;
 
  // period is elapsed time
  unsigned long elapsedTime = finishTime - startTime;
  // frequency is inverse of period, adjusted for clock period
  float freq = F_CPU / float (elapsedTime);  // each tick is 62.5 nS at 16 MHz
  
  Console.print ("Took: ");
  Console.print (elapsedTime);
  Console.print (" counts. ");

  Console.print ("Frequency: ");
  Console.print (freq);
  Console.println (" Hz. ");

  // so we can read it  
  delay (1);

  prepareForInterrupts ();   
}   // end of loop}

If you want, I start with a new thread.