hi and thanks for reading my first newbie post. My UNO is beside me right now, connected to my win 7 PC and that's as far as I can get !
Since March I have been building a pendulum clock with a one second beat. For those that are familiar with clocks it's based on the master clocks that were widely used until the 1960's to run strings of slave dials in schools, factories etc.etc. There is a construction blog on my website.
The question. The clock makes an nice short reset pulse every 30 seconds (after processing it drives the dials) I have a GPS receiver giving a precision pulse every one second which I could divide by 30 in hardware if necessary.
The aim is to measure the time between these two pulses to 5 decimal places ( 1/100 th of milliseconds). with a + or - indication of whether the clock is ahead or behind the reference GPS pulse.
I would like to set the period between measurements over the range between 5 to 60 minutes.
And I need the results to be stored.
The problem is I know nothing whatsoever about programming.
Can the Arduino be used for this ? Is there a sketch that could do this or be modified to do it ?
Thanks...RJ
The aim is to measure the time between these two pulses to 5 decimal places ( 1/100 th of milliseconds).
Interrupts and micros().
The problem is I know nothing whatsoever about programming.
That IS a problem. Are you interested in learning?
Can the Arduino be used for this ?
Maybe. It is capable of measuring the time between two pulses very accurately. What you do with that information defines whether or not the Arduino is the right answer.
Is there a sketch that could do this or be modified to do it ?
void setup()
{
}
void loop()
{
}
(Needs a few modifications...)
Than you PaulS for you useful and supercillious reply. I was hoping that someone who perhaps only posts replies occasionally when something comes up which particularly interests them. I could get the impression from yours that newcomers are not welcome here.
The first bit of info I was looking for was if the Arduino is accurate enough for my project I can already measure individual 30 second periods with a Racal timer/counter - but only to 4 decimal places or 1/10,000 sec which has proved to be not accurate enough.
The second was whether Milles or PulseIn sketchs night be a starting point if accurate enough.
I could create a single pulse in hardware that had the time of the period between two separate pulses.
I am willing to learn but was hoping for a leg up.
The resulting time measurement would eventually be logged every hour and saved ideally in comma delineated for placing weekly obs into something like Excell to end up with performance graphs.
Hi,
Why 5 decimal places...What are you going to do with the accuracy information?
Tom....
Like the clocks..
One problem with using an Arduino to monitor a real clock is that an Arduino is not a good timekeeper. Notionally it uses a 16MHz oscillator but in practice it does not oscillate at precisely 16MHz. It would probably be possible to measure the frequency accurately and make adjustments in the code to allow for the actual value. But there is also a risk that the frequency will vary from time to time - perhaps due to temperature.
People who use an Arduino and want it to maintain "clock" time use a Real Time Clock (RTC) module.
Measuring to 10 microsecs may also be a problem because the Arduino increments the value of micros() in steps of 4. Otherwise it would have no spare capacity to do anything useful.
...R
@Tom.
Hi Tom..The Racal timer measures to 4 places every other 30 seconds and is displayed for only 1 sec. But a reading of, say, 30.0003 could be anything from 30.00031 to 30.00039. that's nearly 1/10000th sec. With 2880 30 second periods in a day that's a error of up to about 1/4 sec a day. The target is to get the clock rated to 1 second a week if possible. And therefore to see variations/trends that could be due to temperature or barometric changes.
Later on, if I can ever actually do this, I would try and add temp and pressure to the recorded readings.
Thank you for your interest...
@Robin2
I have been googling all this for some time and had come to wonder about the accuracy.
Quote: Measuring to 10 microsecs may also be a problem because the Arduino increments the value of micros() in steps of 4. Otherwise it would have no spare capacity to do anything useful.]
Does that mean the microseconds are incremented in 4's but that 10's of microseconds are ok ? Sorry if that's a dumb question.
I see that I could buy a RTC based on Maxim DS3232 but am not sure how to make use of one. Do you sample the RT at each pulse and compute the difference within the sketch ?
Roger
Welcome to the forum,
To elaborate on PaulS response,
1/100 of a millisecond is 10 uSec. As the micros() call has a granularity of 4 uSec it is on the edge of measuring the accuracy you want. Measuring 30.000.000 uSec should be possible and as PaulS states you need to use interrupts.
The Pulsein() command has a finer granularity (around 1usec) but it has the flaw that it uses a formula that is based on number of instructions executed. As the Arduino compiler settings changed during the releases and there are different boards, this formula might not be exact. There have been a number of discussions on this forum about it.
Most accurate way would be to implement an HW timer based clock, however that is not trivial.
I made a first version of the code you need, It should help you to get started.
please also read - https://www.arduino.cc/en/Reference/AttachInterrupt - to understand the working a bit.
The first measurement will be wrong as it needs to get in sync with the 30 second pulses. You could add code for that. Note this code is not tested on your system and I am curious how well it will work.
//
// FILE: uSecMeasure.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: measure duration with micros
// DATE: 2015-08-06
// URL: http://forum.arduino.cc/index.php?topic=340081.0
//
// Released to the public domain
//
volatile uint32_t prev =0;
volatile uint32_t now = 0;
volatile bool flag = false;
// IRQ will be called once every 30.0000000 seconds approx.
void IRQ()
{
now = micros();
flag = true;
}
void setup()
{
Serial.begin(115200);
Serial.println("Start uSecMeasure 0.1");
// enable onboard LED
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
// set up measurement
// you neeed to attach the 30 sec clock pulse to on PIN 2 UNO
attachInterrupt(0, IRQ, FALLING); // FALLING might be not the right signal
}
void loop()
{
if (flag)
{
flag = false; // reset for next interrupt
// make a local copy of now
cli(); // cli - sei - is needed as the next line could theoretically be interrupted, changing the value of now
uint32_t localNow = now;
sei();
uint32_t duration = localNow - prev;
prev = localNow;
Serial.println(duration);
// adjust LED to show if it is more than 100 uSeconds off (adjust to your needs)
if ((duration > 30000100UL) || (duration < 29999900UL)) digitalWrite(13, HIGH);
else digitalWrite(13, LOW);
}
}
Rob..Thank you very much. Later today when the house has gone quiet - I have two families holidaying down here ! - I will study the info in the link. Particularly with reference to Interrupts which at present I don't understand. I will learn about all this but my elderly brain is not as good now as it used to be !
Thanks for the comment on the pulsin command. I do understand that...
I've looked through the sketch you have kindly provided. It looks as though the GPS pulse is not used and the Arduino is timing the 30 second periods ? A great start and thanks again for taking the trouble to write it..
I will report back when I've tried it..It may take a few days thou..
Roger
I do keep adding my website address but it keeps disappearing again. But it must have appeared at some time because I think Tom must have seen it.
Roger,
I've been measuring the oscillators in my various projects recently to an accuracy of better than 1ppm. I've been measuring 1 second periods, simply because my reference (a GPS) outputs a 1Hz pulse and that's also a nice rate for viewing from a human perspective. But there's no reason why the same method couldn't be used to measure over 30 seconds.
The basic notion, already mentioned above, is to program a hardware timer directly. I use the 16-bit timer 1 programmed to run at full speed, 62.5ns per step. I feed the PPS signal, which the datasheet of my GPS claims is accurate to ±10ns, into the input capture pin for the timer. The PPS signal edge is latched by hardware and also generates an interrupt allowing an ISR to read the latched timer value. A second ISR counts rollovers of the timer. Together, the rollover and latched value, give a 32-bit time in units of processor clock cycles.
With that I have a very accurate measure of the number of processor cycles each second. Most Arduinos have resonators that vary quite a bit as the temperature changes.
To measure a pulse, I feed the target into a digital pin and sit in a tight loop polling it and recording the timer 1 value and rollover count for each transition. This gives me the pulse width in terms of processor cycles, which I can then compare to the concurrent measurement of processor frequency determined by the PPS measurement.
I haven't spent the time analyzing exactly how accurate this is. I only wanted something good to 1ppm and I'm fairly sure I get at least that.
An interrupt is like an emergency phone call, you stop what you are doing, handle the interrupt and then continue where you left off.
For a processor an interrupt is the fastest way to react on an event.
To keep actions atomic - copying the four byte value of now, takes more than one instruction - one can temporary disable interrupts with cli() and restore them with sei() so the copying is not interrupted (and thereby breaking the logical integrity of the value of now.
Rob,
Won't your method simply reflect the underlying error in his Uno's clock? In 30 seconds a typical Uno's clock will be off by tens of milliseconds. If I understand cornishlad correctly he wants an accuracy of 10 microseconds over that period. Or am I missing something?
I do not expect the clock to drift tens of milliseconds in 30 seconds time, but the proof is in the pudding test.
So yes, I am very interested how well the sketch will work...
It might be that the only way to monitor drift over a day is an GPS unit or sync with NTP ...
Try this simple time counting sketch, see how much drift you see.
I watch it against the official US time clock at http://www.nist.gov/, lower right corner of the page.
unsigned long currentMicros;
unsigned long previousMicros;
unsigned long elapsedTime;
// Initial time to start, 10:00:00 with 90 years, 240 days. (around start of May),
// adjust as needed.
// Get this working, then more display code if needed
byte hundredths;
byte tenths;
byte secondsOnes = 0;
byte oldsecondsOnes;
byte secondsTens = 0;
byte minutesOnes = 0;
byte minutesTens = 0;
byte hoursOnes= 0;
byte hoursTens = 1;
int days = 240; //
byte years = 90;
void setup(){
Serial.begin(115200); // make serial monitor match
Serial.println (Setup Done");
}
void loop(){
currentMicros = micros();
// how long's it been?
elapsedTime = currentMicros - previousMicros;
if ( elapsedTime >=10000UL){ // 0.01 second passed? Update the timers
previousMicros = previousMicros + 10000UL;
hundredths = hundredths+1;
if (hundredths == 10){
hundredths = 0;
tenths = tenths +1;
if (tenths == 10){
tenths = 0;
secondsOnes = secondsOnes + 1;
if (secondsOnes == 10){
secondsOnes = 0;
secondsTens = secondsTens +1;
if (secondsTens == 6){
secondsTens = 0;
minutesOnes = minutesOnes + 1;
if (minutesOnes == 10){
minutesOnes = 0;
minutesTens = minutesTens +1;
if (minutesTens == 6){
minutesTens = 0;
hoursOnes = hoursOns + 1;
if (hoursOnes == 10){
hoursOnes = 0;
hoursTens = hoursTens +1;
if ( (hoursTens == 2) && (hoursOnes == 4){
hoursOnes = 0;
hoursTens = 0;
if (days>1){
days = days-1;
}
else {
days = 365;
years = years - 1;
}
} // 24 hr rollover check
} //hoursTens rollover check
} // hoursOnes rollover check
} // minutesTens rollover check
} // minutesOnes rollover check
} // secondsTens rollover check
} // secondsOnes rollover check
} // tenths rollover check
} // hundredths rollover check
} // hundredths passing check
if (oldSecondsOnes != secondsOnes){ // show the elapsed time
oldSecondsOnes = secondsOnes;
Serial.print (years);
Serial.print(":");
Serial.print(days);
Serial.print(":");
Serial.print(hoursTens);
Serial.print(hoursOnes);
Serial.print(":");
Serial.print(minutesTens);
Serial.print(minutesOnes);
Serial.print(":");
Serial.print(secondsTens);
Serial.println(secondsOnes);
} // end one second check
} // end loop
I have two Unos and they are both about 0.1% slow. I think that's pretty typical for the resonators they have. After 30 seconds the clock would be 30ms short if you're expecting 1 cycle to be 62.5ns. In addition, the resonators are very temperature sensitive.
I have a sketch to measure the frequency. It's not perfect (there are occasional hiccups in the logic) but it works pretty well. I just hooked up an Uno to my GPS and loaded the sketch. Here it is along with the output. You can see the already inaccurate resonator drifting further even in this short time. It will probably drift by an additional 10-20ppm in the next twenty minutes and a lot more over the course of the day as the temperature varies.
// Check processor clock accuracy against GPS
//
// Connect the GPS to the Uno via 5V, GND.
// Connect the PPS signal to the input capture pin D8.
#define PPS_INPUT_PIN 8 // 328 pin 14 (input capture)
// Pin operation macros
#define INPUT_PORT(pin) (pin < 8 ? PIND : (pin < 14 ? PINB : PINC))
#define OUTPUT_PORT(pin) (pin < 8 ? PORTD : (pin < 14 ? PORTB : PORTC))
#define PIN_MASK(pin) (pin < 8 ? 1<<pin : (pin < 14 ? 1<<pin-8 : 1<<pin-14))
#define SET_PIN(pin, level) (level == LOW ? (OUTPUT_PORT(pin) &= ~PIN_MASK(pin)) : (OUTPUT_PORT(pin) |= PIN_MASK(pin)))
volatile uint16_t captureTicks = 0;
volatile uint16_t captureRolls = 0;
volatile uint16_t rollovers = 0;
volatile bool captureFlag = false;
uint32_t prevCaptureTime = 0;
// =======================================================================================
ISR (TIMER1_CAPT_vect)
{
captureTicks = ICR1;
captureRolls = rollovers;
captureFlag = true;
}
ISR (TIMER1_OVF_vect)
{
rollovers++;
}
// =========================================================================================
void setup()
{
Serial.begin(115200);
Serial.println("\nHello\n");
pinMode(PPS_INPUT_PIN, INPUT);
// Set up timer 1 for input capture of PPS signal
TCCR1A = 0; // reset timer1
TCCR1B = 0;
TCNT1 = 0;
TCCR1B = 0x41; // no prescale; capture on rising edge
TIMSK1 = 0x21; // enable capture interrupt; enable overflow interrupt
}
void loop()
{
if (captureFlag) {
uint16_t t = captureTicks;
uint16_t r = captureRolls;
captureFlag = false;
uint32_t captureTime = (uint32_t(r) << 16) + uint32_t(t);
uint32_t elapsed = captureTime - prevCaptureTime;
prevCaptureTime = captureTime;
Serial.print(elapsed);
Serial.print(" cycles/sec, ");
Serial.print(float(elapsed)/16.0 - 1000000.0, 1);
Serial.print(" ppm");
Serial.println();
}
}
È
Hello
553945 cycles/sec, -965378.5 ppm
15983420 cycles/sec, -1036.3 ppm
15983416 cycles/sec, -1036.5 ppm
15983415 cycles/sec, -1036.6 ppm
15983411 cycles/sec, -1036.8 ppm
15983402 cycles/sec, -1037.4 ppm
15983400 cycles/sec, -1037.5 ppm
15983401 cycles/sec, -1037.4 ppm
15983402 cycles/sec, -1037.4 ppm
15983402 cycles/sec, -1037.4 ppm
15983400 cycles/sec, -1037.5 ppm
15983397 cycles/sec, -1037.7 ppm
15983399 cycles/sec, -1037.6 ppm
15983396 cycles/sec, -1037.8 ppm
15983399 cycles/sec, -1037.6 ppm
15983398 cycles/sec, -1037.6 ppm
15983396 cycles/sec, -1037.8 ppm
15983398 cycles/sec, -1037.6 ppm
15983396 cycles/sec, -1037.8 ppm
15983394 cycles/sec, -1037.9 ppm
15983396 cycles/sec, -1037.8 ppm
15983396 cycles/sec, -1037.8 ppm
15983406 cycles/sec, -1037.1 ppm
15983407 cycles/sec, -1037.1 ppm
15983405 cycles/sec, -1037.2 ppm
15983401 cycles/sec, -1037.4 ppm
15983394 cycles/sec, -1037.9 ppm
15983391 cycles/sec, -1038.1 ppm
15983391 cycles/sec, -1038.1 ppm
15983390 cycles/sec, -1038.1 ppm
15983393 cycles/sec, -1037.9 ppm
15983389 cycles/sec, -1038.2 ppm
15983391 cycles/sec, -1038.1 ppm
15983391 cycles/sec, -1038.1 ppm
15983388 cycles/sec, -1038.3 ppm
15983389 cycles/sec, -1038.2 ppm
15983389 cycles/sec, -1038.2 ppm
15983387 cycles/sec, -1038.3 ppm
15983388 cycles/sec, -1038.3 ppm
15983386 cycles/sec, -1038.4 ppm
Nice sketch,
drift is more than I expected, but quite constant in itself (average of -1037.66).
That could help to bring it down to the order of 2 ppm.
or am I too optimistic (again)?
It's not constant. It varies with temperature. Right now, indoors on a cloudy day, it's drifted to -1073ppm.
A crystal is a lot better. But for the 10us over 30s accuracy you'd need a precision of 0.3ppm and a reference so you could calibrate it. You'd still need to keep the temperature within certain bounds.
I think using the GPS to dynamically calibrate his resonator would work. Using the input capture the PPS measurement error would be no more than one clock cycle. So that means a worst case error of two clock cycles to measure the number of cycles between successive PPS pulses. For measuring a second pulse like his pendulum produces, a tight loop (with interrupts disabled just prior to the expected arrival of the pulse) could detect the change of state and then read the timer count and overflow value. I don't know what the error is in a loop like that, maybe 4 cycles? Double it for two measurements and add that to the PPS error and I think he could safely stay within his 10us target. I think. I'd want to test it, maybe by using a second GPS as a control.
There's probably a better, more elegant way to do this. It's just what I came up with for my own purposes.
I wrote a sloppy sketch to test this. Rather than use a second GPS I just used one, feeding the PPS signal into both input pins. So I was using the input capture to measure the clock frequency with the PPS signal and using that result to measure the "other" signal, which was also the PPS. So the error would be a measure of the precision of the method. Over 30 seconds (or any interval, for that matter) the pulse period measurement jitter was ±0.5us and the accuracy should be more or less guaranteed by the GPS itself.
Hi,
You are trying to compare a one second interval from your clock, to a one second interval from the GPS.
Sync the clock and GPS, count say 60 seconds from the clock and from the GPS, then calculate the difference.
You error per second will 1/60th of this.
I know I am preaching to someone who has a better idea than me about timekeeping, but its worth my two bobs worth.
Tom.....
Tom, that's essentially what I've been doing. But there's no reason to wait a full minute. In one second the processor clock nominally advances 16 million steps. That's usually enough. And since the Uno's resonator can drift significantly on the scale of seconds, measuring a longer interval means you end up calculating an average frequency. So I don't think using a longer interval buys you anything -- unless what you're comparing it to is also longer, like in the case of the OP.
There is a construction blog on my website.
Could you share a link please?