亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

7-Segment Clock with Arduino Nano + DS3231 + LDR

组件和用品

Arduino Nano R3
适用于 Arduino Uno 或 Elegoo Uno
× 1
Adafruit 7 段背包 - 1.2" 高位
- 在我的情况下为 1.2" Tall Digits(如果您购买捆绑包,则可选)
× 1
Adafruit 1.2 4-Digit 7-Segment Display w/I2C Backpack - 绿色
× 1
Adafruit DS3231
或 DS1307(如果您愿意)
× 1
电阻 100k ohm
× 1
光敏电阻
× 1
面包板(通用)
× 1
跳线(通用)
10-14 件
× 1
纽扣电池 CR1220
× 1

应用和在线服务

Arduino IDE

关于这个项目

介绍

在您手腕上总是有一个时钟的时代,无论是手腕上的手表还是智能手机,Arduino Uno/Nano 都有些乏味。否则,您在本文之外拥有 NTP 服务器同步设备,这些设备通过您的 Internet 连接始终在线。

故事

我的一个朋友出于个人原因拒绝了他卧室里有 WiFi 连接的设备,所以我给 Arduino 配备了一个单独的时钟。

选择合适的产品

我很惊讶,即使是 Adafruit 也有这么多不同的产品可供选择:取决于所需的张力,以及不同的精度!在这里,我决定购买两种产品:更便宜的 DS1307 和可能更精确的 DS3231 .

需要说明的是:这两款产品都可以用在这个时钟上。使用DS1307需要注意正确的PIN分配和温度显示选项的限制:备注 "//" displayTemp(); loop() 内的函数。

调整草图

我去寻找草图并找到了另一个成员的东西。我重组并适应了这个草图,但保留了捷克语注释并添加了英语注释。

广告应该尽可能大,所以我决定制作一个 7 段广告:毕竟,我只想把时间放在心上。

我在查看草图时遇到的下一个惊喜:在这里,DS3231 提供了使用温度的选项 ,DS1307 - 除了它的不准确性 - 缺失。

初始化时钟

如果您有 CR1220 纽扣电池,您可以按照 Adafruit 设置时钟的简短教程进行操作。综上所述,时间不是从网上下载的,而是从本地PC随着时间的推移。上传时间戳传送到定时器。

功能

之后我将 LED 矩阵添加到电路中,用于时间和温度输出 .可以通过变量设置时间和温度变化的周期。

特别是,LED矩阵上的单个闪烁的点和数字的控制如何工作和控制,在草图中得到了很好的描述。

这里我参考了更多的 Adafruit 来源。

草图由夏/冬时间的调整四舍五入 以及 LED 矩阵的亮度取决于环境光 (夜间显示应该比白天更暗)。

在视频中,您肯定注意到时间和温度的变化。你有没有注意图中左边的那个点?这会根据秒数改变其位置(向上或向下)。

如果您知道如何在时钟出现故障时在 LED 矩阵上发出“ERR”,请给我反馈。此时会出现“bEEF”:

 // 哦不,没有数据! Serial.println("DS3231 传感器错误 - 无法读取温度");矩阵打印(0xBEEF,十六进制); // 用 BEEF matrix.writeDisplay() 通知用户;延迟(5000); 

扩展

闹钟或闹钟时间也未集成。

也可能通过蓝牙模块和 Blynk 成功扩展。

2019 年 2 月 1 日更新:

今天已经完成了从面包板到打孔卡永久投注的转移。给有兴趣的人几张图:

您将在附件中找到更新的代码 v1.1 以及自定义的镶边图像。

代码

  • MyClock v1.0
  • MyClock v1.1
