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

DCF77 分析器/时钟 v2.0

组件和用品

Arduino Mega 2560
× 1
Arduino UNO
× 1

关于这个项目

发现 Arduino 平台后,我大吃一惊,有朝一日开发自己的电子产品的梦想成真了。

正如任何人都会做的那样,我从基本草图开始,但很快我就想做一些有用的东西。因为我一直很喜欢无线电时钟(在我的例子中它们与来自德国的 DCF77 信号同步),所以我决定制作一个时钟,它不仅可以显示时间,还可以显示正在发生的事情。

经过数百小时的修修补补,犯了无数的错误,我终于有了一个可以用我自己的代码和印刷电路板设计的时钟。

DCF77 分析器/时钟 v1.0 的照片和视频:

但是后来我发现了 Udo Klein 的 DCF77 超级滤波器,它可以在无线电信号不太好的情况下提供干净的信号。

这是一个单独的 Arduino Uno 板,带有 Superfilter 软件,(您可以将其视为一个独立的“黑匣子”,过滤信号)连接在 DCF77 天线和运行我的草图的 Arduino Mega 之间。

所以我制作了第一个时钟的 2.0 版本:

  • 完全重写的代码
  • 广泛评论,希望任何人都能理解发生了什么
  • 添加了 PIR 运动传感器以降低功耗
  • 添加了 DCF77 超滤器
  • 额外显示温度或其他用途(如日出/日落时间)

新 DCF77 分析仪/时钟 v2.0 的照片和视频:

演示

观看视频请点击这里

内置“祖父时钟”

观看视频请点击这里

设计

前面板和外壳:

前面板的设计是在一个名为 Inkscape 的免费软件程序中完成的(见本页开头的下载地址)。

事实证明,实际生产前面板是最困难的部分。我花了很多钱试图在当地的 FabLab 使用激光切割机和一种带有类似铝涂层的特殊丙烯酸树脂来制作它。这个想法是用激光切割孔并通过烧掉非常薄的涂层来雕刻文字和线条,露出下面的黑色亚克力。但这是一场噩梦,因为由于大量用户的大量使用和“滥用”,激光切割机无法在我需要的公差范围内进行生产。

然后我遇到了一个在线照片服务。它们打印在各种材料上,其中之一是 DiBond 面板。价格非常好,28 欧元,包括邮费。但结果起初令人失望,因为他们没有以 1:1 的比例打印我的设计,而是稍微放大了。 因此,如果您决定使用此方法,请务必小心。先给他们打个电话问问能不能1:1打印。

打完电话后,他们寄给我另一个尺寸合适的面板。比预期的要好,非常好!

然后需要大量的钻孔和布线:

代码

  • DCF 分析器/时钟 v2.1
  • 超滤草图
