Arduino Nanoアナログ時計:DS3231 RTCと1mAアメーターで作る精密木製タイマー
必要な部品と材料
| 部品 | 数量 | 備考 |
|---|---|---|
| Arduino Nano R3 | 1 | 制御用マイコン |
| DS3231M RTCモジュール(±5ppm、I2C) | 1 | 高精度リアルタイムクロック |
| 1mA アナログアメーター(パネルメーター) | 3 | 時・分・秒表示用 |
| 5kΩ 抵抗 | 3 | 各メーターのPWM電流制限用(メーター特性に合わせて調整) |
| 10kΩ 抵抗 | 2 | プルアップ用等 |
| タクトスイッチ 12mm | 2 | 時刻合わせ用(アップ/ダウン) |
使用ソフトウェア
- Arduino IDE
プロジェクト概要
木製ケースに収めたアナログパネルメーターを用いた時計をArduino Nanoで製作しました。DS3231 RTCから時刻を取得し、3つの1mAアメーターをPWM制御で駆動して時・分・秒を針の代わりに表示します。メーターの個体差に合わせてPWM値をキャリブレーションする機能もコードに組み込んでいます。
元ネタはInstructablesの「Analog VU meter and Clock Arduino Powered」ですが、秒表示機能と起動時のフルスケールキャリブレーション動作を追加しました。使用するアメーターによって最適な5kΩ抵抗値やPWM値が異なるため、ご自身のメーターに合わせてコード内の定数を調整する必要があります。
配線図
主な接続
- USB 5V(赤) → VCC
- USB GND(黒) → GND
- タクトスイッチ左/下 → Digital 2
- タクトスイッチ右/上 → Digital 3
- DS3231 SDA → Analog 4 (A4)
- DS3231 SCL → Analog 5 (A5)
- 左メーター(時) → Digital 5 (PWM)
- 右メーター(分) → Digital 6 (PWM)
- 秒メーター → Digital 9 (PWM)
ソースコード
コードはDS1307ライブラリ互換のI2C通信でDS3231から時刻を読み取り、各メーターに適切なPWM値を出力します。メーターの非直線性を補正するため、時間ごと・分ごとに異なるPWM値をルックアップテーブル的に指定しています。秒メーターは分メーターとは別のスケーリング係数(4.25)を使用しています。
/* Analog Panel Meter - Clock ONLY Mode
Instructables Link: https://www.instructables.com/id/Analog-VU-meter-and-Clock-Arduino-Powered/
Credits: bildr - DS1307 RTC code https://bildr.org/2011/03/ds1307-arduino/
_____________________
Wiring goes as follows:
- USB red wire (5v) to VCC
- USB black wire to GND
- Buttons
- Left/Down to Digital 2
- Right/Up to Digital 3
- DS1307 RTC
- SDA to Analog 4
- SCL to Analog 5
- Left Analog Meter to Digital 5 (PWM)
- Right Analog Meter to Digital 6 (PWM)
- Seconds Analog meter to Digital 9 (PWM)
_____________________
Note: Because all meters are slightly different, the PWM values need to be adjusted based on your design.
Feel free to use my code, but you will have to change some values because it is set to work specifically with my meters.
*/
#include "Wire.h"
#define DS1307_ADDRESS 0x68
byte zero = 0x00;
int downButton = 2;
int upButton = 3;
int hours = 0;
int minutes = 0;
int seconds = 0;
int lastMinute = 0;
int lastSecond = 0;
int leftMeter = 5;
int rightMeter = 6;
int secMeter = 9;
void setup() {
Wire.begin();
Serial.begin(9600);
pinMode(leftMeter, OUTPUT);
pinMode(rightMeter, OUTPUT);
pinMode(secMeter, OUTPUT);
// 起動時テスト:全メーターをフルスケール振れさせる
digitalWrite(leftMeter, HIGH);
digitalWrite(rightMeter, HIGH);
digitalWrite(secMeter, HIGH);
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(leftMeter, LOW);
digitalWrite(rightMeter, LOW);
digitalWrite(secMeter, LOW);
digitalWrite(13, LOW);
delay(1000);
}
void loop() {
printDate();
delay(75);
// ボタンで時刻調整
if (digitalRead(downButton) == HIGH) {
// 時刻を1分戻す処理
byte second = seconds;
byte minute = minutes;
byte hour = hours;
if (minutes > 0) { --minute; }
else { minute = 59; if (hours > 0) { --hour; } else { hour = 23; } }
writeTimeToRTC(second, minute, hour);
}
if (digitalRead(upButton) == HIGH) {
// 時刻を1分進める処理
byte second = 0;
byte minute = minutes;
byte hour = hours;
if (minutes < 59) { ++minute; }
else { minute = 0; if (hours < 23) { ++hour; } else { hour = 0; } }
writeTimeToRTC(second, minute, hour);
}
}
byte decToBcd(byte val) { return ( (val/10*16) + (val%10) ); }
byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); }
void writeTimeToRTC(byte second, byte minute, byte hour) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(zero);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(zero);
Wire.endTransmission();
}
void printDate() {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(zero);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
seconds = bcdToDec(Wire.read());
minutes = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0b111111); // 24時間制
// Serial.print(hours); Serial.print(":"); Serial.println(minutes); // デバッグ用
// 分の更新時にのみメーター駆動値を更新(チラつき防止)
if (lastMinute != minutes) {
// 時メーター:12時間制で0-11時を0-255にマッピング(要調整)
if (hours == 1 || hours == 13) analogWrite(leftMeter, 0);
else if (hours == 2 || hours == 14) analogWrite(leftMeter, 29);
else if (hours == 3 || hours == 15) analogWrite(leftMeter, 52);
else if (hours == 4 || hours == 16) analogWrite(leftMeter, 75);
else if (hours == 5 || hours == 17) analogWrite(leftMeter, 98);
else if (hours == 6 || hours == 18) analogWrite(leftMeter, 130);
else if (hours == 7 || hours == 19) analogWrite(leftMeter, 152);
else if (hours == 8 || hours == 20) analogWrite(leftMeter, 172);
else if (hours == 9 || hours == 21) analogWrite(leftMeter, 192);
else if (hours == 10 || hours == 22) analogWrite(leftMeter, 213);
else if (hours == 11 || hours == 23) analogWrite(leftMeter, 234);
else if (hours == 0 || hours == 12) analogWrite(leftMeter, 255);
// 分メーター:0-59分を0-255に線形マッピング(係数4.75はメーター依存)
if (minutes * 4.75 < 255) analogWrite(rightMeter, minutes * 4.75);
else analogWrite(rightMeter, 255);
// 秒メーター:0-59秒を0-255に線形マッピング(係数4.25)
if (seconds * 4.25 < 255) analogWrite(secMeter, seconds * 4.25);
else analogWrite(secMeter, 255);
lastMinute = minutes;
lastSecond = seconds;
}
}
調整のポイント
- 5kΩ抵抗:メーターの内部抵抗と合わせてPWM電流を制限します。メーターによって最適値が変わるため、可変抵抗で試してから固定抵抗に置き換えるのが確実です。
- PWM値テーブル:コード内の
analogWrite(leftMeter, ...)の数値は、筆者のメーターで12時方向が255、1時方向が0になるよう実測で決定したものです。お手持ちのメーターで針の角度を確認しながら書き換えてください。 - 分・秒のスケーリング係数:
minutes * 4.75、seconds * 4.25もメーター特性依存です。理想は255/60 = 4.25ですが、メーターの非直線性やゼロ点ズレで補正が必要です。 - 起動時キャリブレーション:
setup()で全メーターを1秒間フルスケール(HIGH)に振らせ、ゼロ点確認を行っています。
製作のヒント
- 木製ケースはレーザーカッターや手工具で加工可能。メーター取り付け穴はメーター径に合わせて正確に開けてください。
- 配線はケース内でショートしないよう、収縮チューブや絶縁テープで保護しましょう。
- 電源はUSB給電(5V)で動作します。モバイルバッテリーでも駆動可能です。
- DS3231にはバックアップ電池(CR2032等)が搭載されており、電源断後も時刻を保持します。
関連リソース
- 元ネタ:Analog VU meter and Clock Arduino Powered
- DS1307/DS3231ライブラリ参考:bildr.org
製造プロセス
- Arduino POVクロック:残像効果で浮かび上がるLED時計を自作する
- DIY Arduinoワードクロック – 文字で時刻を表示する洗練されたリアルタイムクロック
- Arduino で作るイスラム教礼拝時刻付きリアルタイムクロック
- 12メートル先から見える大型LEDマスタークロック(アラーム機能付き)を自作しよう
- Arduino Nanoで作るウェアラブル心拍ドレス:CrazyCircuitsとDFRobotセンサーで自信を持ってプロジェクトを構築
- アナログ風LED POVクロック – Arduino Nanoで作る残像時計
- FlightGear用アナログトリムタブホイールをArduino Nanoで自作 ─ Python経由でUDP連携
- Arduino Nanoとジョイスティックで2軸ステッピングモーターを制御:Visuinoで簡単プログラミング
- パネルメーター:機械インターフェースと制御のためのコスト効率の高いソリューション
- 適切なパネル選択:デジタルとアナログソリューションの比較
- パネルメーター徹底解説:産業機器の監視と制御の仕組み