0

I have a very fast signal connected to pin2 of an Arduino Mega 2560. The signal is a square wave of approximately 500 000 Hz. I would like to measure the frequency of this signal.

First approach Updating a counter inside the interrupt service routine and computing the inverse of it every second should be enough.

Second approach setting a timer interrupt, as suggested by @Majenko, to compute the frequency of the signal based on the amount of increments received in a constant interval of time.

The Problem

micros() and millis() aren't working properly with this fast input signal, as described in this question. So I cannot count how many increments the counter variable had in one second. Any advice?

1

volatile unsigned long counter = 0;

void setup(){
   pinMode(pinInt,INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(pinInt),frequencyCheck,FALLING);
   tempo = millis()
}

/*
* ISR: FrequencyCheck
*/
void frequencyCheck(){
 counter++;
}

void loop() {  
   Serial.print("Tempo: ");
   Serial.print(tempo);
   Serial.print(" millis: ");
   Serial.print(millis());
   Serial.print(" micor: ");
   Serial.println(micros());

  if (millis() - tempo >= 1000) {
   Serial.print(" 1 sec! counter value: ");
   Serial.print(counter);

   // Reset tick count  
   counter = 0;
   tempo = millis();
 }
}

This is the output of the program with the 500 kHz square wave:

Tempo: 0.00 millis: 0 micor: 1864
Tempo: 0.00 millis: 0 micor: 1352
Tempo: 0.00 millis: 0 micor: 1868
Tempo: 0.00 millis: 0 micor: 1356
Tempo: 0.00 millis: 0 micor: 1868
Tempo: 0.00 millis: 0 micor: 1360
Tempo: 0.00 millis: 0 micor: 1816
Tempo: 0.00 millis: 0 micor: 1304
Tempo: 0.00 millis: 0 micor: 1760

2

int pinInt = 2;
float tempo = 0;
volatile unsigned long counter = 0;
volatile float frequencies = 0, oldVal=0, periodISR = 0.0;
volatile float sigma = 0.01, delta = 0.0;
volatile unsigned long int ticks = 0;

void setup() {
  Serial.begin(115200);
  pinMode(pinInt,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(pinInt),frequencyCheck,FALLING);
  Serial.println("Ready");
  setupTimerInterrupt();
}

/*
* ISR: FrequencyCheck
*/
void frequencyCheck(){
 counter++;
}


void setupTimerInterrupt()
{
 // Timer settings
 // Initialize Timer
 noInterrupts();
 TCCR3A = 0;
 TCCR3B = 0;

 // Set compare match register to the desired timer count
 //OCR3A=14; //16*10^6/(1043Hz*1024)-1 = 14 -> 1043 Hz
 //OCR3A=77; //16*10^6/(200Hz*1024)-1 = 77 -> 200 Hz
 //OCR3A=193; //16*10^6/(80Hz*1024)-1 = 193 -> 80 Hz
 //OCR3A=103; //16*10^6/(150Hz*1024)-1 = 103 -> 150 Hz
 OCR3A=143; //16*10^6/(109Hz*1024)-1 = 143 -> 109 Hz s
 //OCR3A=780; //16*10^6/(20Hz*1024)-1 = 780 -> 20 Hz
 //OCR3A=2000; //16*10^6/(8Hz*1024)-1 = 780 -> 8 Hz
 //OCR3A=50; //16*10^6/(308Hz*1024)-1 = 50 -> 308 Hz 

 TCCR3B |= (1 << WGM32);
 // Set CS10 and CS12 bits for 1024 prescaler:
 TCCR3B |= (1 << CS30) | (1 << CS32);
 // enable timer compare interrupt:
 TIMSK3 |= (1 << OCIE3B);

 // enable global interrupts:
 interrupts();
}

// Interrupt Service Routine
ISR(TIMER3_COMPB_vect) {
   ticks++;

   // compute frequency
   noInterrupts();
   delta = 0.0091743119/counter;
   interrupts(); 
                                   //I couldn't use a computed ISR period 
                                   // because of the micros issue, so I    
                                   // used the period of time corresponding to 
                                   // 109Hz directly

 //reset counter interrupt
 counter = 0;
}

void loop() {
   Serial.print(" micor: ");
   Serial.print(delta,7);
   Serial.print(" Counter: ");
   Serial.println(counter);
   Serial.print(" mil: ");
   Serial.println(millis());
}

Please note that I have addede a second argument to the Serial.print() function to specify the format of the fload to be 7 decimal precision. Unfortunately, the output shows that the frequency value is not updated... Any advice on this approach?

 micor: 0.0000000 Counter: 17216864 mil: 0
 micor: 0.0000000 Counter: 17233980 mil: 0
 micor: 0.0000000 Counter: 17251112 mil: 0
 micor: 0.0000000 Counter: 17268276 mil: 0
 micor: 0.0000000 Counter: 17285424 mil: 0
 micor: 0.0000000 Counter: 17302548 mil: 0
  • 2
    The Arduino probably isn't fast enough to do this in software. You should investigate timers. – Majenko Dec 15 '17 at 15:07
  • 2
    I would suggest using a timer to count the incoming pulses. Use the square wave as the clock source. – Majenko Dec 15 '17 at 15:11
  • 2
    The interrupt is firing too fast and not giving millis() a chance to work. – Majenko Dec 15 '17 at 15:14
  • 1
    There are numerous examples of using timers to implement a frequency counter. For one: gammon.com.au/timers – jose can u c Dec 15 '17 at 16:01
  • 1
    Don't attachInterrupt(), use the signal as a clock source to the timer, as Majenko suggested in his comment. That's really the only reasonable approach at this kind of frequency. – Edgar Bonet Dec 15 '17 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.