# Measuring Time while using interrupt pin

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

• The Arduino probably isn't fast enough to do this in software. You should investigate timers. – Majenko Dec 15 '17 at 15:07
• 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
• The interrupt is firing too fast and not giving millis() a chance to work. – Majenko Dec 15 '17 at 15:14
• 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
• 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