Arduino Nano模拟指针时钟:DS3231 RTC + 1mA电流表精密木制计时器
组件与物料清单
| 组件 | 数量 | 备注 |
|---|---|---|
| Arduino Nano R3 | 1 | 主控板 |
| Maxim DS3231M RTC实时时钟模块 | 1 | ±5ppm高精度,I2C接口 |
| 1mA 指针式电流表 | 3 | 分别显示时、分、秒 |
| 5kΩ 电阻 | 3 | 配合电流表调节PWM输出 |
| 10kΩ 电阻 | 2 | 按钮上拉 |
| 12mm 轻触开关 | 2 | 时间调节按钮(上/下) |
软件与工具
- Arduino IDE
项目简介
这是一个外观精美的木质模拟指针时钟,基于Arduino Nano和三个1mA指针式电流表制作。灵感来源于网络上的类似项目,我增加了秒针显示功能,并添加了启动时全刻度扫描校准功能。
关键提示:由于每个电流表特性略有差异,5kΩ电阻值及PWM输出数值需根据实测调整。代码中的数值针对我的电流表校准,复刻时必须修改对应参数。
接线说明
- USB红线(5V) → VCC,黑线 → GND
- 左按钮(减) → 数字引脚2
- 右按钮(加) → 数字引脚3
- DS3231 RTC: SDA → A4, SCL → A5
- 时针电流表 → 数字引脚5 (PWM)
- 分针电流表 → 数字引脚6 (PWM)
- 秒针电流表 → 数字引脚9 (PWM)
完整代码
/* 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:
- 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) {
byte second = seconds;
byte minute = minutes;
byte hour = hours;
if (minutes > 0) { --minute; }
else { minute = 59; if (hours > 0) --hour; else hour = 23; }
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(zero);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(zero);
Wire.endTransmission();
}
if (digitalRead(upButton) == HIGH) {
byte second = 0;
byte minute = minutes;
byte hour = hours;
if (minutes < 59) { ++minute; }
else { minute = 0; if (hours < 23) ++hour; else hour = 0; }
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(zero);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(zero);
Wire.endTransmission();
}
}
byte decToBcd(byte val) {
return ((val / 10 * 16) + (val % 10));
}
byte bcdToDec(byte val) {
return ((val / 16 * 10) + (val % 16));
}
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小时制
// 仅当分钟变化时更新指针,减少抖动
if (lastMinute != minutes) {
// 时针PWM查表(需根据实测校准)
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);
// 分针:每分钟约4.75 PWM步进(理想值4.25,视表头特性调整)
if (minutes * 4.75 < 255) analogWrite(rightMeter, minutes * 4.75);
else analogWrite(rightMeter, 255);
// 秒针:每秒4.25 PWM步进
if (seconds * 4.25 < 255) analogWrite(secMeter, seconds * 4.25);
else analogWrite(secMeter, 255);
lastMinute = minutes;
lastSecond = seconds;
}
}
原理图

制作要点总结
- 表头校准是核心:每个1mA电流表内阻、灵敏度不同,必须实测调整PWM映射表
- 木质外壳:可激光切割或手工制作,预留表头安装孔位
- DS3231优于DS1307:温补晶振,年误差仅±1分钟,无需频繁校时
- 启动自检动画:上电指针全程扫描,既酷炫又能验证机械行程
制造工艺
- Arduino POV 时钟:自制视觉暂留 LED 显示器
- DIY Arduino单词时钟 – 极简优雅的实时文字显示
- 自制 Arduino 伊斯兰祷告时间实时时钟
- 自制大尺寸LED主时钟带闹钟功能 — 12米外清晰可见
- Arduino Nano 智能礼服:心率感应 LED 装饰,融合 CrazyCircuits 与 DFRobot 传感器
- 模拟指针风格 POV 时钟:Arduino Nano + 17 LED + 霍尔传感器
- 自制 FlightGear 飞行模拟升降舵配平轮:Arduino Nano + Python UDP 桥接方案
- Arduino Nano + 摇杆控制双步进电机:Visuino 图形化教程
- 用 Arduino Pro Mini 与 DS1302 RTC 打造精准七段数码管时钟
- 面板仪表:机器界面与控制的高性价比方案
- 面板选型指南:数字与模拟方案的深度对比
- 面板仪表详解:如何监测与控制工业设备