Frequency Counter Library

Please do not paint belts. The paint may damage the belt (thanks to the enclosed / entrained solvents) and lead to premature cracking. Not only are modern belts very expensive to replace, losing one will usually leave you stranded. Not the best way to impress the missus.

Instead use a hall-effect or optical rig on a sprocket or similar device that does not need physical modification.

Constantin:
The paint may damage the belt (thanks to the enclosed / entrained solvents) and lead to premature cracking.

Honestly this is not my place to expertise but it would seem there is certain types of paints that would not be a problem.

Not only are modern belts very expensive to replace, losing one will usually leave you stranded. Not the best way to impress the missus.

Last time I looked, the belts were not all that expensive. But losing one can indeed leave you stranded but alas this is a risk with any type of engine modification.

SmeezeKitty, do as you wish.

All I can tell you is that I had to replace every rubber hose on a diesel engine because some lugnut sprayed them with the same 'Perkins blue' as the rest of the engine. And to do that, we got to lift the engine out of the boat, drain it of all fluids, etc. Not the fastest fix.

Every hose had cracked thanks to this painting treatment. Given how important belts are, I wouldn't mess with them and pick up the desired signal elsewhere.

I got this to work well on one sensor, using my Arduino UNO.

But I have not been able to get it to work at all on a Leonardo. [ Serial doesn't even print the 'Frequency Library' line at the start] Have there been major changes to serial for Leonardo?

Another question is, how would I be able to expand this to multiple sensors without using multiple Arduinos?

Hello to everybody, first of all I'm not an expert altought I have succeed so far with some small Arduino based project.
I'm now trying to develop a radioastronomic receiver (radiometer) controlled by Arduino.
Now the topic:

  • I have an Arduino Uno rev.2 with an Ethernet shield with microSD slot (both not yet used, but useful later on)
  • In order to control the receiver I have to program 2 different PWM on 2 different pins
  • for what I read on the web pages, I can use the instruction analog.write(pin,pwm) on the pins 3,5,6,9,10,11 if not already used by other devices
  • the pin 5 (T1) is used to read the OL frequency of the receiver by means of the library FreqCounter.h herewith discussed..
  • pin 3 seems to be used by the Eth shield as well as the pins 0,1,2,4,10,14,15
  • thus, "fre to be used" for my purpose, remain the pins 6,9,11

Unfortunately only the output on the pin 6 works. Pins 9 and 11 always are at low level, no PWM, even with no shield on top of the Arduino Uno.
The board works fine is I do not call the frequency reading routine.
What I'm doing wrong? Waht shall I do to fix the trouble?
On the following a draft of the cose I'm using. Please note it's a very early draft of what I would do, so several variables are defined but not used yet.

Many thanks to all for the help!
Pierluigi

#include <FreqCounter.h>

// OL input on digital pin #5

const short pwm1=9; // pin 9 is 8 MSB PWM
const short pwm2=6; // pin 6 is 8 LSB PWM

long int frq; //frequency read
long int IF=10700000; // first IF of the Rx
const short prescaler=8; // scale factor of the ext. prescaler
const long int fastro1=25610000; // astro1 = 1st frequency
const long int fastro2=13385000; // astro2 = 2nd frequency
long int OLnow; // current OL frequency
long int RXnow; // current RX frequency
long int errore=0; // frequency error

int pwmh; // 8 MSB of PWM
int pwml; // 8 LSB of PWM

float Vastro1=0.2035; // VCO nominal input for fastro1
// float Vastro2=3; // VCO nominale per rx frequenza fastro2

int bitbase1=Vastro165535/5; // total PWM bits (res.16) of feed forward VCO a freq. astro1
// int bitbase2=Vastro2
65535/5; // bit di PWM totali (risoluzione 16) del feed forward tensione VCO a freq. astro1

void setup() {
Serial.begin(9600); // connect to the serial port
Serial.println("Frequency Counter");
}

void loop() {

FreqCounter::f_comp= 5; // Set compensation
FreqCounter::start(1000); // Start counting with gatetime of 100ms
while (FreqCounter::f_ready == 0) // wait until counter ready

frq=FreqCounter::f_freq; // read result
OLnow= frq*prescaler; // OL frequency calculation
RXnow= OLnow-IF; // RX frequency from IF and OL
errore= RXnow-fastro1; // tuning freq. errorcalcolo errore di sintonia

pwmh= bitbase1/256;
pwml= bitbase1-256*pwmh;

analogWrite(pwm1, pwmh);
analogWrite(pwm2, pwml);

Serial.print("bitbase1= ");
Serial.print(bitbase1);
Serial.print(" pwmh= ");
Serial.print(pwmh);
Serial.print(" pwml ");
Serial.print(pwml);
Serial.print(" frq= ");
Serial.print(frq);
Serial.print(" OLnow= ");
Serial.print(OLnow);
Serial.print(" RXnow= ");
Serial.print(RXnow);
Serial.print(" Errore= ");
Serial.println(errore);
delay(20);
}

How about a variation on the frequency counter lib that takes its input from the analog comparator? This would avoid the need for a preamplifier. You wouldn't be able to count the input directly in counter 2 because AFAIK it can't be clocked from the analog comparator output. However, you could use the analog comparator interrupt to count pulses, and use timer 1 as before to define the gate time.

Hey,
first of all, thanks for the great library!

I have a small issue with my LEDs and this library. They are working if I give them the value "HIGH" or "255". But however they are not working with a lower value. I have tested the leds in an other sketch. So they are correctly wired and working fine, also the arduino. It seems to be a problem with the "FreqCounter::start(100);", if I remove it, the lower values are working, but of course the frequency counter not...

has someone an idea? thanks in advance!

Assuming you mean the frequency counter library at http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/, it uses timers 1 and 2, and disables timer 0 during the gate time. This means that none of the PWM pins on a Uno will work while you are measuring a frequency.

If the frequency you want to measure is less than about 10kHz, there are other ways of measuring it that take over only one timer, or even no timers at all.

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.

  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?

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

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

Try this:

// 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);
}

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.

// 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);
}

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

(you just beat me :slight_smile:

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

One thing I found while testing this is that the PWM frequency on pin 3 is not 488.28Hz as documented at Arduino Playground - 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.

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

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
}