Wrong values from ADC Arduino - frequency meter

Thread Starter

RazvanT19

Joined Apr 21, 2020
7
Hi there!

I'm building a frequency meter using as input a sine wave between 0.05V-0.55V (from a peak detector) and a frequency range between 5Khz-10Khz. I tried to change the sampling rate (I need at least 20Khz) to 76Khz (setting 16 prescaler from ADCSRA register), but the resulting data from ADC it's a constant (=255). I didn't find anything which could cause this constant output.

Having a higher sampling rate means that I could find more precisely the max amplitudes and then I could measure the time period between two max amplitudes resulting the frequency.

Any help or tips would be much appreciated! Thanks in advance!
Output
Input

Code:
const int MAX_RESULTS = 256;
volatile int results [MAX_RESULTS];
volatile int resultNumber;

void setup() {
  ADMUX = 0x20; // set A0 analog input
  ADCSRA = 0xEC;// set 16 prescaler, enable ADC and interrupts and start ADC measurements
  Serial.begin(115200);
}

  ISR (ADC_vect)
{
    results[resultNumber++] = ADCH;
    if(resultNumber == MAX_RESULTS)
    {
      ADCSRA = 0;  // turn off ADC
    }

}

void loop () {
  while (resultNumber < MAX_RESULTS)
    { }

for (int i = 0; i < MAX_RESULTS; i++)
  {
    Serial.println (results[i]);
  }
  //start a new conversion
  resultNumber = 0;
  ADCSRA = 0xEC;
}[code]
 
Last edited by a moderator:

Thread Starter

RazvanT19

Joined Apr 21, 2020
7
The problem's here: ADMUX = 0x20, this value means that I disabled the internal reference. I changed 0x20 to 0x60, it works fine, but I'm thinking how to calculate the frequency for this output wave: dropbox.com/s/9ce297vr7b77d19/out.png?dl=0

wave_red.jpg

Moderators note : embeded reduced image
 
Last edited by a moderator:

danadak

Joined Mar 10, 2018
4,057
You have to calibrate against a known clock. Does your board have a crystal
for base clock generation ? If not it will take an external clock to cal against.

Or you write a cal routine during production test where you feed chip a highly
accurate clock, the cal routine compares against freq measured, and a least squares
error curve fit equation or power series equation is developed where you compute
its coefficients as you sweep freq/temperature/voltage. The equation then is used to
correct freqs measured. This is more advanced case as you now have all these
tests to perform in manufacturing.


Regards, Dana.
 

MrChips

Joined Oct 2, 2009
30,712
You do not need to use the ADC in order to measure frequency. ATmega328 has internal timer/counter modules which are capable of counting external signals up to 16MHz.
 

BobTPH

Joined Jun 5, 2013
8,813
And why are you using a peak detector when trying to measure frequency? A peak detector is designed to remove the frequency and follow the amplitude.

Bob
 

Plamen

Joined Mar 29, 2015
101
Frequency meters are digital in nature - they count pulses per second (Hz) or per ms (kHz).
Their input signal has to be shaped first to logic level (High/Low) pulses. This is traditionally done by Schmitt triggers - for instance comparator based with positive feedback. The input signal may have to be conditioned first if it is not monotonous (risk of counting harmonics). If the signal is not strictly periodical (or modulated) and has relatively limited frequency range (say 20 to 1) - a Phase locked loop (PLL) like LM567 could be used to condition and shape to logic level.
 

djsfantasi

Joined Apr 11, 2010
9,156
That’s not how you use an ISR on an Arduino.

in the setup, you need to convert the pin you’re using for the interrupt from a digital PIN number to an ISR PIN number.

The absence of attachInterrupt() is what drew my attention.

Then you use the attachInterrupt() function to define which function is executed when an interrupt occurs on the specified pin. You also define whether the ISR is triggered on a rising edge, a trailing edge or both.

Another useful command is the Arduino pulseIn() command. This command triggers at the beginning of a pulse and returns the microseconds it is HIGH. A similar use for when its low gives you the period and hence the frequency.
 

Thread Starter

RazvanT19

Joined Apr 21, 2020
7
Frequency meters are digital in nature - they count pulses per second (Hz) or per ms (kHz).
Their input signal has to be shaped first to logic level (High/Low) pulses. This is traditionally done by Schmitt triggers - for instance comparator based with positive feedback. The input signal may have to be conditioned first if it is not monotonous (risk of counting harmonics). If the signal is not strictly periodical (or modulated) and has relatively limited frequency range (say 20 to 1) - a Phase locked loop (PLL) like LM567 could be used to condition and shape to logic level.
I used a comparator as you said, but now the output needs an offset to have positive amplitude. Do you have any suggestion? out_comparator.jpg
 

Thread Starter

RazvanT19

Joined Apr 21, 2020
7
Frequency meters are digital in nature - they count pulses per second (Hz) or per ms (kHz).
Their input signal has to be shaped first to logic level (High/Low) pulses. This is traditionally done by Schmitt triggers - for instance comparator based with positive feedback. The input signal may have to be conditioned first if it is not monotonous (risk of counting harmonics). If the signal is not strictly periodical (or modulated) and has relatively limited frequency range (say 20 to 1) - a Phase locked loop (PLL) like LM567 could be used to condition and shape to logic level.
Thanks for your suggestion!
 

Thread Starter

RazvanT19

Joined Apr 21, 2020
7
That’s not how you use an ISR on an Arduino.

in the setup, you need to convert the pin you’re using for the interrupt from a digital PIN number to an ISR PIN number.

The absence of attachInterrupt() is what drew my attention.

Then you use the attachInterrupt() function to define which function is executed when an interrupt occurs on the specified pin. You also define whether the ISR is triggered on a rising edge, a trailing edge or both.

Another useful command is the Arduino pulseIn() command. This command triggers at the beginning of a pulse and returns the microseconds it is HIGH. A similar use for when its low gives you the period and hence the frequency.
Thanks!
 
Top