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