I think that the miscounting is due to the time that it takes for the interrupt to begin counting pulses.
To demonstrate this, I modified your code to turn pin 8 high at the beginning of the 'counting_start' ISR and then low again at the beginning of the 'counting_stop' ISR.
I used direct port manipulation to make the pin change state as quickly as possible (in 1 clock cycle : 62.5ns).
/*
Count pulses on pin 5 via Timer-1
Start with rising edge on pin 2
Stop with falling edge on pin 2
ToDo:
- deal with overflows
*/
#include <Streaming.h>
void setup() {
Serial.begin(19200);
pinMode(2, INPUT); digitalWrite(2, HIGH); // trigger on pin-2 = PD2 = interrupt-0
pinMode(5, INPUT); digitalWrite(5, HIGH); // pulses on pin-5 = PD5 = T1
pinMode(8, OUTPUT);
TCCR0A = 0; // setup timer-0
TCCR0B = 0;
TIMSK0 = 0;
TCCR2A = 0; // setup timer-2
TCCR2B = 0;
TIMSK2 = 0;
TCCR1A = 0; // setup timer-1
TCCR1C = 0;
TIMSK1 = 0;
GTCCR = 0;
counting_stop();
}
void loop() {
Serial << "Counting:" << endl;
while (1) {}
}
void counting_start() {
// Serial << "Ready ... ";
PORTB = 0B00000001;
TCCR1B = 7; // start
attachInterrupt(0, counting_stop, FALLING); // ready to stop
}
void counting_stop() {
PORTB = 0B00000000;
unsigned long counts;
TCCR1B = 0; // stop
counts = TCNT1;
TCNT1 = 0;
attachInterrupt(0, counting_start, RISING); // ready to start
Serial << counts << " pulses" << endl;
}
You can see from the following oscilloscope trace that it takes just over 3µs for the ISR to start working. This means that at a frequency of 1MHz the first 3 pulses don't get counted.
I sent 26 pulses to pin 5, but only 23 are counted.
- Channel 1 - yellow trace - signal to pin 2.
- Channel 2 - red trace - pin 8, counting occurs when high.
- Channel 3 - blue trace - 26 pulses at 1MHz to pin 5.
The trace above also shows why in my earlier tests when I had a continuous stream of pulses that I counted more pulses than expected.
It takes 3µs for pin 8 to go high after pin 2 goes high, but 5µs to go low after pin 2 goes low. Thus I was counting for an extra 2µs.