DCF Analyzer / Clock v2.1Arduino
2020-01-18 错误发布:节能开关已修复
/* ==================================================================================DCF77分析仪/时钟版本 2 ================================================================================本草图是免费软件;您可以根据自由软件基金会发布的 GNU 宽松通用公共许可证的条款重新分发和/或修改它;许可证的 2.1 版,或(由您选择)任何更高版本。分发此草图是希望它有用,但不作任何保证;甚至没有对适销性或针对特定目的的适用性的暗示保证。有关更多详细信息,请参阅 GNU 宽松通用公共许可证。您应该已经收到一份 GNU 宽松通用公共许可证以及这个库;如果没有,请写信给 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ==================================================================================这个 C++ 代码远未优化,因为我自己是 Arduino 和 C++ 新手。但即使现在学习了更多,我还是想保持代码的简洁性和可读性。这就是为什么我可能会过度记录代码以帮助理解发生了什么。 Erik de Ruiter 2014-2020 2014 年 5 月第一个版本 2016 年 3 月 - 大修... 2016 年 7 月 - 开始构建 2.0 时钟并调整草图 2.1 版日期 2020-01-18 - Powersafe 功能已修复。 2.0 版 - 此草图适用于我的 DCF/分析器时钟的 2.0 版。它默认使用 Arduino MEGA 和 DCF Superfilter 并驱动许多单独的 LED,我现在使用 Arduino Mega 的端口而不是 Maxim 7219 芯片。这是因为使用Maxim芯片驱动具有许多不同电压/电流规格的LED是有问题的。例如,点亮额外的 LED 会影响(变暗)已经点亮的 LED。由于我不是电子工程师,我唯一的解决方案是使用 Arduino Mega 的额外端口。当然,您可以使用晶体管或额外的芯片来驱动 LED,但对我来说,这是显而易见的解决方案。 - 删除了所有 Maxim 共阳极显示代码 1.72 版 - 选项:使用便宜的 Ebay PIR 检测器在未检测到活动时关闭可选显示。用户可以设置关闭延迟,以防止在有人不动但显示器应该打开时关闭显示器。 - 现在可以通过将“POWERSAVINGOFFTIME”和“POWERSAVINGONTIME”这两个值都设置为零来禁用显示夜间关机。 - 修复了在省电模式下不关闭的温度显示。 - 错误计数器显示没有每小时重置 - 固定版本 1.71 - 在午夜重置温度最小/最大内存的用户选项 版本 1.7: - 温度显示的分辨率得到改进:从 0.5 摄氏度到 0.1 摄氏度 由于 DS18B20 传感器的时间需要转换温度并保持代码清洁,温度显示每分钟更新一次。 - 奇偶校验例程优化。 - 更可靠地检查错误的 DCF 数据,防止使用无效数据进行 RTC 更新。 - EoB 错误现在会按原样清除内部 LED 环。 - DCF OK LED 现在可以更可靠地显示 DCF 信号的状态。如果发生错误,立即关闭,只有在所有 3 个奇偶校验位都正常时才打开。 1.6 版: - 将温度函数更改为每分钟仅计算一次。在更改之前出现奇怪的错误,因为我使用了 100 毫秒的延迟来给 DS18B20 传感器时间来计算温度。但是延迟函数在大多数 C++ 代码中是一个非常糟糕的主意,所以我终于摆脱了它。 1.5 版: - 对 scanSignal 函数和其余代码进行全面检查!我的第一次尝试成功了,但可以改进... - rPW 和 rPT 指示灯没有按我的预期工作,所以现在更正了。 - 缓冲区结束错误检查例程现在可以正常工作。 - 我对传入的 DCF 信号进行了奇偶校验。在信号中发送了 3 个奇偶校验位,因此现在检查这些位,并且只有当所有三个都正常时,才会接受接收到的时间信息,更新显示并同步 RTC。如果需要,您可以附加 3 个额外的双色 LED(共阴极)以查看 3 个奇偶校验位中的每一个是 OK 还是 Failed。 - 我认为通过将所有 PIN 配置放在一个易于阅读的表格中,我使接线(或更改接线)变得更加容易 - 只要您使用 1 DS18B20 temp。传感器,我编辑了代码,因此您不再需要找出 I2C 设备的地址。 - 代码的大清理... - 现在可以通过编辑两个变量 POWERSAVINGONTIME 和 POWERSAVINGOFFTIME 来更轻松地配置关闭显示器(时钟保持正常运行)的节能。 - 更改了一些变量名称: - Maxim 实例 'lc' 和 'lc1' 现在是 MaximCC 和 MaximCA - 显示说明 MaximDcfTime 现在是 DisplayTempWeek - DCF77SOUNDPIN 现在是 BUZZERSWITCHPIN - 现在内置上电后的 LED/显示器测试 简短说明: 开机:上电后,首先进行 LED 测试。 LED 和显示屏依次点亮以保持低功耗。然后时钟开始接收 DCF 脉冲,当检测到分钟标记(2 秒间隔)时,分钟标记 LED 亮起,缓冲器计数器复位。内部 LED 环现在将显示传入的 DCF 脉冲,这些脉冲也存储在缓冲区中。在接收数据期间的 3 个时刻,检查奇偶校验 DCF 位以查看数据是否有效。有效数据接收:当在分钟结束时,在检测到分钟标记后(BF(缓冲区满)LED 亮起),所有三个奇偶校验位都正常('DCF OK' LED 亮起),缓冲区信息为用于提取时间和日期信息。然后更新 RTC 时钟(“RTC 同步”LED 亮起)并将内部 LED 环信息复制到外部 LED 环。时间、日期和星期显示、日期 LED、夏令时/冬令时和闰年 LED 信息将更新为新的时间信息。无有效数据:当一个或多个奇偶校验位由于噪声信号不正常时,会继续接收 DCF 信息,但不会用于更新 RTC、显示器和 LED。外部 LED 环、“RTC 同步”和“DCF OK”LED 将被重置。时间、日期、星期、星期 LED、夏季/冬季 LED 和闰年 LED 不受影响,并继续显示最后接收到的有效值。 “Period Time”和/或“Period With”错误 LED 将指示错误并更新错误计数器显示。每小时,错误显示将投注设置为零。当由于噪声信号而在检测到分钟标记之前接收到更多 DCF 脉冲时,EoB,缓冲区结束 LED 亮起。 (当检测到分钟标记时,我们应该有不超过 58 位/脉冲) 检测到分钟标记后,开始新的循环。温度:在 30 秒标记处,温度显示屏将显示上次重置后过去一段时间的高值和低值。 Chime:如果 CHIME 开关为 ON/HIGH,则在每小时开始时,Chime(如果已连接)将发出声音。在夜间,用户在代码中设置的时间,禁用 chime。省电 - 显示器关闭 这仅在省电开关为高电平时才有效: 1. 夜间关闭 在用户设置的时间,显示器在晚上关闭并在早上打开。查看 POWERSAVINGOFFTIME 和 POWERSAVINGONTIME 变量。检查功能  以选择要在夜间关闭的显示器。 2. PIR SENSOR 连接 PIR 传感器并激活 PIR 选项 POWERSAVE_BY_PIR 和 PIR_DELAY_TIME 的延迟。每次 PIR 检测器检测到移动时,都会重置分钟计数器,但如果检测到的移动时间超过 PIR_DELAY_TIME,则显示屏将关闭。当发生移动时,显示屏会立即开启。注意:如前所述,当显示器关闭时,时钟将正常工作。 DCF 蜂鸣声:通过连接到 BUZZERSWITCHPIN 引脚的开关,您可以听到接收到的 DCF 位的声音。音调持续时间等于 DCF 位的脉冲宽度,因此为 100 或 200 毫秒。其他:当 RTC 电池电量耗尽或检测到连接故障时,RTC 错误 LED 亮起。积分:我从 Matthias Dalheimer 和 Thijs Elenbaas 的工作中学到了很多东西,他们制作了自己的 DCF77 解码器。如果没有他们的工作,我将不知道从哪里开始。我最终编写了自己的代码(使用他们的点点滴滴),所以我可以理解正在发生的事情......我的代码远非高效或先进,但它确实有效,我知道发生了什么。有趣的网站: - Brett Oliver :http://home.btconnect.com/brettoliver1/ - Joop Tap :http://www.jooptap.nl - Thijs Ellenbaas :http://thijs.elenbaas.net/2012/04/ arduino-dcf77-radio-clock-receiver-hardware-2/ - Mathias Dalheimer:https://github.com/roddi/DCF77-Arduino/blob/master/DCF77Servoclock/DCF77.h - DCF77 维基百科:https://en .wikipedia.org/wiki/DCF77 - 更多 DCF77 信息:http://www.picbasic.nl/indexes_uk.htm - 我的 Flickr 网站:https://www.flickr.com/photos/edr1924/albums - 我的 Github网站:https://github.com/deruiter *///----------------------------------- -------------------------------------------------- ---------------------// 图书馆//------------------------ -------------------------------------------------- --------------------------------// Arduino(新)时间库........ ..................... http://www.pjrc.com/teensy/td_libs_Time.html#include //如果使用 Arduino Uno、Mega 等,请启用此行。#include // 一个基本的 DS1307 库y 将时间作为 time_t 返回 .... http://www.pjrc.com/teensy/td_libs_DS1307RTC.html#include // Maxim 7219 显示库 ..... ...................... http://playground.arduino.cc/Main/LEDMatrix// !!!注意:您必须使用特殊版本的 Ledcontrol.h 库才能获得共阳极支持// 因为 Maxim 芯片通常只适用于普通阴极显示器!#include //SPI 接口库 .... ...................................... http://arduino.cc/en/Reference/ SPI#include // OneWire 可让您访问 Maxim/Dallas 制造的 1-wire 设备,// 例如 DS18S20、DS18B20、DS1822 ..................... ........ http://www.pjrc.com/teensy/td_libs_OneWire.html// DallasTemperature 库可以为您完成所有这些工作! ... http://milesburton.com/Dallas_Temperature_Control_Library#include //---------------------------- -------------------------------------------------- ---------------------------// Arduino UNO 引脚连接在一个易于阅读的表中//// 输入 - Rx - 用于编程/ 与 PC 通信// 输出 - Tx - 用于编程/与 PC 通信#define DCF77PIN 2 // 输入 - 来自天线 pcb 的 DCF 信号。 Pin 必须是中断输入!#define PIRDETECTORPIN 3 // 输入 - PIR 探测器:检查房间内的活动以激活显示器#define BUZZERSWITCHPIN 4 // 输入 - 开关 - 打开/关闭 DCF77“哔”压电蜂鸣器/ON =HIGH , OFF =LOW#define CHIMESWITCHPIN 5 // input - SWITCH - 打开/关闭每小时钟声/ ON =HIGH, OFF =LOW#define POWERSAVESWITCHPIN 6 // input - SWITCH - 打开/关闭省电功能,以便显示始终开启 / ON =HIGH, OFF =LOW#define TEMPSENSORPIN 8 // 输入 - Dallas One Wire DS18B20 温度传感器#define TEMPRESETPIN 9 // 输入 - PUSH BUTTON - 重置温度最小/最大内存/ HIGH =reset#define MAXIMCCLD 10 // 输出 - CS/LOAD - 到 Maxim 7219 芯片的伪 SPI 连接 - 7 段显示#define MAXIMCCCLK 11 // 输出 - CLOCK - 到 Maxim 7219 芯片的伪 SPI 连接 - 7 段显示#define MAXIMCCDATA 12 // 输出 -数据 - 与 Maxim 7219 芯片的伪 SPI 连接 - 7 段显示器// !!引脚 22 至 53 仅用于 LED#define LED_SUNDAY 22 // 输出 - LED - Sunday#define LED_MONDAY 23 // 输出 - LED - Monday#define LED_TUESDAY 24 // 输出 - LED - 星期二#define LED_WEDNESDAY 25 //输出 - LED - 星期三#define LED_THURSDAY 26 // 输出 - LED - 星期四#define LED_FRIDAY 27 // 输出 - LED - Friday#define LED_SATURDAY 28 // 输出 - LED - 星期六#define LED_CEST 29 // 输出 - LED - Summertime CEST #define LED_CET 30 // 输出 - LED - 冬季 CET#define LED_LEAPYEAR 31 // 输出 - LED - 闰年#define LED_RTCERROR 32 // 输出 - LED - 读取 RTC 数据时出现问题(空电池/连接)#define LED_RTCSYNC 33 //输出 - LED - 当 RTC 与 DCF 时间成功同步时亮#define LED_TEMP 34 // 输出 - LED - 显示温度#define LED_OPTION1 35 // 输出 - LED - 显示可选 1 数据#define LED_OPTION2 36 // 输出 - LED - 显示可选 2 数据#define LED_ERRORPT 37 // 输出 - LED - DCF 周期时间错误#define LED_ ERRORPW 38 // 输出 - LED - DCF 周期宽度错误#define LED_BUFFERFULL 39 // 输出 - LED - 缓冲区满指示,接下来将分析数据#define LED_MINUTEMARKER 40 // 输出 - LED - 缓冲区前检测到的 DCF 数据流结束已填充,数据已损坏#define LED_BUFFEROVERFLOW 41 // 输出 - LED - 由于信号错误,在一分钟内收到的数据比预期的多#define LED_DCFSTATUS 42 // 输出 - LED - 当我们有良好的 DCF 数据时亮起#define LED_POWERSAVE 43 / / output - LED - 省电模式被激活,一些显示器关闭#define LED_PARITY1PASS 44 // output - LED - Parity 1 bit is OK#define LED_PARITY1FAIL 45 // output - LED - Parity 1 bit FAILED#define LED_PARITY2PASS 46 //输出 - LED - 奇偶校验 2 位正常#define LED_PARITY2FAIL 47 // 输出 - LED - 奇偶校验 2 位 FAILED#define LED_PARITY3PASS 48 // 输出 - LED - 奇偶校验 3 位正常#define LED_PARITY3FAIL 49 // 输出 - LED - 奇偶校验 3 bit FAILED#define LED_PIRMOTION 50 // 输出 - LED - 当 PIR 检测到运动时亮起/ / 模拟引脚#define BUZZER A7 // 输出 - DCF77 的压电蜂鸣器“哔”(到蜂鸣器的“+”)#define SPEAKERVOLPIN A6 // 输出 - 音板音量 - LOW =音量低一级。 SPEAKERVOLUME 确定开机后激活此输出的次数#define CHIMEPIN A5 // 输出 - Chime Activate - OUTPUT LOW =Activate Chime on Adafruit Soundboard FX // 用于 DS1307 RTC // I2C 数据 - 连接到实时时钟 pcb/ / 用于 DS1307 RTC // I2C 时钟 - 连接到实时时钟 pcb//-------------------------------- -------------------------------------------------- ------------------------// DS18B20 初始化//-------------------- -------------------------------------------------- ------------------------------------OneWire ds(TEMPSENSORPIN); // 定义 Onewire 实例 DS//------------------------------------------- -------------------------------------------------- --------------// Maxim 7219 矩阵显示初始化//--------------------------- -------------------------------------------------- -----------------------------/* clearDisplay(int addr) ..................... ......................... 清除选中的显示 MaximCC.shutdown(int addr, boolean) ...... .......................... 从省电模式唤醒 MAX72XX(真 =睡眠,假 =唤醒)MaximCC.setIntensity(int addr , value) .......................... 为 LED 设置中等亮度 (0=min - 15=max) MaximCC .setLed(int addr, int row, int col, boolean state) .......... 打开行、列中的 LED。请记住,索引从 0 开始! MaximCC.setRow(int addr, int row, byte value) ...................... 这个函数有 3 个参数。例如:MaximCC.setRow(0,2,B10110000); MaximCC.setColumn(int addr, int col, byte value) ...................这个函数有 3 个参数。例如:MaximCC.setColumn(0,5,B00001111); MaximCC.setDigit(int addr, int digit, byte value, boolean dp) ......这个函数接受一个byte类型的参数并在指定的列上打印相应的数字。有效值的范围从 0..15 开始。 0..9 之间的所有值都打印为数字,10..15 之间的值打印为其十六进制等效值 MaximCC.setChar(int addr, int digit, char value, boolean dp) .... 将显示: 0 1 2 3 4 5 6 7 8 9 ABCDEFHLP; - . , _  (空格或空格字符) POWERSAVESWITCHPIN ***** 请设置您拥有的设备数量 ***** 但最大默认值 8 MAX72XX 也可以使用。 LedConrol(DATAIN, CLOCK, CS/LOAD, NUMBER OF MAXIM CHIPS) */// lc 用于 Maxim 显示器LedControl MaximCC =LedControl(MAXIMCCDATA, MAXIMCCCLK, MAXIMCCLD, 7, false); // 定义 Maxim 72xx 的引脚以及我们使用多少个 72xx //----------------------------------- -------------------------------------------------- ---------------------// 用户设置、变量和数组定义//----------------- -------------------------------------------------- --------------------------------------// 下面的值不是 PIN 码而是一个值来设置声板上的“降低音量”输入被激活的次数//这样可以在通电后降低声板的音量,如果需要的话。#define SPEAKERVOLUME 12//选择你是否想要一个启动后测试所有 LED 和显示器//“1”=是,“0”=否#define PERFORM_LED_TEST 1//每 7 段显示之间的延迟,以毫秒为单位#define LEDTEST_DELAY_DISPLAYS 600// LED 环中每个 LED 之间的延迟和其他 LED 在 ms#define LEDTEST_DELAY_LED_RING 20 // 选择是否要将 DS18B20 温度传感器一次配置为最高分辨率。// 这是在使用冷杉传感器后需要的时间。运行软件后 // 将此设置设为 ON 一次,将其关闭。// '1' =ON, '0' =OFF#define CONFIGURE_DS18B20 0// POWERSAVE TIME - MANDATORY values!//// 定义日期和夜间。这用于省电显示的开和关时间// 并确定是否会激活提示音(在白天)。//// 只有在省电时间关闭显示器,时钟才能保持完全活动状态。/ / 要在任何时候禁用显示器电源,只需将节能开关设置为 OFF//// 节能开关打开:显示器将在设置的夜间关闭 // 并且如果 POWERSAVE_BY_PIR 功能被激活并且有没有 // 设置 PIR_DELAY_TIME 的运动。// 省电开关关闭:始终显示,仅在白天响铃。//// 值采用“小时”格式,因此晚上 8 点将是“20”,而不是 20:00或 8PM...#define POWERSAVINGOFFTIME 9 // 显示器已激活#define POWERSAVINGONTIME 22 // 显示器已关闭// 用户选项:仅当房间内有活动时才激活显示器// '1' =ON, '0 ' =OFF#define POWERSAVE_BY_PIR 1 // 延迟 MINUTES 在关闭显示器之前等待没有检测到#define PIR_DELAY_TIME 30 // 重置温度 min 的用户选项/ 午夜最大内存// '1' =午夜重置,'0' =仅手动重置#define TEMPRESET_MIDNIGHT 1//---------------------- -------------------------------------------------- -------// 定义杂项参数#define DS1307_I2C_ADDRESS 0x68 // 定义RTC I2C 地址#define DCF_INTERRUPT 0 // 与pin相关的中断号//定义Maxim 7219显示号接线顺序//第一个Maxim 7219 in接线'菊花链'必须为'0',下一个'1'等//公共阴极显示器#define LedRingInner 0#define LedRingOuter 1#define DisplayBufferBitError 2#define DisplayPeriodPulse 3#define DisplayTempWeek 4#define DisplayDate 5#define DisplayTime 6/ / 定义显示亮度级别#define BrightnessLedRingOuter 1#define BrightnessLedRingInner 1#define BrightnessDisplayTime 1#define BrightnessDisplayDate 7#define BrightnessDisplayTempWeek 15#define BrightnessDisplayPeriodPulse 2#define BrightnessDisplayBufferBitError 15 // Pulse flanksstatic unsigned longleadingEdge =0; tatic unsigned long trailingEdge =0;unsigned long previousLeadingEdge =0;// 用于 volatile unsigned int DCFSignalState =0; // 中断变量总是需要 volatile 限定符!!// 用于 
int previousSecond =0;unsigned int previousSignalState =0;// DCF 缓冲区和指标static int DCFbitBuffer[59]; // 这里,接收到的 DCFbits 被存储 const int bitValue[] ={1, 2, 4, 8, 10, 20, 40, 80}; // 这些是接收到的 DCFbits 的十进制值 // 只有在新的一分钟开始后,才会在内部 LED ringboolean MinuteMarkerFlag =false;int bufferPosition =0;int previousMinute =0;int previousHour =0;// 变量上显示接收到的比特检查 DCF 位是否为 valdbool dcfValidSignal =false;int dcfP1counter =0;int dcfP2counter =0;int dcfP3counter =0;int dcfParityCheckP1 =0;int dcfParityCheckP2 =0;int dcfParityCheckP3 =0 存储解码 DCF 变量时间inint dcfMinute =0;int dcfHour =0;int dcfDay =0;int dcfWeekDay =0;int dcfMonth =0;int dcfYear =0;int dcfDST =0;intleapYear =0;// 用于存储周数和日数值的变量int dayNumber;int weekNumber;// 错误计数器变量int errorCounter =0;boolean errorCondition =false;// 杂项变量boolean daytimeChange =true;boolean dayTime =false;int dcf77SoundSwitch =0;// 温度变量byte present =0;byte DS18B20Data[12];int maxTemp =0;int minTemp =0;int lowByte =0;int hi ghByte =0;float tempReading =0;int tempCelsius =0;boolean tempResetButton =false;// PIR 检测器变量int pirActivity =0;int pirDisplaysState =1;unsigned int pirTimer =0;unsigned long previousTimePIR =0;//===============================================================================// 设置//==============================================================================void setup(){ // 初始化串口通信Serial.begin(9600); // 初始化 PIN 连接 pinMode(DCF77PIN, INPUT); pinMode(TEMPRESETPIN,输入); pinMode(BUZZERSWITCHPIN, INPUT); pinMode(CHIMESWITCHPIN,输入); pinMode(POWERSAVESWITCHPIN,输入); pinMode(PIRDETECTORPIN,输入); pinMode(CHIMEPIN,输出); pinMode(SPEAKERVOLPIN,输出); // 初始化 LED 引脚 22 - 50 for (int i1 =22; i1 <=50; i1++) { pinMode(i1, OUTPUT); } // 初始化变量、LED 显示和 LED 的 initialize(); // 在引脚 DCF_INTERRUPT 上初始化 DCF77 脉冲中断,寻找信号的变化, // 因此上升沿或下降沿脉冲将触发中断处理程序并 // 执行 int0handler 函数。 attachInterrupt(DCF_INTERRUPT, int0handler, CHANGE); // 初始化 RTC 并设置为 SyncProvider。 // 稍后 RTC 将与 DCF 时间同步 setSyncProvider(RTC.get); // 从 RTC 获取时间的函数 // 检查 RTC 是否设置了系统时间 if (timeStatus() !=timeSet) { // 无法与 RTC 同步 - 激活 RTCError LED digitalWrite(LED_RTCERROR, HIGH); } else { // RTC 已设置系统时间 - 调暗 RTCError LED digitalWrite(LED_RTCERROR, LOW); } // 上电后,设置Adafruit Audio Board的扬声器音量 // 将两个管脚初始化为低电平,即默认输出状态 digitalWrite(SPEAKERVOLPIN, LOW);数字写入(CHIMEPIN,低); // 使用 'SPEAKERVOLUME' 步骤降低音板默认音量 for (int i =0; i <=SPEAKERVOLUME; i++) { digitalWrite(SPEAKERVOLPIN, HIGH);延迟(100);数字写入(SPEAKERVOLPIN,低);延迟(100); } // 下面的函数应该只运行一次。 // 用于配置DS18B20传感器的温度分辨率 if (CONFIGURE_DS18B20 ==1) { configureDS18B20(); } // 用于测试目的和/或手动设置 RTC 时间 // setTime(23, 59, 40, 31, 12, 13); // RTC.set(now()); // 请求温度转换 calculateTemp(); // 检查是否需要 LED 测试 if (PERFORM_LED_TEST ==1) { // 进行 LED 测试 ledTest(); } else { // 如果不做 LED 测试,我们需要等待 DS18B20 传感器准备好延迟(750); } // 现在从传感器获取温度并显示它 displayTemp(); // LED 测试后激活错误计数器显示 ledDisplay(DisplayBufferBitError, "R", 0);}//==============================================================================// 循环//==============================================================================void loop(){ // 首先检查脉冲方向是否改变(上升或下降) // 否则我们将继续评估相同的脉冲 if (DCFSignalState !=previousSignalState) { // 'reset'变量的状态 previousSignalState =DCFSignalState; // 评估输入脉冲 scanSignal(); } // 检查开关是否改变并对其采取行动 checkSwitches(); // 检查 PIR 移动 checkPIR(); // 执行必须每秒、每分钟或每小时只发生一次的任务 //-------------------------------- -------------------------------------tasksEverySecond();任务每分钟(); tasksEveryHour();}//================================================================================================================//// 函数名称:processDcfBit// 调用自://// 目的:评估接收到的信号。决定我们收到的是“1”还是“0”//并检查脉冲计时是否在限制范围内//参数:无//返回值:无////================================================================================================================/* 脉宽脉宽|- -| |-- --| |----- 分钟结束标记:2000ms -----| ___ ___ ___ ___ ___ | 0 | | 1 | | 0 | | 0 | | 1 | | | | | | | | | | | | | | | | | | | | | ______| |_______________| |_______| |___________________________________| |_______________| |__ _ _ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 1000 2100 2000 2200 3000 3100 3100 NO PULSE 5000 5100 6000 6200 <<示例millis()值=#5 DCF ^bit结束^#DCF ^位^# 57 DCFbit# 58 DCFbit# 0 DCFbit# 1 等等... < REJECTED error(LED_ERRORPW); errorCondition =true; } //-------------------------------------------------------------------------------- // CHECK PULSE TIME //-------------------------------------------------------------------------------- // If the detected pulse is too short it will be an incorrect pulse that we shall reject // should be 100 and 200 ms ideally if (((trailingEdge - leadingEdge) <70) || ((trailingEdge - leadingEdge)> 230)) { //rPT - ERROR:Pulse Width too short or too long -> REJECTED error(LED_ERRORPT); errorCondition =true; } // if we had an error return and start over if (errorCondition ==true) { errorCondition =false; // although we have an error, store current rising edge time to compare at the next Rising-Edge. previousLeadingEdge =leadingEdge;返回; } //-------------------------------------------------------------------- // no errors found so now we can continue //-------------------------------------------------------------------- // first we turn any error Led's OFF digitalWrite(LED_ERRORPW, LOW); digitalWrite(LED_ERRORPT, LOW); digitalWrite(LED_BUFFERFULL, LOW); // previous BF digitalWrite(LED_BUFFEROVERFLOW, LOW); // previous EoB digitalWrite(LED_MINUTEMARKER, LOW); // previous EoM // END OF MINUTE check, looking for a gap of approx. 2000ms if (leadingEdge - previousLeadingEdge> 1900 &&leadingEdge - previousLeadingEdge <2100) { // end of minute detected:finalizeBuffer(); } // refresh previousLeadingEdge time with the new leading edge time previousLeadingEdge =leadingEdge; //-------------------------------------------------------------------------------- // process DCF bits //-------------------------------------------------------------------------------- // distinguish between long and short pulses if (trailingEdge - leadingEdge <170) { // call processDcfBit function and sent it the value '0' processDcfBit(0); // if switch is HIGH, the DCF pulses are audible if (dcf77SoundSwitch ==1) buzzer(100); } else { // call processDcfBit function and sent it the value '1' processDcfBit(1); // if switch is HIGH, the DCF pulses are audible if (dcf77SoundSwitch ==1) buzzer(200); } } // if (DCFSignalState ==0)} // void scanSignal();//================================================================================================================//// Function name :processDcfBit// called from ://// Purpose :after reception of one good DCF bit, do some checks and save it in the DCFbitBuffer array// Parameters :none// Return value :none////================================================================================================================void processDcfBit(int dcfBit){ //-------------------------------------------------------------------- // display values on the 7 segment displays //-------------------------------------------------------------------- // display bufferPosition, digits 7,6 MaximCC.setChar(DisplayBufferBitError, 7, bufferPosition / 10, false); MaximCC.setChar(DisplayBufferBitError, 6, bufferPosition % 10, false); // display received DCFbit, digit 4 MaximCC.setChar(DisplayBufferBitError, 4, dcfBit, false); //-------------------------------------------------------------------- // display incoming DCF bits on inner LED ring //-------------------------------------------------------------------- // only if we have valid DCF data or after an Minute Mark (EoM) signal // activate the inner LED ring and diplay incoming data if (dcfValidSignal ==true || MinuteMarkerFlag ==true) { // display received bits on inner LED ring MaximCC.setLed(LedRingInner, bufferPosition / 8, bufferPosition % 8, dcfBit); } //-------------------------------------------------------------------- // // Fill DCFbitBuffer array with DCFbit //-------------------------------------------------------------------- DCFbitBuffer[bufferPosition] =dcfBit; //-------------------------------------------------------------------- // Parity check //-------------------------------------------------------------------- // DURING reception of the DCF bits, calculate and display the results of the DCF parity check. // // There is a Parity bit for the minutes, the hours and for the date. // DCF77 works with EVEN parity, this works as follows:// The hours for example have 6 bits plus a paritybit. The bits with value 1 are add up including the paritybit, // the result must be an even number. If there is a bit wrong received, a 0 is as 1, or a 1 is as 0 received, // then the result is uneven. source:http://www.picbasic.nl/frameload_uk.htm?http://www.picbasic.nl/info_dcf77_uk.htm if (bufferPosition ==0) { // reset the parity LED's digitalWrite(LED_PARITY1PASS, LOW); digitalWrite(LED_PARITY1FAIL, LOW); digitalWrite(LED_PARITY2PASS, LOW); digitalWrite(LED_PARITY2FAIL, LOW); digitalWrite(LED_PARITY3PASS, LOW); digitalWrite(LED_PARITY3FAIL, LOW); // reset variables dcfP1counter =0; dcfP2counter =0; dcfP3counter =0; dcfParityCheckP1 =0; dcfParityCheckP2 =0; dcfParityCheckP3 =0; } // ---------------------------------------- // First parity check:minute bits // ---------------------------------------- if (bufferPosition ==28) { for (int i =21; i <=27; i++) { // count the number of bits with the value '1' dcfP1counter +=DCFbitBuffer[i]; } // perform P1 parity check. Parity is OK if the sum is an EVEN value if ((DCFbitBuffer[28] + dcfP1counter) % 2 ==0) { // Parity1 PASS LED ON digitalWrite(LED_PARITY1PASS, HIGH); // Parity P1 PASS dcfParityCheckP1 =1; } else { // Parity1 FAIL LED ON digitalWrite(LED_PARITY1FAIL, HIGH); // we have no valid data! dcfValidSignal =false; // Turn DCF OK LED OFF digitalWrite(LED_DCFSTATUS, LOW); } } // ---------------------------------------- // Second parity check:hour bits // ---------------------------------------- if (bufferPosition ==35) { for (int i =29; i <=34; i++) { dcfP2counter +=DCFbitBuffer[i]; } // perform P2 parity check. Parity is OK if the sum is an EVEN value if ((DCFbitBuffer[35] + dcfP2counter) % 2 ==0) { // Parity2 PASS LED ON digitalWrite(LED_PARITY2PASS, HIGH); // Parity P2 PASS dcfParityCheckP2 =1; } else { // Parity2 FAIL LED ON digitalWrite(LED_PARITY2FAIL, HIGH); // we have no valid data! dcfValidSignal =false; // Turn DCF OK LED OFF digitalWrite(LED_DCFSTATUS, LOW); } } // ---------------------------------------- // Third parity check:date bits // ---------------------------------------- if (bufferPosition ==58) { for (int i =36; i <=57; i++) { dcfP3counter +=DCFbitBuffer[i]; } // perform P3 parity check. Parity is OK if the sum is an EVEN value (DCFbitBuffer[58] + dcfP3counter) % 2 ==0 ? dcfParityCheckP3 =1 :dcfParityCheckP3 =0; // Turn Parity2 'PASS' or 'FAIL' LED ON if (dcfParityCheckP3 ==1) { // Parity2 PASS LED ON digitalWrite(LED_PARITY3PASS, HIGH); // Parity P3 PASS dcfParityCheckP3 =1; } else { // Parity2 FAIL LED ON digitalWrite(LED_PARITY3FAIL, HIGH); // we have no valid data! dcfValidSignal =false; // Turn DCF OK LED OFF digitalWrite(LED_DCFSTATUS, LOW); } // ---------------------------------------- // finally, check all Parity bits // ---------------------------------------- dcfParityCheckP1 + dcfParityCheckP2 + dcfParityCheckP3 ==3 ? dcfValidSignal =true :dcfValidSignal =false; } //-------------------------------------------------------------------- // before continuing with the next bit, increment counter //-------------------------------------------------------------------- bufferPosition++; //-------------------------------------------------------------------- // check if we have not received too many pulses? //-------------------------------------------------------------------- if (bufferPosition> 59) { // Buffer Overflow ERROR - we have received more pulses before reaching // the 2 second 'gap' signalling the end of the minute. //This error may be due to a noisy signal giving addition peaks/dcfBits // So clear both DCFbit displays and start again. // Reset buffer counter bufferPosition =0; // clear inner LED ring MaximCC.clearDisplay(LedRingInner); // turn Buffer Overflow Error LED ON error(LED_BUFFEROVERFLOW); // exit return; } //-------------------------------------------------------------------- // everything OK so we wait for next incoming DCFbit //--------------------------------------------------------------------}//================================================================================================================//// Function name :finalizeBuffer// called from ://// Purpose :Process the succesfully received DCF data of one minute// Parameters :none// Return value :none////================================================================================================================void finalizeBuffer(void){ //-------------------------------------------------------------------- // We are here because of the detected 2 second 'gap'. // Now check if it correspondends with the buffer counter // 'bufferPosition' which should be value 59 //-------------------------------------------------------------------- if (bufferPosition ==59 &&dcfValidSignal ==true) { // bufferPosition ==59 so turn Buffer Full LED ON digitalWrite(LED_BUFFERFULL, HIGH); // Turn DCF OK LED ON digitalWrite(LED_DCFSTATUS, HIGH); // Reset inner LED ring (incoming time information) MaximCC.clearDisplay(LedRingInner); // copy 'contents' of inner LED ring to the outer LED ring (current time information) for (int i =0; i <59; i++) { MaximCC.setLed(LedRingOuter, i / 8, i % 8, DCFbitBuffer[i]); } // process buffer and extract data sync the time with the RTC decodeBufferContents(); // set Arduino time and after that set RTC time setTime(dcfHour, dcfMinute, 0, dcfDay, dcfMonth, dcfYear); RTC.set(now()); // activate Synced LED digitalWrite(LED_RTCSYNC, HIGH); // Reset running buffer bufferPosition =0; // Reset DCFbitBuffer array, positions 0-58 (=59 bits) for (int i =0; i <59; i++) { DCFbitBuffer[i] =0; } // reset flag MinuteMarkerFlag =false; } // if (bufferPosition ==59) //-------------------------------------------------------------------- // The buffer is not yet filled although the 2 second 'gap' was detected. // Can be result of a noisy signal, starting in middle of receiving data etc. // Turn 'Minute Mark' LED ON //-------------------------------------------------------------------- else { digitalWrite(LED_MINUTEMARKER, HIGH); // Clear displays MaximCC.clearDisplay(LedRingInner); MaximCC.clearDisplay(LedRingOuter); // Reset running buffer and start afresh. Now we are in sync with the incoming data bufferPosition =0; // Reset DCFbitBuffer array, positions 0-58 (=59 bits) for (int i =0; i <59; i++) { DCFbitBuffer[i] =0; } // set flag so we can display incoming pulsed on the inner LED ring. MinuteMarkerFlag =true; }}//================================================================================================================//// Function name :decodeBufferContents// called from ://// Purpose :Evaluates the information stored in the buffer.// This is where the DCF77 signal is decoded to time and date information// Parameters :none// Return value :none////================================================================================================================void decodeBufferContents(void){ // Buffer is full and ready to be decoded dcfMinute =bitDecode(21, 27); dcfHour =bitDecode(29, 34); dcfDay =bitDecode(36, 41); dcfWeekDay =bitDecode(42, 44); dcfMonth =bitDecode(45, 49); dcfYear =bitDecode(50, 57); //call function to calculate day of year and weeknumber dayWeekNumber(dcfYear, dcfMonth, dcfDay, dcfWeekDay); // Get value of Summertime DCFbit. '1' =Summertime, '0' =wintertime dcfDST =bitDecode(17, 17); // determine Leap Year leapYear =calculateLeapYear(dcfYear);}//================================================================================================================//// bitDecode//// called from //================================================================================================================int bitDecode(int bitStart, int bitEnd){ // reset 'bitValue-array' counter int i =0; int value =0;...This file has been truncated, please download it to see its full contents.
Superfilter sketchArduino
//// This is the Superfilter sketch I use with the DCF Analyzer/Clock 2.0 // Udo Klein did an amazing job with this filter//// Erik de Ruiter/* Arduino Uno pin connections I used for the DCF Analyzer Clock DCF input ................. A5 (19) =dcf77_sample_pin Output DCF Filtered ....... 12 =dcf77_filtered_pin Output DCF Semi Synthesized A2 (16) =dcf77_semi_synthesized_pin Output DCF Synthesized .... 6 =dcf77_synthesized_pin LED DCF output filtered ... A4 (18) =dcf77_monitor_pin =DCF Monitor LED LED 1 Hz pulse ............ 10 =dcf77_second_pulse_pin =Filter Locked LED LED DCF OK ................ 13 =dcf77_signal_good_indicator_pin =Signal Quality LED LED Difference Filtered ... 7 =dcf77_filter_diff_pin \ LED Difference Semi Synth.. A0 =dcf77_semi_synthesized_diff_pin -> =Signal Difference LED LED Difference Synthesized 4 =dcf77_synthesized_diff_pin /*/ //// www.blinkenlight.net//// Copyright 2014, 2015 Udo Klein//// This program is free software:you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program. If not, see http://www.gnu.org/licenses/#include /*const uint8_t pon_pin =51; // connect pon to ground !!!const uint8_t data_pin =19;const uint8_t gnd_pin =51;const uint8_t vcc_pin =49;*/const uint8_t dcf77_analog_samples =false;const uint8_t dcf77_analog_sample_pin =5;const uint8_t dcf77_sample_pin =19; // A5const uint8_t dcf77_inverted_samples =0;#if defined(__AVR__)#define ledpin(led) (led)#else#define ledpin(led) (led<14? led:led+(54-14))#endifconst uint8_t dcf77_monitor_pin =ledpin(18); // A4const bool provide_filtered_output =true;const uint8_t dcf77_filtered_pin =ledpin(12);const uint8_t dcf77_inverted_filtered_pin =ledpin(11);const uint8_t dcf77_filter_diff_pin =ledpin(7);const bool provide_semi_synthesized_output =true;const uint8_t dcf77_semi_synthesized_pin =ledpin(16);const uint8_t dcf77_inverted_semi_synthesized_pin =ledpin(15);const uint8_t dcf77_semi_synthesized_diff_pin =ledpin(14);const bool provide_synthesized_output =true;const uint8_t dcf77_synthesized_pin =ledpin(6);const uint8_t dcf77_inverted_synthesized_pin =ledpin(5);const uint8_t dcf77_synthesized_diff_pin =ledpin(4);const uint8_t dcf77_second_pulse_pin =ledpin(10);const uint8_t dcf77_signal_good_indicator_pin =ledpin(13);volatile uint16_t ms_counter =0;volatile Internal::DCF77::tick_t tick =Internal::DCF77::undefined;template void set_output(uint8_t clock_state, uint8_t sampled_d ata, uint8_t synthesized_signal){ if (enable) { const uint8_t filtered_output =clock_state  200) :digitalRead(dcf77_sample_pin)); #else dcf77_inverted_samples ^ digitalRead(dcf77_sample_pin); #endif digitalWrite(dcf77_monitor_pin, sampled_data); digitalWrite(dcf77_second_pulse_pin, ms_counter <500 &&clock_state>=Clock::locked); const uint8_t synthesized_signal =tick ==Internal::DCF77::long_tick ? ms_counter <200:tick ==Internal::DCF77::short_tick ? ms_counter <100:tick ==Internal::DCF77::sync_mark ? 0:// tick ==DCF77::undefined --> default handling // allow signal to pass for the first 200ms of each second (ms_counter <=200 &&sampled_data) || // if the clock has valid time data then undefined ticks // are data bits --> first 100ms of signal must be high ms_counter <100; set_output (clock_state, sampled_data, synthesized_signal); set_output (clock_state, sampled_data, synthesized_signal); set_output (clock_state, sampled_data, synthesized_signal); ms_counter+=(ms_counter <1000); scope_1.process_one_sample(sampled_data); scope_2.process_one_sample(digitalRead(dcf77_synthesized_pin)); return sampled_data;}void output_handler(const Clock::time_t &decoded_time) { // reset ms_counter for 1 Hz ticks ms_counter =0; // status indicator --> always on if signal is good // blink 3s on 1s off if signal is poor // blink 1s on 3s off if signal is very poor // always off if signal is bad const uint8_t clock_state =DCF77_Clock::get_clock_state(); digitalWrite(dcf77_signal_good_indicator_pin, clock_state>=Clock::locked ? 1:clock_state ==Clock::unlocked? (decoded_time.second.digit.lo &0x03) !=0:clock_state ==Clock::free ? (decoded_time.second.digit.lo &0x03) ==0:0); // compute output for signal synthesis Internal::DCF77_Encoder now; now.second =BCD::bcd_to_int(decoded_time.second); now.minute =decoded_time.minute; now.hour =decoded_time.hour; now.weekday =decoded_time.weekday; now.day =decoded_time.day; now.month =decoded_time.month; now.year =decoded_time.year; now.uses_summertime =decoded_time.uses_summertime; now.leap_second_scheduled =decoded_time.leap_second_scheduled; now.timezone_change_scheduled =decoded_time.timezone_change_scheduled; now.undefined_minute_output =false; now.undefined_uses_summertime_output =false; now.undefined_abnormal_transmitter_operation_output =false; now.undefined_timezone_change_scheduled_output =false; now.advance_minute(); tick =now.get_current_signal();}void setup_serial() { Serial.begin(115200);}void output_splash_screen() { Serial.println(); Serial.println(F("DCF77 Superfilter 3.0")); Serial.println(F("(c) 2015 Udo Klein")); Serial.println(F("www.blinkenlight.net")); Serial.println(); Serial.print(F("Sample Pin:")); Serial.println(dcf77_sample_pin); Serial.print(F("Inverted Mode:")); Serial.println(dcf77_inverted_samples); #if defined(__AVR__) Serial.print(F("Analog Mode:")); Serial.println(dcf77_analog_samples); #endif Serial.print(F("Monitor Pin:")); Serial.println(dcf77_monitor_pin); Serial.println(); if (provide_filtered_output) { Serial.println(F("Filtered Output")); Serial.print(F(" Filtered Pin:")); Serial.println(dcf77_filtered_pin); Serial.print(F(" Diff Pin:")); Serial.println(dcf77_filter_diff_pin); Serial.print(F(" Inverse Filtered Pin:")); Serial.println(dcf77_inverted_filtered_pin); Serial.println(); } if (provide_semi_synthesized_output) { Serial.println(F("Semi Synthesized Output")); Serial.print(F(" Filtered Pin:")); Serial.println(dcf77_semi_synthesized_pin); Serial.print(F(" Diff Pin:")); Serial.println(dcf77_semi_synthesized_diff_pin); Serial.print(F(" Inverse Filtered Pin:")); Serial.println(dcf77_inverted_semi_synthesized_pin); Serial.println(); } if (provide_synthesized_output) { Serial.println(F("Synthesized Output")); Serial.print(F(" Filtered Pin:")); Serial.println(dcf77_synthesized_pin); Serial.print(F(" Diff Pin:")); Serial.println(dcf77_synthesized_diff_pin); Serial.print(F(" Inverse Filtered Pin:")); Serial.println(dcf77_inverted_synthesized_pin); Serial.println(); } Serial.print(F("Second Pulse Pin:")); Serial.println(dcf77_second_pulse_pin); Serial.print(F("Signal Good Pin:")); Serial.println(dcf77_signal_good_indicator_pin); Serial.println(); Serial.println(); Serial.println(F("Initializing...")); Serial.println();};void setup_pins() { if (provide_filtered_output) { pinMode(dcf77_filtered_pin, OUTPUT); pinMode(dcf77_filter_diff_pin, OUTPUT); pinMode(dcf77_inverted_filtered_pin, OUTPUT); } if (provide_semi_synthesized_output) { pinMode(dcf77_semi_synthesized_pin, OUTPUT); pinMode(dcf77_semi_synthesized_diff_pin, OUTPUT); pinMode(dcf77_inverted_semi_synthesized_pin, OUTPUT); } if (provide_synthesized_output) { pinMode(dcf77_synthesized_pin, OUTPUT); pinMode(dcf77_synthesized_diff_pin, OUTPUT); pinMode(dcf77_inverted_synthesized_pin, OUTPUT); } pinMode(dcf77_monitor_pin, OUTPUT); pinMode(dcf77_signal_good_indicator_pin, OUTPUT); pinMode(dcf77_second_pulse_pin, OUTPUT); pinMode(dcf77_sample_pin, INPUT); digitalWrite(dcf77_sample_pin, HIGH);}void setup_clock() { DCF77_Clock::setup(); DCF77_Clock::set_input_provider(sample_input_pin); DCF77_Clock::set_output_handler(output_handler);}void setup() { setup_serial(); output_splash_screen(); setup_pins(); setup_clock();/* pinMode(gnd_pin, OUTPUT); digitalWrite(gnd_pin, LOW); pinMode(pon_pin, OUTPUT); digitalWrite(pon_pin, LOW); pinMode(vcc_pin, OUTPUT); digitalWrite(vcc_pin, HIGH); */}void loop() { Clock::time_t now; DCF77_Clock::get_current_time(now); if (now.month.val> 0) { Serial.println(); Serial.print(F("Decoded time:")); DCF77_Clock::print(now); Serial.println(); } Serial.print(DCF77_Clock::get_clock_state()); Serial.print(' '); DCF77_Clock::debug(); scope_1.print(); scope_2.print();}

定制零件和外壳

This is a PCB I made for the Time and Date displays Maxim_7219_LED_display_unit_for_Adafruit_0_56inch_7_segment_v1_1.zipThis is my PCB design for the very compact smaller 7 segment displays Maxim_7219_LED_display_unit_for_KingBright_7_segment_SC39_11SRWAv1_1.zipTicking sound and Chime sound, see text for explanation Grandfather_Clock_Sound_files.zip

示意图

DOWNLOAD to view details! dcf77-analyzer-clock-v2_1_jVZT5sqIwn.zip

制造工艺

  1. 布谷鸟钟
  2. Arduino pov 视觉时钟
  3. DIY 最简单的 IV9 Numitron 时钟与 Arduino
  4. 使用 Adafruit 1/4 60 Ring Neopixel 的简单挂钟
  5. 简单字时钟(Arduino)
  6. 带有伊斯兰祈祷时间的 Arduino 时钟
  7. Arduino Spybot
  8. FlickMote
  9. 主时钟
  10. Arduino 温度。使用 3.2 显示的监视器和实时时钟
  11. 7 段阵列时钟
  12. 带 DS1302 RTC 的简单闹钟