Go Down

Topic: i want to read frequency realtime (Read 17019 times) previous topic - next topic

copachino

this code its from techone, but this only read the frequency of one second, but its there a possible way to read 
"real time", for example and oscillospe reads the frequency realtime, without counting it, like this code.... im not making oscilloscope but its an example, i want to read frequency to make an inertial dyno..... but i need the reading of angular velocity(rev per second) on real time(may be a delay)....... hope anyone could help me clear this out




Code: [Select]
byte freqpin = 2;

unsigned long timeone;

unsigned int frequency;
unsigned int timediff;

unsigned int tcount=0;

// sample time of 1 second or 1000 ms.
unsigned int sampletime=1000;

volatile unsigned int count=0;

void setup()
{
pinMode(freqpin, INPUT);
attachInterrupt(0,freqinput,RISING);
// set interrupt pin 2 and use rising ( from gnd to +5 )
  Serial.begin(9600);
}

void loop()
{
/* Use while() loop and use millis().
    Calculate the time difference and compare the
    value with the sample time.
*/
// activate the interrupt
tcount=0;
count=0;
timediff=0;
attachInterrupt(0,freqinput,RISING);

timeone=millis();
while(timediff<sampletime)
{
  tcount=count;
  timediff=millis()-timeone;
}
// de-activated the interrupt
detachInterrupt(0);

// Calculated frequency
frequency=tcount;

// Display frequency
Serial.print("Test while - ");
Serial.print("Frequency : ");
Serial.println(frequency,DEC);
delay (3000);



// The interrupt routine
void freqinput ()
{
  count++;

PeterH

What do you mean when you say "real time"?

copachino

#2
Feb 10, 2012, 02:28 am Last Edit: Feb 10, 2012, 02:34 am by copachino Reason: 1
i mean that every milisecond i get the real frequency of what i am meassuring an not just the counting of the frequency in a given time...

ok for me to explain just take a look in the code the code just counts the frequency so if a reduce the semple time to 500miliseconds and i imput a frequency of 10khz, arduino will print to serial only 5khz.... i dont want that, i want tha every 100miliseconds o maybe less arduino prints 10khz.... so i want the real frequency in serial always......

retrolefty

If you truly want or need 'real-time' frequency measurements then you have to leave the world of digital and build it in the analog world. There have been true F-to-V analog chips that output a DC measurement value proportional to the frequency of the input signal. However you are going to have to come up with requirement specifications before running off to find proper components and chips.

Frequency range, what is the minimum and maximum frequency to be measured.
That is the minimum and maximum amplitude voltage of the input signal.
What is wave form shape of the input signal.
What DC measurement range do you require.

Now back to reality, frequency measurements are best done in the digital world and have been for a pretty long time. Just define how fast an update time you require and state the input frequency range to be measured, What measurement resolution you require and then see if there is not a digital solution to the problem. You know you don't have to count for a full second to measure the frequency of a signal?

Lefty 

copachino


You know you don't have to count for a full second to measure the frequency of a signal?

Lefty 


thats what i dont know how to program, the measureing of a frequency without countig for a full second for now in the code i just change the sampletime to 1 mili and before print just multiply by 1000 but it gives me a hugh error in the measuring.... for now "real time" i know its impossible to get. and probebly i dont need it i just need a faster update of the real frequency

retrolefty



You know you don't have to count for a full second to measure the frequency of a signal?

Lefty  


thats what i dont know how to program, the measureing of a frequency without countig for a full second for now in the code i just change the sampletime to 1 mili and before print just multiply by 1000 but it gives me a hugh error in the measuring.... for now "real time" i know its impossible to get. and probebly i dont need it i just need a faster update of the real frequency


Well I will only give you a hint how the big boy frequency counters measure in much shorter update windows. Instead of counting the input signal for a fixed period, they something take a high speed fixed oscillator, say 10mhz, and let the input signal define the gate time for counting the those fixed frequency pulses. So say you have a 60hz input signal to be measured. You start counting the 50mhz pulses at the zero crossing of the 60hz signal and stop counting at the next zero crossing. You then end up with the number of 100nsec counts for a 8.333millisecond period. A little math and you will have a new measurement in well under 10millsec time span.

I'm sure the same principles can be applied to an arduino using it's built in timers, proper commands and calculations. However again until you define your specific specifications of the input signal it's hard to start.

Lefty

copachino

thanks for replying...... i am reading an analog sensor which was adapted for a square signal needed for hardware interrupts, the are measuring speed of an engine, in an oscilloscope readings are 10,680hz, and if a use the code from above it oscilates in that frequency but if a change sample time to reduce it and then multiply the output if gives likes 20% error....

the signal its square from 5v to 0v

nickgammon

Your problem is the counts in the sample time. For example, if you sample for 1 mS then the number of counts would be:

Code: [Select]
.001 / (1 / 10680) = 10.68

In other words, it will count either 10 or 11 maybe. My tests of a frequency of 10680 bear this out:

Code: [Select]
Frequency: 11000
Frequency: 10000
Frequency: 11000
Frequency: 11000
Frequency: 10000


If you count for 2 mS you will get:

Code: [Select]
.002 / (1 / 10680) = 21.36

That is, 21 or 22 counts.

We are now closer:

Code: [Select]
Frequency: 10500
Frequency: 10500
Frequency: 10500
Frequency: 10500
Frequency: 10500
Frequency: 11000
Frequency: 11000
Frequency: 11000


So you have the trade-off, of faster results vs. lower accuracy.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jwatte

Frequency is a time domain phenomenon, that does not exist instantaneously.

If you know a whole lot about the signal (what the waveform is, what the amplitude is, what the likely frequency range is, etc), then you can take a few quick samples of the signal, and fit those samples to your model of the waveform, to estimate the frequency. However, that's always an application-specific "tunable" process, not a "true" frequency measurement.

A good middle ground mostly-well-behaved signals is to measure the time between zero crossings -- typically in one particular direction (say, negative to positive). Keep the time of the last zero crossing, and the next time it happens, subtract that time from the current time. Invert, to get an estimate of frequency. You can keep multiple samples of zero crossings in a FIFO to measure across more cycles, and get more stability but slower response time to changes.

copachino


Your problem is the counts in the sample time. For example, if you sample for 1 mS then the number of counts would be:

Code: [Select]
.001 / (1 / 10680) = 10.68

In other words, it will count either 10 or 11 maybe. My tests of a frequency of 10680 bear this out:

Code: [Select]
Frequency: 11000
Frequency: 10000
Frequency: 11000
Frequency: 11000
Frequency: 10000


If you count for 2 mS you will get:

Code: [Select]
.002 / (1 / 10680) = 21.36

That is, 21 or 22 counts.

We are now closer:

Code: [Select]
Frequency: 10500
Frequency: 10500
Frequency: 10500
Frequency: 10500
Frequency: 10500
Frequency: 11000
Frequency: 11000
Frequency: 11000


So you have the trade-off, of faster results vs. lower accuracy.

well i will have to guest how many samples per second are needed for a good test graph.......and also get good frequency reads..... any filter o something else could be possible applied to get the nearest possible to real frequency??

nickgammon

#10
Feb 10, 2012, 06:10 am Last Edit: Feb 10, 2012, 06:27 am by Nick Gammon Reason: 1

Well I will only give you a hint how the big boy frequency counters measure in much shorter update windows. Instead of counting the input signal for a fixed period, they something take a high speed fixed oscillator, say 10mhz, and let the input signal define the gate time for counting the those fixed frequency pulses.


Based on Lefty's suggestion I have adapted my earlier timing sketch to use this method.

Code: [Select]
// Frequency timer
// Author: Nick Gammon
// Date: 10th February 2012

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

// here on rising edge
void isr ()
{
  unsigned int counter = TCNT1;  // quickly save it
 
  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
    {
    startTime = (overflowCount << 16) + counter;
    first = false;
    return; 
    }
   
  finishTime = (overflowCount << 16) + counter;
  triggered = true;
  detachInterrupt(0);   
}  // end of isr

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


void prepareForInterrupts ()
  {
  // get ready for next time
  EIFR = _BV (INTF0);  // clear flag for interrupt 0
  first = true;
  triggered = false;  // re-arm for next time
  attachInterrupt(0, isr, RISING);     
  }  // end of prepareForInterrupts
 

void setup () {
  Serial.begin(115200);       
  Serial.println("Frequency Counter");
 
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  // Timer 1 - interrupt on overflow
  TIMSK1 = _BV (TOIE1);   // enable Timer1 Interrupt
  // zero it
  TCNT1 = 0;     
  // start Timer 1
  TCCR1B =  _BV (CS20);  //  no prescaling

  // set up for interrupts
  prepareForInterrupts ();   
 
} // end of setup

void loop ()
  {

  if (!triggered)
    return;

  unsigned long elapsedTime = finishTime - startTime;
  float freq = 1.0 / ((float (elapsedTime) * 62.5e-9));  // each tick is 62.5 nS
 
  Serial.print ("Took: ");
  Serial.print (elapsedTime);
  Serial.print (" counts. ");

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

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

  prepareForInterrupts ();   
}   // end of loop


This sets up Timer 1 as a high-resolution timer, that is, it ticks every clock cycle, namely every 62.5 nS.

We connect our input to D2 and look for rising interrupts (so from one rising pulse to the next is the period). By counting how many lots of 62.5 nS we got we can work out the period. Take the inverse and we have the frequency. Like this, for 10,680 Hz:

Code: [Select]
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1497 counts. Frequency: 10688.04 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1501 counts. Frequency: 10659.56 Hz.
Took: 1500 counts. Frequency: 10666.67 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1497 counts. Frequency: 10688.04 Hz.
Took: 1497 counts. Frequency: 10688.04 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1501 counts. Frequency: 10659.56 Hz.
Took: 1499 counts. Frequency: 10673.78 Hz.
Took: 1502 counts. Frequency: 10652.46 Hz.
Took: 1501 counts. Frequency: 10659.56 Hz.



This sketch seems to work up to about 90 KHz, after which it can't keep up.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

copachino

amazing, ive just uploaded and seems to be a lot more stable than the old one.... probably with a low-pass filter this could be more accurate.......... but this code need all arduino speed right??? so wont be enable to process a filter???

nickgammon

Well you can do whatever you want. :)

After all, we are reading an almost-instantaneous frequency (by measuring a single period). So you can do whatever, and then measure another one.

I added a simple counter, like this:

Code: [Select]
unsigned long foo;

And then in loop:

Code: [Select]
void loop ()
  {

  foo++;
 
  if (!triggered)
    return;

// .. and the rest of it


At 10680 Hz foo got up to around 41, so you could add up 41 things while it was actually counting.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

copachino

probably could try something to improve those jumps in frequency but im testing 10khz as signal and thats a lot more than i need in fact so for less speed i supposed there are more accuracy.... ill try with 1khz an see if it goes well than i wont use anything to try to improve this, if its needed probably youll se me asking for help here again.....

thanks so much for sharing the code

nickgammon

My pleasure. At 1 KHz I got a pretty accurate reading:

Code: [Select]
Took: 16015 counts. Frequency: 999.06 Hz.
Counted up to: 520
Took: 16015 counts. Frequency: 999.06 Hz.
Counted up to: 522
Took: 16017 counts. Frequency: 998.94 Hz.
Counted up to: 521
Took: 16017 counts. Frequency: 998.94 Hz.
Counted up to: 521
Took: 16016 counts. Frequency: 999.00 Hz.
Counted up to: 518
Took: 16016 counts. Frequency: 999.00 Hz.


That's only 0.1% out.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up