Go Down

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

Picoteando

#60
Feb 16, 2015, 02:28 pm Last Edit: Feb 18, 2015, 02:18 pm by Picoteando
Hi guys,

This is my first post and actually this is my first project with Arduino. I am trying to understand how that library works and there are some things that I do not understand inside the ISR:

Code: [Select]

ISR(TIMER2_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
      TIMSK2 &= ~(1<<OCIE2A);        // disable Timer2 Interrupt
      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
}


1.- Timer2 interrupt is disabled but it is never enabled again. Is it automatically enabled after the ISR?
2.- Counter T1 is stopped.. what makes it run again? The input signal?
3.- What does "delayMicroseconds(FreqCounter::f_comp);" do? I mean, why do we need that delay and why is f_comp set to 1? Shall I change that value depending on the application?
4.- Why is timer0 enabled every time that the frequency is measured?

Thanks so much!

d866

#61
Mar 20, 2015, 03:30 pm Last Edit: Mar 20, 2015, 03:33 pm by d866
Here is an improved version of the frequency counter sketch. There were a couple of problems with the previous version:

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

Sorry for dragging up an old thread but what is the value of the variable sampleTime in this sketch, is it 0 or is there a standard value for this? I'm slightly confused! I realize I could run  the sketch and print the value to the serial port but I don't have access to my Arduino for a week and it's bugging me!

DevilMoo

Hello!
Is there any method to make the frequency be a "double"?
Thanks!

CrossRoads

double, or long/unsigned long, instead of a float?
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

robtillaart

Hello!
Is there any method to make the frequency be a "double"?
Thanks!
On an AVR [UNO/MEGA] a double equals a float (32 bit IEEE754 float),
other platforms like ARM based DUE might have 64bit double,
Rob Tillaart

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

HBO88

Hello guys,

I have a small question about the frequency counter sketch, from the example of DC42.
Here is "delay(sampleTime)" used.  
I dont want to use delay.

Is it possible to make a timing with millis() or something instead of delay for this sketch?
Thanks in advance.


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

robtillaart

Check the - blink without delay - example sketch. It shows how to write delay less
Rob Tillaart

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

HBO88

Thanks for your reply Rob,
But when i tried it with the millis timer, I get a overflow of the reading??
It is maybe something simple, but i don't see the problem.

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;
unsigned long currentMilis;
unsigned long lastMilis = 0;
float Hz;


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
}




void loop()
{
  currentMilis = millis();
  attachInterrupt(2, isr, RISING);    // enable the interrupt
  
  if (currentMilis - lastMilis > 1000) // instead of using delay(1000)
  {
    detachInterrupt(2);
    lastMilis = currentMilis;
    numPulses = 0;                      // prime the system to start a new reading
    Hz =  (1000000.0 * (float)(numPulses - 2)) / (float)(lastPulseTime - firstPulseTime);
  }
  Serial.println(Hz);


}

HBO88

I found the problem!
It was not an overflow, but divided with 0.

When my if statement was true, i first set the numPulses to 0, and then calculate my Hz.
numPulses have to be set 0 after my calculation, so it is solved now.

The complete code for a accurate frequency measurement without using delay:

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;
unsigned long currentMilis;
unsigned long lastMilis = 0;
float Hz;



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
attachInterrupt(2, isr, RISING);    // enable the interrupt
}




void loop()
{
currentMilis = millis();
 attachInterrupt(2, isr, RISING);    // enable the interrupt
  
  if (currentMilis - lastMilis > 1000) // instead of using delay(1000)
  {
   detachInterrupt(2);
   lastMilis = currentMilis;
   Hz =  (1000000.0 * (float)(numPulses - 2)) / (float)(lastPulseTime - firstPulseTime);
  
     numPulses = 0;  
    attachInterrupt(2, isr, RISING);    // enable the interrupt  
}
   Serial.println(Hz);

}

Chrislid

Hello guys !!!

Just a small error in the previous code writted by HBO88...
You mixed up the number of the interruption and the number of PIN !!!!
Be carefull

Correction:
Please replace attachInterrupt(2, isr, RISING); by attachInterrupt(0, isr, RISING);

Otherwise congratulation for the rest!

Chris,

full_throttle

hi , i want ask some question. how about i want measure frequency from function generator by using arduino uno. can i connect direct from function generator to analog pin . thank you

polymorph

full_throttle, you should start your own thread. You'll get a lot more answers that way.

And place this question in something like Project Guidance, or General Electronics.
Steve Greenfield AE7HD
Drawing Schematics: tinyurl.com/23mo9pf - tinyurl.com/o97ysyx - https://tinyurl.com/Technote8
Multitasking: forum.arduino.cc/index.php?topic=223286.0
gammon.com.au/blink - gammon.com.au/serial - gammon.com.au/interrupts

tk5ep

@HBO88

I tried your modified version, but it's not working as expected on an UNO.
A have an incoherent value and often "inf" or "ovf"

Any help ?

idans

hi i wish to use freqcounter lib with pwm output, is it possible to use pwm when waiting to interrupt on timer2?

barryx

Anyone tried getting the FreqCount running a Zero? I'm looking to measure a input signal that varies from around 100kHz to 80kHz. Been trying to figure all the internal routing of the Zero to make this happen withou any success yet.

Go Up