工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduino Nanoのみで作る高精度時計 ─ 内部クロック誤差をソフト補正

概要

外部RTCモジュールなしで、Arduino Nanoの内蔵クロックのみを用いて高精度な時計を実現。内部クロックの系統誤差を実測し、ソフトウェアで毎時補正することで、5日間で誤差ゼロを達成した手法を解説します。16×2 LCD表示、3ボタンで時刻・日付・補正値設定可能。

核心アイデア:誤差の実測と定常補正

  1. Arduinoのmillis()とPCの高精度クロックを比較し、1時間あたりの誤差(ミリ秒)を測定
  2. 測定値をspeedCorrection変数に格納
  3. 自作ミリ秒カウンタで毎時speedCorrectionを加減算し、誤差を打ち消し

必要な部品

誤差測定用ツール

付属のArduinoスケッチ+Processingスクリプトで自動測定可能。Arduinoが2秒ごとに経過ミリ秒を送信、Processing側でPCクロックと比較し、1時間後の差分を算出。

独自ミリ秒カウンタ(Timer0割り込み)

millis()は約50日でオーバーフローし、書き換え不可。そこでTimer0のCTCモードで1ms割り込みを自作し、任意リセット可能なカウンタを実装。

// Timer0を1ms割り込みに設定(16MHz/64分周)
TCCR0A = (1 << WGM01);        // CTCモード
OCR0A = 0xF9;                 // 249 = 1ms
TIMSK0 |= (1 << OCIE0A);      // 比較一致割り込み有効
TCCR0B |= (1 << CS01) | (1 << CS00); // 分周 1/64
TCNT0 = 0;
sei();                        // 全割り込み有効

volatile unsigned long currentTime = 0; // 0時からの経過ms
volatile unsigned long elapsed = 0;     // 汎用経過カウンタ

ISR(TIMER0_COMPA_vect) {
  if (currentMode != SET_TIME) currentTime++;
  elapsed++;
}

日次・時間次処理

// 日付またぎ処理(24時間 = 86,400,000 ms)
if (currentMode == SHOW_TIME && currentTime > MILLIS_PER_DAY) {
  noInterrupts();
  currentTime -= MILLIS_PER_DAY;
  interrupts();
  currentDate++; // ユリウス日で管理
}

// 毎時の誤差補正
if (elapsed >= MILLIS_PER_HOUR) {
  noInterrupts();
  currentTime += speedCorrection; // 正なら遅れ補正、負なら進み補正
  elapsed = 0;
  interrupts();
}

日付管理:ユリウス日

日付をユリウス日(紀元前4713年1月1日からの日数)で保持。グレゴリオ暦⇔ユリウス日相互変換関数で表示・設定を実現。うるう年・世紀末スキップも自動計算。

操作モード(モードボタンで遷移)

モード内容アップ/ダウン操作
時刻表示通常動作-
時刻設定時・分設定時/分 インクリメント
年設定年設定年 ±1
日月設定日・月設定日/月 インクリメント(月末自動調整)
補正値設定速度補正調整±5ms/ステップ

実測結果

コード全文(主要部)

#include 
LiquidCrystal lcd(12, 13, 6, 7, 8, 9);

#define MODE_BTN 2
#define UP_BTN 3
#define DOWN_BTN 4

enum { SHOW_TIME=1, SET_TIME, SET_YEAR, SET_DATE, SET_SPEED_ADJ };
int currentMode = SHOW_TIME;
int speedCorrection = 3545; // 実測値に書き換え

volatile unsigned long currentTime = 0, elapsed = 0;
unsigned long lastTime = -1000;
float currentDate = JulianDate(1,1,2021), lastDate = 0;
const unsigned long MILLIS_PER_DAY = 86400000UL;
const unsigned long MILLIS_PER_HOUR = 3600000UL;

void setup() {
  // Timer0 1ms割り込み設定(上記参照)
  pinMode(MODE_BTN, INPUT_PULLUP);
  pinMode(UP_BTN, INPUT_PULLUP);
  pinMode(DOWN_BTN, INPUT_PULLUP);
  lcd.begin(16, 2);
}

void loop() {
  // 日付またぎ・毎時補正(上記参照)
  checkButtons(); // ボタン処理でモード遷移・値変更
  
  switch (currentMode) {
    case SHOW_TIME: showTime(currentTime); showDate(currentDate); break;
    case SET_TIME: showTimeSet(currentTime); break;
    case SET_YEAR: showYearSet(currentDate); break;
    case SET_DATE: showDDMMSet(currentDate); break;
    case SET_SPEED_ADJ: showSpeedSet(); break;
  }
  wait(150); // 自作delay
}

// ユリウス日変換、時刻分解、ボタン処理、LCD表示関数等は全文参照

メリット・デメリット

まとめ

「RTCモジュールを買うほどでもないが、そこそこの精度が欲しい」用途に最適なソフトウェアRTC手法です。クロック誤差が一定である前提ですが、実用上十分な精度が得られます。

製造プロセス

  1. Arduino POVクロック:残像効果で浮かび上がるLED時計を自作する
  2. ArduinoだけでDTMFデコーダーを構築 – 外付けIC不要
  3. Arduinoで作るモニター用Ambilightシステム:没入感アップの自作ガイド
  4. Adafruit 60 LED NeoPixelリングとArduinoで作るスタイリッシュな壁掛け時計
  5. DIY Arduinoワードクロック – 文字で時刻を表示する洗練されたリアルタイムクロック
  6. Arduino で作るイスラム教礼拝時刻付きリアルタイムクロック
  7. 12メートル先から見える大型LEDマスタークロック(アラーム機能付き)を自作しよう
  8. Arduinoとスマホで作るスマート電圧計 – 簡単DIYプロジェクト
  9. ArduinoとMAX30100で作るリアルタイムIoT心拍数モニター
  10. Arduino UNO WiFi Webサーバー:ブラウザからLEDをON/OFF制御
  11. Arduino Pro MiniとDS1302 RTCで作る高精度7セグメント時計
メリットデメリット
外部部品不要(RTCモジュール・電池不要)電源断で時刻リセット(バックアップ不可)
低コスト・シンプル個体ごとに校正必須、温度ドリフト未補償
50日オーバーフロー問題を解決高精度用途にはDS3231/GPS推奨