Pages: 1 2 [3] 4   Go Down
Author Topic: Frequency Counter Library  (Read 37644 times)
0 Members and 1 Guest are viewing this topic.
Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
thanks in advance.
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

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.

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The frequency will be between 85 and 255Hz.
I am using a pulse Generator which gives sqare waves with a maximum of 5V.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13479
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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
Logged

Rob Tillaart

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

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Try this:

Code:
// 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 Hz
unsigned 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);
}
Logged

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.

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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 Hz
float 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);
}
« Last Edit: October 18, 2013, 04:07:23 am by dc42 » Logged

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.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13479
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Very good sample DC42,
another argument to use float division is that integer division truncates.

(you just beat me smiley
Logged

Rob Tillaart

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

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh great! Thanks alot!!
This Frequency counter works really really good for me! Now I can move on  smiley ...
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

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.

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i have a small question for u..that is it possible to measure the freq of the sine wave using arduino...
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

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.

Offline Offline
Newbie
*
Karma: 1
Posts: 37
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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
}
« Last Edit: December 17, 2013, 03:50:13 pm by dariq88 » Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 37
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Now the library also works for leonardo
Code:
#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
    }
   
}
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13479
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for fixing Leonardo support,

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

mismatch between code and comment smiley

Logged

Rob Tillaart

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

Offline Offline
Newbie
*
Karma: 1
Posts: 37
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ops,probably there are others mismatch, sorry smiley-yell
Logged

Pages: 1 2 [3] 4   Go Up
Jump to: