非接触式音乐洗手定时器
组件和用品
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
应用和在线服务
|
关于这个项目
虽然洗手一直是预防疾病和整体健康的重要武器,但它作为遏制 COVID-19 大流行蔓延的预防措施而获得了新的重视。
CDC 的良好洗手指南指出,理想情况下必须洗手 20 秒。 https://www.cdc.gov/handwashing/when-how-handwashing.html
🤓📚** 额外的东西 ** 🤓📚 如果您有兴趣,这里有一些洗手背后的科学! - https://www.cdc.gov/handwashing/show-me-the-science-handwashing.html
在这个洗手计时器的改进中,我们的音乐洗手计时器通过在超声波传感器前挥手来激活,并在 7 段显示器上显示倒计时。为了让它更有趣,它还会从预编程的叮当声列表中轮流播放 20 秒的叮当声。您可以通过转录您拥有的任何乐谱来轻松添加自己的音乐!
下面是 Touchless Musical 洗手定时器 在行动中,显示了我在
中编写的所有 4 个叮当声- 生日快乐
- Do-Re-Mi(音乐之声)
- 我们会摇滚你(女王)
- 危险主题音乐
男孩,我的手是超级骗子 干净到最后吧! 😊
🤓📚** 额外的东西 ** 🤓📚到现在,我们都知道,唱两遍《祝你生日快乐》大约需要20秒,而且这已经成为了事实上的洗手时间标准,甚至连加拿大总理贾斯汀·特鲁多都唱过!加拿大首席公共卫生官 Theresa Tam 博士有她自己的最爱,例如 We Will We Will Wash You ! 😊在下面观看 CBC 儿童新闻撰稿人 Arjun Ram 的精彩采访。
我在我们的 Touchless Musical Hand Wash Timer 中收录了这两首歌 ,再加上几个! 😊
第 1 步 - 示意图
该项目使用 Arduino Uno、7 段 LED 背包 (I2C)、HC-SR04 超声波传感器和压电蜂鸣器。请参考下面的示意图。
第 2 步 - 规划和设置
除了原理图和编程之外,我还想考虑“成品”以及如何使其可用 - 因此将其放入外壳并为此进行规划。
我使用了 ProtoStax Enclosures - 它们是可堆叠的,并且支持 Arduino、Raspberry Pi 和 Breadboard。由于我使用带有面包板电路的 Arduino,我为 Arduino 选择了 ProtoStax Enclosure,为面包板/定制板选择了 ProtoStax Enclosure。我还希望超声波传感器可以从外面接触到,因此固定在外壳上 - 我使用了用于超声波传感器 HC-SR04 的 ProtoStax 套件。
我开始使用水平堆叠连接器水平堆叠 Arduino 和 Breadboard 基础平台以促进原型设计:
一旦我有了原型平台,我就可以开始根据原理图填充组件。我将 HC-SR04 超声波传感器连接到用于超声波传感器 HC-SR04 的 ProtoStax 套件的侧壁上,以便在原型完成后将外壳组装在一起后即可使用。带有传感器的侧壁进入底座的槽中,如图所示:
图>
第 3 步 - 编程和测试
现在我有了一个工作原型平台,我可以开始为它开发代码。我将在下面的单独部分中深入研究代码功能和布局。这是测试的视频。疯狂的是,我用来录制视频的 iPhone 11 实际上拾取了超声波传感器的明显声纳脉冲,在下面的视频中可以非常清楚地听到(尽管超声波脉冲几乎无法通过无害的点击进行注册 -点击-点击)! 😊
确认一切正常后,我继续添加侧壁和剩余的连接器和顶部以完成我的外壳:
顶部的视频显示了正在使用的最终“产品”! 😊
理解代码
初始化组件:
我们使用 LED Backpack 库中的 Adafruit_7segment 类来初始化我们的 7 段显示器并与之通信。
Adafruit_7segment matrix =Adafruit_7segment();
我们还将HC-SR04上的trig和echo pin分别初始化为输出和输入
pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); matrix.begin(0x70);
在主循环中,这是在高层次上完成的:
1) 检查超声波传感器距离读数,看是否已触发洗手定时器。
2)如果是,则记下当前时间,初始化倒计时计时器(我将其设置为 20 为 20 秒),并选择下一个要播放的音乐叮当声。我首先使用 random() 来选择随机旋律,但我在旋律数组上将其更改为“循环”(循环回到第一个),并将 startMusic 设置为 1(设置倒计时和运动中的音乐播放) .
if (distance <10 &&!startMusic) { startMusic =1; // initializeTimer1();倒计时 =20;当前时间 =毫秒(); melodyNum =(melodyNum+1)%(NUM_MELODIES(melody)); }
看马没有延迟()!
在这里,我们同时做两件事——我们要定期更新倒计时时钟,显示还剩多少秒可以洗手。我们还希望处理叮当声并及时正确播放。
我们不能 因此使用延迟()。
播放音乐的典型示例使用 Tone 库的tone() 函数,并在继续播放下一个音符之前等待适当的延迟。这是行不通的,因为我们还想更新倒计时!
tone() 是一个非阻塞调用。它使用 Timer2 在指定的时间长度内发送信号,这意味着在此期间,我们可以自由地进行其他处理。
我们使用millis() 和局部变量来计算已经过去了多少时间,而不是使用delay(),并且可以在此期间继续进行其他检查并执行其他操作。我们将进一步查看确切的代码。
以简单的方式转录音乐 - 全音符、四分音符等
我们想要演奏给定的旋律,也想让转录更多旋律变得容易。 Arduino 音乐示例通常存储两种不同的数组,一种用于音符,另一种用于音符持续时间(以毫秒为单位)。
为了简化事情,我创建了一个结构来关联一个音符和它给定的持续时间。我没有使用绝对持续时间,而是使用了我为
创建的 #defines 的相对持续时间typedef struct Note { int frequency;浮动持续时间; } 注意;#define NOTE_WHOLE 1#define NOTE_HALF 0.5f#define NOTE_QUARTER 0.25f#define NOTE_EIGHTH 0.125f#define NOTE_SIXTEENTH 0.0625f#define DOTTED(X) (X * 1.5f)
让我们以生日快乐为例。
这可以转录如下,非常注意注意。如果您无法阅读乐谱,只需找到要使用的实际音符即可。 🤓📚但是学习阅读乐谱总是一项很好的技能,而且您不必非常擅长 - 只需知道音符是什么就可以让您将音乐移调到您的阿杜诺! 🤓📚
// Happy BirthdayNote melody[] ={ {NOTE_G6, DOTTED(NOTE_EIGHTH)}, {NOTE_G6, NOTE_SIXTEENTH}, {NOTE_A6, NOTE_QUARTER}, {NOTE_G6, NOTE_QUARTER}, {NOTE_C7, NOTE_QUARTERB6, {NOTE_G6, NOTE_QUARTERB ,NOTE_HALF},{NOTE_G6,DOTTED(NOTE_EIGHTH)},{NOTE_G6,NOTE_SIXTEENTH},{NOTE_A6,NOTE_QUARTER},{NOTE_G6,NOTE_QUARTER},{NOTE_D7,NOTE_QUARTER},{NOTE_C7,{NOTE_C7,NOTE_HOTTHLF}) },{NOTE_G6,NOTE_SIXTEENTH},{NOTE_E7,NOTE_QUARTER},{NOTE_D7,NOTE_QUARTER},{NOTE_C7,NOTE_QUARTER},{NOTE_B6,NOTE_QUARTER},{NOTE_A6,NOTE_HALF},{NOTE_F7,NOTE_F7,DOTTE) NOTE_SIXTEENTH}, {NOTE_E7, NOTE_QUARTER}, {NOTE_C7, NOTE_QUARTER}, {NOTE_D7, NOTE_QUARTER}, {NOTE_C7, NOTE_HALF}, };
注意(双关语!)我在这里没有使用任何实际的持续时间,我将音符的相对持续时间指定为四分音符、八分音符、十六分音符等。我什至有一个 DOTTED() 宏来表示一个带点的音符(1.5 x 之前任何音符的持续时间)。
旋律本身包含这个数组,以及关于整个音符应该代表什么持续时间的附加信息。
typedef struct Melody { Note *notes; int numNotes; int wholeNoteDurationMs; } 旋律;
由于无法使用指向数组的指针来调整 C 数组的大小,因此我添加了 numNotes 作为 Note 数组的大小。这可以使用 MELODY_LENGTH 宏轻松初始化 - 这样您就不必担心在转录自己喜欢的歌曲时在 Note 数组中创建了多少个音符!
然后我定义了一个这样的 Melody 数组以在我的程序中使用。
Melody melodies[] ={ {melody, MELODY_LENGTH(melody), 1250}, {melody3, MELODY_LENGTH(melody3), 1000}, {melody4, MELODY_LENGTH(melody4), 1000}};
在循环中,当启动倒数计时器和音乐时,我使用上面的音符信息、相对持续时间和整个音符的实际持续时间来计算如何播放音乐。在播放音乐的间隙,我还检查并更新倒数计时器并在 7 段显示器上显示数字。
因为我想象人们想听完整个叮当声,所以我继续播放叮当声直到结束,即使 20 秒到了(倒计时将变成负数,直到歌曲结束)。叮当声结束后,它会停止,直到再次在超声波传感器前挥动您的手来进一步触发。如果叮当声太短,它将再次播放,直到 20 秒过去并且音乐播放完毕!简单的。
if (startMusic) { // 选择旋律播放 Melody mel =melodies[melodyNum];注意 *m =mel.notes; int mSize =mel.numNotes; // speedUp 是一种加快音符播放速度的简单方法。最好的方法是 // 适当地设置 WholeNoteDurationMs。 int speedUp =1; noTone(TONE_PIN); // 从一个干净的石板开始 for (int thisNote =0; thisNote
整个代码可以在 GitHub 上找到,并且包含到存储库的链接。我建议从那里获取代码,而不是从这里复制和粘贴代码。
进一步推进项目
一旦您熟悉了代码示例并理解了代码,尝试通过做更多事情来扩展您的学习总是很好的。
以下是有关如何推进该项目的一些建议:
1) 您可以找到自己喜欢的曲调,然后使用 NOTE 转录它 和注意 持续时间 我上面描述的宏。只需记住注释掉一个或多个已定义的其他叮当声,以降低内存使用量(除非您继续将 Note 和 Melody 数组成功移动到 PROGMEM,如下所述!😊)
2) 旋律会占用 SRAM 中的空间,并且会很快耗尽可用内存。例如,我转录了 4 首旋律(生日快乐、Do-Re-Mi、We Will Rock You 和 Jeopardy!)。然而,这些将 SRAM 使用率推到了 96%,不足以用于 7 段显示库的运行,并且它没有正确更新!我不得不从 Melody 数组中排除其中一首旋律,以便一切正常。
Arduino Uno 带有 2k SRAM,但带有 32k 闪存(程序所在的位置)。如果您可以将一些全局变量移动到闪存中,您不仅可以为程序的其余部分释放 SRAM,而且您还有更多空间来存储更多歌曲!尝试通过将 Note 和 Melody 数组定义为 PROGMEM 将它们移动到 Flash 中。 [注意:这是一项先进的工作,并非微不足道。你 将 成为 降级 数组 的 结构 到 PROGMEM 和 然后 有 到 阅读 程序 到 访问 数据。]
为了让您了解这些差异,这个程序(带有 3 个旋律)在 Uno 上占用了 31% 的程序存储和 76% 的动态内存。使用 PROGMEM 中定义的上述变量,它占用了 32% 的程序空间(这只是 Flash 内存使用量略有增加,还有更多可用空间)和仅 22%(低于 76%)的动态内存!这意味着您可以轻松添加大量 这个非接触式音乐洗手计时器的歌曲 一旦你把东西移到 PROGMEM! 😊
你能想出其他方式来扩展这个项目吗?在下面与我们分享! 😊
快乐制作! 😊
代码
ProtoStax 非接触式音乐洗手定时器演示
ProtoStax Touchless Musical Handwash Timer Demo https://github.com/protostax/ProtoStax_Touchless_Musical_Handwash_Timer示意图
这显示了用于非接触式音乐洗手倒数计时器的电路原理图制造工艺