Clock calibrator

Thinking out aloud here and .. will this work ?
I want to time a pendulum ( ~1sec period) and was planning to use an interrupt and within its service routine take a note of micros () , then repeat at the next passing of the pendulum - the difference in two occurrences telling me the period .
I’m thinking in both cases the machine cycles between detecting the input interrupt and taking a micros reading will be the same .So the difference will be the true time difference .
Was planning on using a 328 with a 2.5ppm 16Mhz Crystal , so my accuracy will be similar ?? ( I have no way to calibrate this , but looking for the best result I can get )
Will any code running between interrupts affect the result ( just thinking in terms of taking , say , 10 readings then reporting the result )

Yes. millis() and micros() run continuously in the background and they are as accurate as the processor clock.

But from what I remember reading, I'm pretty sure micros() doesn't get updated once per us so it doesn't have 1us precision/resolution... It might not be accurate to the exact microsecond but it won't drift any more than the main clock. For a ~1 second measurement it should be "fine" but you could have issues measuring just a few microseconds.

Got a feeling you might be right - I’ll look that up-Yes , resolution is 4uS on 328 based system , not an issue that

If you want to know the exact frequency, you should measure more than one period to average out the timing measurement skew.

1 PPS from GPS?

I have one, bring your project to me and test.

M good offer thanks - haven’t built it yet !!!

If you have a GPS module, then Perry Bebbington's suggestion will work to calibrate the Arduino CPU clock frequency, to very high accuracy (to better than 1 part in 10^8 if I recall correctly).

I used Nick Gammon's code for that, on the Uno :

// Frequency timer using input capture unit
// Author: Nick Gammon
// Date: 31 August 2013
// added averaging JR 2015
// Input: GPS 1PPS capture signal on Pin D8

volatile boolean first;
volatile boolean triggered;
volatile unsigned int overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;

// timer overflows (every 65536 counts)
ISR (TIMER1_OVF_vect)
{
  overflowCount++;
}  // end of TIMER1_OVF_vect

ISR (TIMER1_CAPT_vect)
{
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = ICR1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)
    overflowCopy++;

  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
  {
    startTime = (overflowCopy << 16) + timer1CounterValue;
    first = false;
    return;
  }

  finishTime = (overflowCopy << 16) + timer1CounterValue;
  triggered = true;
  TIMSK1 = 0;    // no more interrupts for now
}  // end of TIMER1_CAPT_vect

void prepareForInterrupts ()
{
  noInterrupts ();  // protected code
  first = true;
  triggered = false;  // re-arm for next time
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;

  TIFR1 = bit (ICF1) | bit (TOV1);  // clear flags so we don't get a bogus interrupt
  TCNT1 = 0;          // Counter to zero
  overflowCount = 0;  // Therefore no overflows yet

  // Timer 1 - counts clock pulses
  TIMSK1 = bit (TOIE1) | bit (ICIE1);   // interrupt on Timer 1 overflow and input capture
  // start Timer 1, no prescaler
  TCCR1B =  bit (CS10) | bit (ICES1);  // plus Input Capture Edge Select (rising on D8)
  interrupts ();
}  // end of prepareForInterrupts


void setup ()
{
  Serial.begin(115200);
  Serial.println("Frequency Counter");

  pinMode(8, INPUT_PULLUP);
  pinMode(7, OUTPUT);
  digitalWrite(7, LOW);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);


  // set up for interrupts
  prepareForInterrupts ();
} // end of setup

void loop ()
{
  static unsigned long average = 0;
  static int n = 0;
  // wait till we have a reading
  if (!triggered)
    return;

  PINB |= (1 << 5); //blink LED

  // period is clock cycles in one second
  unsigned long elapsedTime = finishTime - startTime;

  Serial.println (elapsedTime);
  average += elapsedTime;
  n++;
  if (n == 10) {
    Serial.print("System clock count, average of ten: ");
    Serial.println(average / 10);
    n = 0;
    average = 0;
  }


  // so we can read it
  delay (500);

  prepareForInterrupts ();
}   // end of loop

Thanks , I’ll look that up - very useful

@jremington

Do you have a link to that Nick Gammon code , I can’t find it in his site .
Thx

  • edit* just ordered a GPS Module !
1 Like

Gammon timers scroll down to input capture.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.