正確な時間を取得するにはどうすればよいですか?


16

Arduinoを使用して時計を作成しましたが、時間がずれているようです。ロールオーバーの問題を認識しています。時計は1週間で約15分ドリフトするようです。

Digi-keyのこの共振器でカスタムPCBを使用しています。コードは、各ループの開始時にmillis()関数を読み取り、その値から機能します。

私の質問は、Arduinoで時間を測定するにはどうすればよいですか。


3
ミリ秒関数には、実行に数クロックサイクルかかる割り込みからデータが提供されます。これにより、各ティックにわずかな時間が追加されます。
TheDoctor 14

3
@TheDoctor:これは間違っています。割り込みは、駆動するハードウェアタイマーを遅くしませんmillis()
エドガーボネット

回答:


15

注:私の答えは受け入れられ、より高い投票スコアを持っていますが、ArduinoにRTCを使用せずに時間を維持させる方法に関するエドガーボネットの素晴らしい答えを必ず読んでください。

DS1307リアルタイムクロックの使用に非常に成功しています。データシートへのリンクはこちらです。

以下にその機能の一部を示します。

  • Arduinoとの通信にICインターフェースを使用しているため、適切なライブラリ(ネットで入手可能)を使用して簡単にプログラミングできます。

  • SCLおよびSDAピン(それぞれアナログA4およびA5)を介してArduinoに接続されているため、2つのピンのみを使用します。

  • 実行に必要な外部コンポーネントはごくわずかです。

  • ITはコイン型電池に接続できるため、Arduinoがオフになっていても時間を維持できます。低電力モードでは、コイン型電池は数年間持続します。

  • ドリフトはほとんどありません(私の場合、週に数秒しかドリフトしません)。

  • それほど高価ではありません。

RTCを使用する予定がない場合は、Farnelまたは他のこのような水晶発振器モジュールにArduinoにクロックを提供するために一般的に使用される水晶を交換できます。以下の画像のように、4ピンパッケージで提供されます。彼らはあなたのarduinoのためにより正確な時計を生成します。

水晶振動子イメージ 水晶振動子イメージ 水晶振動子イメージ

記載されているモジュールは両方とも50 ppmの許容誤差を持ち、5 Vで動作します。

繰り返しますが、明確にするために、これらの水晶発振器モジュールは、以下のような通常の2ピンクリスタルと混同しないでください。これらは、たとえば、MCUの外部クロックの回路の一部です。

水晶発振器


DS1302で十分ですか、DS1307に移行する必要がありますか?
ケリーS.

14

クロックを構築するためにRTCは必要ありません。ATmegaチップには、RTC自体の機能を実行するために必要なすべてのハードウェアが備わっています。方法は次のとおりです。

  1. 32768 Hzの時計用クリスタルを購入します。購入するか、古い時計を分解します。これらの水晶は、特に時間管理のために設計されており、温度ドリフトが非常に小さくなっています。RTCチップを使用する場合は、これらのいずれかが必要です。

  2. ATmegaのヒューズを8 MHz RCオシレーターで動作するように設定します。これにより、millis()機能が恐ろしく不正確になり、XTAL1ピンとXTAL2ピンも解放されます。

  3. 時計のクリスタルをTOSC1およびTOSC2ピンに接続します。これらはXTAL1およびXTAL2と同じピンです(328Pでは9および10)。異なる名前は、異なる機能を意味するために使用されます。

  4. タイマー/カウンター2を非同期操作、通常のカウントモード、プリスケーラーを128に設定し、タイマーオーバーフロー割り込みを有効にします。

これで、1秒に1回という非常に安定した速度でTIMER2_OVF割り込みが発生します。ISRで時計の表示を1秒進めるだけです。割り込みの間に、MCUを非常に深いスリープ(省電力スリープモード:タイマー/カウンター2以外は何も実行しない)にして、数個のAAセルで何年も実行できます。ディスプレイが電力を大量に消費する場合を除き、明らかに。

私はこれを24時間片手で壁掛け時計を作るために丁度やりました。このリンクは、フランス語の元のドキュメントの英語の翻訳を指すようになりました。

クォーツ校正

クォーツのキャリブレーションを行わない場合、通常は週に数秒の大きなドリフトが予想されます。ドリフト率は、水晶をMCUに接続するトレースの浮遊容量に依存します。原則として、微調整された静電容量を追加することで除去できます。RTCで同じドリフトの問題が発生することに注意してください。

この種の精度に満足しているなら、それで生きて幸せになりましょう。ただし、ドリフトを測定する場合は、ドリフトが非常に安定していることに気付くでしょう。その後、ソフトウェアで簡単に補正し、年間数秒の精度を達成できます。