MyClock v1.0C/C++
// MyClock v1.0// Ingo Lohs// 硬件:通过使用 Arduino IDE v1.8.8/* 矩阵理论 ht16k33 使用 Arduino Uno 和 Arduino Nano(ATmega328P [旧引导加载程序])进行测试最简单的方法是调用打印 - 就像你用 Serialprint(variable,HEX) 做的一样 - 这将打印一个十六进制数,从 0000 到 FFFFprint(variable,DEC) 或 print(variable) - 这将打印一个十进制整数,从 0000 到 9999 如果你需要更多控制,您可以调用 writeDigitNum(location, number) - 这会将数字 (0-9) 写入单个位置。位置 #0 一直向左,位置 #2 是冒号点,因此您可能想跳过它,位置 #4 一直在右边。要控制冒号和小数点,请使用 writeDigitRaw(location, bitmap) 函数。(注意中心冒号的两个点在显示器内部连接在一起,因此无法单独寻址它们。)为位置指定 2,位映射如下:0x02 - 中心冒号(两者均为 d ots)0x04 - 左冒号 - 下点 0x08 - 左冒号 - 上点 0x10 - 小数点如果你想要一个小数点,调用 writeDigitNum(location, number, true) 这将绘制小数点。要绘制冒号,请使用 drawColon(true or false) 如果您想完全控制所有数字中的段,您可以调用 writeDigitRaw(location,bitmask) 将原始 8 位掩码(如存储在 uint8_t 中)绘制到任何位置。所有绘图例程仅更改显示Arduino 保存的内存。不要忘记在通过 I2C 将内存“保存”到矩阵后调用 writeDisplay()。来源:https://www.mouser.com/ds/2/737/adafruit-led-backpack-932846。 pdf*/#include  // 如果使用 Arduino Uno、Mega 等,请启用此行#include #include "Adafruit_LEDBackpack.h"#define DS3231_I2C_ADDRESS 0x68int ldr_sensor =A0; // LDR 光敏电阻与 100k Ohm 到 GND,另一条腿 5Vint ldr_value =0; // LDR 值 - var store valueint Brightness_matrix; // LED 矩阵亮度 - var store valueint threshold_brightness =400; // 阈值闪烁率_值 =0; // LED 矩阵闪烁率int delay_matrix_time =20; // 显示时间有多长(20 秒)int delay_matrix_temp =2000; // 显示 temp (2 sec)int flashy_dot =2 的时间; // 不闪烁 - 在左侧 2 个单点 Adafruit_7segment matrix =Adafruit_7segment();byte decToBcd(byte val){return ( (val/10*16) + (val%10) );}byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) );}void setup() { Serial.begin(9600); Wire.begin(); matrix.begin(0x70);}void loop() { lightBrightness(); // 矩阵亮度调整 matrixBlinkrate(); // Matrix-Blinkrate Jusitierung displayTime(); // 显示实时时钟数据 displayTemp(); // 显示温度 }void lightBrightness() {// setBrightness(brighness) - 让你改变整个显示器的整体亮度。 0 是最不亮的,15 是最亮的,并且是在您启动 ldr_value =analogRead(ldr_sensor); 时由显示器初始化的值。 Serial.print("LDR:"); Serial.println(ldr_value); if (ldr_value <=threshold_brightness) { // 亮度与阈值的测量brightness_matrix =0; // 白天很亮 } else { Bright_matrix =15; // 晚上很黑 }}void matrixBlinkrate() {//blinkRate(rate) - 您可以使整个显示器闪烁。 0 不闪烁。 1、2 或 3 用于显示闪烁。 matrix.blinkRate(blinkrate_value);} void displayTime(){matrix.setBrightness(brightness_matrix); matrix.clear();// 在矩阵上显示多长时间(以秒为单位)for (uint16_t i =0; i > 更改为夏令时 - 三月的最后一个星期日 2 点钟 if ((dayOfWeek ==7) &&(dayOfMonth>=25)&&(month ==3) &&(hour ==2)) { // nastavení hodin na 3 hodinu // 将时钟设置为 3 小时 setDS3231time(se,mi,3,we,dm,mo,ye); } // změna času na zimní //>> 改为冬令时 if ((dayOfWeek ==7) &&(dayOfMonth>=25) &&(month ==10) &&(hour ==1)&&(year !=1 )) { // rok použit jako indikace, že bylo léto // 用年份表示现在是夏天 setDS3231time(se,mi,ho,we,dm,mo,1); } if ((dayOfWeek ==7) &&(dayOfMonth>=25) &&(month ==10) &&(hour ==3) &&(year ==1)) { // nastavení hodin na 2 hodinu a příznak na 0 // 将时钟设置为 2 小时,并将年份标记为 0 setDS3231time(se,mi,2,we,dm,mo,0); } /* 为位置指定 2,位映射如下: 0x02 - 中心冒号(两个点) 0x04 - 左冒号 - 下点 0x08 - 左冒号 - 上点 0x10 - 小数点 */ /* 位置 #2 控制还有像这样的左侧 2 个单点(=blinky_dot):2 =不闪烁 3 =不闪烁 4 =左上角闪烁(单个上点) 5 =左上角闪烁(单个上点) 6 =左上角闪烁(单个上点) ) + 中间的两个冒号 7 =闪烁左上角(单个上点) + 中间的两个冒号 8 =闪烁左下角(单个下点) 9 =闪烁左下角(单个下点) 10 =闪烁左下角(单个下点) ) + 中间的两个冒号 11 =左下角闪烁(单个下点)+ 中间的两个冒号 12 =中间的两个冒号都闪烁(两个左单点),中间没有两个冒号 */ // 格式小时:_0:mm if (hour> 9) { matrix.writeDigitNum(0, (hour / 10), false); matrix.writeDigitNum(1, (hour % 10), false); // 这将使用模数(0-9)写入单个位置 https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/modulo/ } else { matrix.writeDigitNum( 1,小时,假); } // matrix.drawColon(true); // 中间的两个冒号都处于活动状态:如果你不想让左边的点闪烁,你可以在这里激活两个冒号 // 给几秒钟的机会在左边的位置显示点 if (se <=30) {blinky_dot =10; // 闪烁左下角(单个下点)+ 中间的两个冒号 } else if (se> 30) { browsey_dot =6; // 左上角闪烁(单个上点)+ 中间的两个冒号 } matrix.writeDigitRaw(2,blinky_dot); matrix.writeDigitNum(3, (minute / 10), false); matrix.writeDigitNum(4, (minute % 10), false);矩阵.writeDisplay(); // 闪烁双点半秒延迟(500);矩阵.drawColon(假);矩阵.writeDisplay();延迟(500); }}void displayTemp(){matrix.setBrightness(brightness_matrix);矩阵清除();字节温度 =get3231Temp(); int abs_temp =abs(temp); // 值的绝对数 matrix.writeDigitNum(1,(abs_temp % 10), false); // 位置 1,值 9,显示十进制) if (temp <0) matrix.writeDigitRaw(0,64); if (temp <=-10) matrix.writeDigitRaw(2,12); // 如果温度为负,我们将负号绘制到第一位。 if (temp>
=10) matrix.writeDigitNum(0, (abs_temp/10), false); // 位置 0,值 1,显示十进制) if (temp <=-10) matrix.writeDigitNum(0, (abs_temp/10), false); // 位置 0,值 1,显示十进制) // matrix.writeDigitRaw(2,0x10); // 十进制点阵.writeDigitRaw(3,99); // 99 ="°" matrix.writeDigitRaw(4,57); // 57 ="C" matrix.writeDisplay(); // 在串行线上显示温度值 // zobrazi hodnoty teploty na seriove lince Serial.print("Temperatur in C:"); Serial.println(get3231Temp()); // +/- 3 摄氏度 // 以秒为单位在矩阵上显示温度的时间 delay(delay_matrix_temp);}void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year){/ / 设置时间和日期数据到 DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // 设置下一个输入从秒寄存器开始 Wire.write(decToBcd(second)); // 设置秒 Wire.write(decToBcd(minute)); // 设置分钟 Wire.write(decToBcd(hour)); // 设置小时 Wire.write(decToBcd(dayOfWeek)); // 设置星期几 (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // 设置日期(1 到 31) Wire.write(decToBcd(month)); // 设置月份 Wire.write(decToBcd(year)); // 设置年份(0 到 99) Wire.endTransmission();}void getDateDs3231(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year){ Wire.开始传输(DS3231_I2C_ADDRESS); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); *second =bcdToDec(Wire.read() &0x7f); *分钟 =bcdToDec(Wire.read()); *小时 =bcdToDec(Wire.read() &0x3f); *dayOfWeek =bcdToDec(Wire.read()); *dayOfMonth =bcdToDec(Wire.read()); *month =bcdToDec(Wire.read()); *year =bcdToDec(Wire.read());}float get3231Temp(){ byte tMSB, tLSB;浮动 temp3231; Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 2); if (Wire.available()) { tMSB =Wire.read(); // 2 的补码 int 部分 tLSB =Wire.read(); // 小数部分 temp3231 =(tMSB &B01111111); // 在 Tmsb temp3231 +=( (tLSB>> 6) * 0.25 ) 上做 2 的数学运算; // 只关心第 7 位和第 8 位返回 temp3231; } else { // 哦不,没有数据! Serial.println("DS3231 传感器错误 - 无法读取温度");矩阵打印(0xBEEF,十六进制); // 用 BEEF matrix.writeDisplay() 通知用户;延迟(5000); } }
MyClock v1.1C/C++
更新 Summer/Winter-Time
// MyClock v1.1// Ingo Lohs// 硬件:使用 Arduino Uno 和 Arduino Nano(ATmega328P [旧引导加载程序])测试,使用 Arduino IDE v1.8.8// 更改 v1.0> v1.1// dayOfWeek ==1 anstatt 7 abgeändert in displayTime() zur korrekten Ermittlung des Sonntages für die Zeitumstellung/* Theory for the Matrix ht16k33最简单的方法是调用print - 就像使用Serialprint(variable,HEX) - 这将打印一个十六进制数,从 0000 到 FFFFprint(variable,DEC) 或 print(variable) - 这将打印一个十进制整数,从 0000 到 9999 如果您需要更多控制,可以调用 writeDigitNum(location, number) - 这会将数字 (0-9) 写入单个位置。位置 #0 一直到左侧,位置 #2 是冒号点,因此您可能想跳过它,位置 #4 一直到右边。要控制冒号和小数点,请使用 writeDigitRaw(location, bitmap) 函数。(注意中心冒号的两个点在显示器的内部,因此不能单独寻址它们。)为位置指定 2,位映射如下:0x02 - 中心冒号(两个点)0x04 - 左冒号 - 下 dot0x08 - 左冒号 - 上 dot0x10 - 小数点如果你想要一个小数点,调用 writeDigitNum(location, number, true) 这将绘制小数点。要绘制冒号,使用 drawColon(true or false) 如果你想完全控制所有数字的段,你可以调用 writeDigitRaw(location,bitmask) 将原始 8 位掩码(存储在 uint8_t 中)绘制到任何位置。所有绘图例程仅更改 Arduino 保留的显示内存。不要忘记在通过 I2C 将内存“保存”到矩阵后调用 writeDisplay()。来源:https://www.mouser.com/ds/2/737/adafruit-led-backpack-932846。 pdf*/#include  // 如果使用 Arduino Uno、Mega 等,请启用此行#include #include "Adafruit_LEDBackpack.h"#define DS3231_I2C_ADDRESS 0x68int ldr_sensor =A0; // LDR 光敏电阻与 100k Ohm 到 GND,另一条腿 5Vint ldr_value =0; // LDR 值 - var store valueint Brightness_matrix; // LED 矩阵亮度 - var store valueint threshold_brightness =400; // 阈值闪烁率_值 =0; // LED 矩阵闪烁率int delay_matrix_time =20; // 显示时间有多长(20 秒)int delay_matrix_temp =2000; // 显示 temp (2 sec)int flashy_dot =2 的时间; // 不闪烁 - 在左侧 2 个单点 Adafruit_7segment matrix =Adafruit_7segment();byte decToBcd(byte val){return ( (val/10*16) + (val%10) );}byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) );}void setup() { Serial.begin(9600); Wire.begin(); matrix.begin(0x70);}void loop() { lightBrightness(); // 矩阵亮度调整 matrixBlinkrate(); // Matrix-Blinkrate Jusitierung displayTime(); // 显示实时时钟数据 displayTemp(); // 显示温度 }void lightBrightness() {// setBrightness(brighness) - 让你改变整个显示器的整体亮度。 0 是最不亮的,15 是最亮的,并且是在您启动 ldr_value =analogRead(ldr_sensor); 时由显示器初始化的值。 Serial.print("LDR:"); Serial.println(ldr_value); if (ldr_value <=threshold_brightness) { // 亮度与阈值的测量brightness_matrix =0; // 白天很亮 } else { Bright_matrix =15; // 晚上很黑 }}void matrixBlinkrate() {//blinkRate(rate) - 您可以使整个显示器闪烁。 0 不闪烁。 1、2 或 3 用于显示闪烁。 matrix.blinkRate(blinkrate_value);} void displayTime(){matrix.setBrightness(brightness_matrix); matrix.clear();// 在矩阵上显示多长时间(以秒为单位)for (uint16_t i =0; i > 更改为夏令时 - 三月的最后一个星期日 2 点钟 if ((dayOfWeek ==1) &&(dayOfMonth>=25)&&(month ==3) &&(hour ==2)) { // nastavení hodin na 3 hodinu // 将时钟设置为 3 小时 setDS3231time(se,mi,3,we,dm,mo,ye); } // změna času na zimní //>> 改为冬令时 if ((dayOfWeek ==1) &&(dayOfMonth>=25) &&(month ==10) &&(hour ==1)&&(year !=1) )) { // rok použit jako indikace, že bylo léto // 用年份表示现在是夏天 setDS3231time(se,mi,ho,we,dm,mo,1); } if ((dayOfWeek ==1) &&(dayOfMonth>=25) &&(month ==10) &&(hour ==3) &&(year ==1)) { // nastavení hodin na 2 hodinu a příznak na 0 // 将时钟设置为 2 小时,并将年份标记为 0 setDS3231time(se,mi,2,we,dm,mo,0); } /* 为位置指定 2,位映射如下: 0x02 - 中心冒号(两个点) 0x04 - 左冒号 - 下点 0x08 - 左冒号 - 上点 0x10 - 小数点 */ /* 位置 #2 控制还有像这样的左侧 2 个单点(=blinky_dot):2 =不闪烁 3 =不闪烁 4 =左上角闪烁(单个上点) 5 =左上角闪烁(单个上点) 6 =左上角闪烁(单个上点) ) + 中间的两个冒号 7 =闪烁左上角(单个上点) + 中间的两个冒号 8 =闪烁左下角(单个下点) 9 =闪烁左下角(单个下点) 10 =闪烁左下角(单个下点) ) + 中间的两个冒号 11 =左下角闪烁(单个下点)+ 中间的两个冒号 12 =中间的两个冒号都闪烁(两个左单点),中间没有两个冒号 */ // 格式小时:_0:mm if (hour> 9) { matrix.writeDigitNum(0, (hour / 10), false); matrix.writeDigitNum(1, (hour % 10), false); // 这将使用模数(0-9)写入单个位置 https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/modulo/ } else { matrix.writeDigitNum( 1,小时,假); } // matrix.drawColon(true); // 中间的两个冒号都处于活动状态:如果你不想让左边的点闪烁,你可以在这里激活两个冒号 // 给几秒钟的机会在左边的位置显示点 if (se <=30) {blinky_dot =10; // 闪烁左下角(单个下点)+ 中间的两个冒号 } else if (se> 30) { browsey_dot =6; // 左上角闪烁(单个上点)+ 中间的两个冒号 } matrix.writeDigitRaw(2,blinky_dot); matrix.writeDigitNum(3, (minute / 10), false); matrix.writeDigitNum(4, (minute % 10), false);矩阵.writeDisplay(); // 闪烁双点半秒延迟(500);矩阵.drawColon(假);矩阵.writeDisplay();延迟(500); }}void displayTemp(){matrix.setBrightness(brightness_matrix);矩阵清除();字节温度 =get3231Temp(); int abs_temp =abs(temp); // 值的绝对数 matrix.writeDigitNum(1,(abs_temp % 10), false); // 位置 1,值 9,显示十进制) if (temp <0) matrix.writeDigitRaw(0,64); if (temp <=-10) matrix.writeDigitRaw(2,12); // 如果温度为负,我们将负号绘制到第一位。 if (temp>
=10) matrix.writeDigitNum(0, (abs_temp/10), false); // 位置 0,值 1,显示十进制) if (temp <=-10) matrix.writeDigitNum(0, (abs_temp/10), false); // 位置 0,值 1,显示十进制) // matrix.writeDigitRaw(2,0x10); // 十进制点阵.writeDigitRaw(3,99); // 99 ="°" matrix.writeDigitRaw(4,57); // 57 ="C" matrix.writeDisplay(); // 在串行线上显示温度值 // zobrazi hodnoty teploty na seriove lince Serial.print("Temperatur in C:"); Serial.println(get3231Temp()); // +/- 3 摄氏度 // 以秒为单位在矩阵上显示温度的时间 delay(delay_matrix_temp);}void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year){/ / 设置时间和日期数据到 DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // 设置下一个输入从秒寄存器开始 Wire.write(decToBcd(second)); // 设置秒 Wire.write(decToBcd(minute)); // 设置分钟 Wire.write(decToBcd(hour)); // 设置小时 Wire.write(decToBcd(dayOfWeek)); // 设置星期几 (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // 设置日期(1 到 31) Wire.write(decToBcd(month)); // 设置月份 Wire.write(decToBcd(year)); // 设置年份(0 到 99) Wire.endTransmission();}void getDateDs3231(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year){ Wire.开始传输(DS3231_I2C_ADDRESS); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); *second =bcdToDec(Wire.read() &0x7f); *分钟 =bcdToDec(Wire.read()); *小时 =bcdToDec(Wire.read() &0x3f); *dayOfWeek =bcdToDec(Wire.read()); *dayOfMonth =bcdToDec(Wire.read()); *month =bcdToDec(Wire.read()); *year =bcdToDec(Wire.read());}float get3231Temp(){ byte tMSB, tLSB;浮动 temp3231; Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 2); if (Wire.available()) { tMSB =Wire.read(); // 2 的补码 int 部分 tLSB =Wire.read(); // 小数部分 temp3231 =(tMSB &B01111111); // 在 Tmsb temp3231 +=( (tLSB>> 6) * 0.25 ) 上做 2 的数学运算; // 只关心第 7 位和第 8 位返回 temp3231; } else { // 哦不,没有数据! Serial.println("DS3231 传感器错误 - 无法读取温度");矩阵打印(0xBEEF,十六进制); // 用 BEEF matrix.writeDisplay() 通知用户;延迟(5000); } }
Github
https://github.com/ILohs/MySketches

示意图

LDR 路径已更正

制造工艺

  1. Arduino pov 视觉时钟
  2. DIY 最简单的 IV9 Numitron 时钟与 Arduino
  3. 使用 Adafruit 1/4 60 Ring Neopixel 的简单挂钟
  4. 带有伊斯兰祈祷时间的 Arduino 时钟
  5. 主时钟
  6. Arduino 温度。使用 3.2 显示的监视器和实时时钟
  7. Arduino Nano:使用操纵杆控制 2 个步进电机
  8. Arduino Apple Watch
  9. 7 段阵列时钟
  10. 带有 Arduino Nano 的手持盖革计数器
  11. 用 Arduino Nano 制作吃饭机器人 |金螺丝
  12. 带 DS1302 RTC 的简单闹钟