Please help me understand this code

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.