ドリフトを修正するアルゴリズムは非常に簡単です。測定されたドリフトから、割り込み間の正確な遅延を計算します。これは10 9  ナノ秒に非常に近いはずです。

#define ONE_SECOND    1000000000  // in nanoseconds
#define ONE_INTERRUPT  999993482  // for example

ISR(TIMER2_OVF_vect)
{
    static uint32_t unaccounted_time;

    unaccounted_time += ONE_INTERRUPT;
    while (unaccounted_time >= ONE_SECOND) {
        advance_display_by_one_second();
        unaccounted_time -= ONE_SECOND;
    }
}

上記の例では、クォーツの速度がわずかに速すぎるため、ソフトウェアは数日ごとにティックを「逃す」ことで補正します。クォーツが遅すぎる場合は、代わりに同じコードが数日に1回ダブルティックします。

この種のキャリブレーションはRTCに対しても実行できますが、RTCは時間を自然に算術演算に役立たない内訳形式で報告するため、大幅に複雑になります。


うわー、それは本当に滑らかなデザインです!愚かなアメリカ人にとっても、デザインを明確にするのに十分な写真を載せた方法が本当に好きです:)
ジョンウォルター

2
@JohnWalthour:ありがとう!今、あなたは私に翻訳を書くことを奨励しています。:-)
エドガーボネット

2
@JohnWalthour:完了!リンクは英語の翻訳を指すようになりました。
エドガーボネット

「ATmegaチップに必要なすべてのハードウェアが揃っている」と言うと、明確にするために、新しいクリスタルを入手しなければならない場合、それは完全に真実ではありません。あなたの解決策は洗練されており、水晶を交換する以上のものではないと思いますが、ハードウェアを必要とせずに向きを変えてハードウェアを交換する必要があると言うと少し混乱しました。
ケリーS.

@ KellyS.French:私の文章は、「ATmegaチップにはRTC自体の役割を実行するために必要なすべてのハードウェアが搭載されています」(強調を追加)です。しかし、その後、ユビキタスDS1307を含むほとんどのRTCが動作するために外部クリスタルが必要であることに注意することが重要です。ATmegaにも違いはありません。RTC 自体を交換するために必要なものはすべて備えていますが、とにかくRTCに接続する必要があるクリスタルを交換するためではありません。RTCのことに注意してくださいモジュールがある以上、それは結晶を含まないように、単にRTCより。
エドガーボネット

6

指定した共振器の安定性は0.3%で、水晶または水晶発振器(Ricardoによると)は50ppmです。何倍も安定しています。共振器の温度ドリフトは恐ろしいことは言うまでもありません。日光で加熱すると変化します。したがって、長時間にわたって時間を維持するために共振器を使用しないでください。

したがって、水晶または水晶発振器のいずれかを使用すると、必要なものが得られます。ATmegaでそれを使用してヒューズをそれぞれ設定するか、RTCに接続されたヒューズを使用します。


50ppmは0.005%の安定性ですか?
マシューG. 14

回答を簡潔にするために、この仕様を一般化します。Res以外の安定性に注意してください。許容誤差がはるかに大きく、かなりずれている可能性があります。ジョン・Wが経験しているように。「正しい仕事のための右の部分」
mpflaga

ああ、用語@mpflagaに興味がありました...初めてです。
マシューG. 14

4

リアルタイムクロック(DSDS1307など)のような追加のハードウェアを使用したくない場合は、未使用の割り込みをすべて無効にすることで、タイミングの精度を大幅に向上させることができます。デフォルトでは、Arduinoスケッチにはさまざまな割り込みルーチンが有効になっており、実際のスケッチには使用されないことがよくあります。あなたがそれを試して無効にするためにそれをせずに行うことができるかどうかを調べる最も簡単な方法noInterrupts();


3
-1(これは-4に値しますが)理由は次のとおりです。1.実際にそれらを必要としない限り、すべての割り込みはデフォルトで無効になっています。2. Arduinosのタイミング精度は、主に共振器の品質によって制限されます。3.割り込みの精度に影響しない何かmillis()あなたが他の問題を持っている場合にはあなたがそれらにサービスを提供し、一度に複数のミリ秒を過ごすために管理していない限り、... 4.無効割り込みnoInterrupts()防ぐことができますmillis()すべての時間を保つことからを!
エドガーボネット

2

私は、Arduinoの精神の多くが質素で、時には問題を突き抜けていることを理解しています。私は職場でArduinoを使用しています(現在はRAMが10倍、クロック速度が10倍であるため、chipKIT)。可能な限り高速で動作するために「周辺機能」が必要です。

プロジェクトの1つでsparkfunリアルタイムクロックを使用していますが、非常に満足しています。また、「Dead on」バリアントもあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.