使用Arduino制作Buzz Wire游戏

在这个有趣的项目中,我们将学习如何使用Arduino制作嗡嗡声有线游戏。所需的许多零件都可以在入门套件中找到(可以从中获得灵感)。

查看最终结果-甚至可以播放音乐:

您要做什么Need

这是完成此项目所需的核心部件:

  • 1 x Arduino UNO或类似产品。
  • 1 x金属衣架。
  • 2个220欧姆电阻器。
  • 1个面包板。
  • 1个压电蜂鸣器。
  • 2个鳄鱼夹。
  • 各种热缩管。
  • 公对公连接线。
  • 以下是一些可选部件,可增强构造:

  • 1 x附加的压电蜂鸣器。
  • 1 x定位杆。
  • 1 x四个七段显示器。
  • 1 x 220欧姆电阻。
  • 1 x瞬时按钮。
  • 公对母连接线。
  • 木板(例)。
  • 各种木螺钉。
  • 只要有足够的引脚,几乎任何Arduino都可以使用。如果不确定您的需求,请查看此购买指南。

    构建计划

    虽然这看起来很复杂,但实际上是一个简单的项目。我将从基本游戏开始,然后添加其他组件以增加复杂性。您可以根据需要选择“选择"。

    核心技工由金属丝形状和手柄上的环组成。玩家必须引导整个路线的循环,而不能使两个方向接触。如果两者接触,则电路完成,并且蜂鸣器响起。当然也可以不使用微控制器来构建该电路,但是这样做的乐趣何在(以及还能听到Monty Python的“ Flying Circus"主题曲)?

    课程

    这是玩家将要引导其循环的形状。这是整个游戏的基础,所以做得好!我选择先降一小点,然后再进行一次大的爬升。将金属衣架弯曲成所需的形状。黄铜线或铜管也可以正常工作,尽管衣架可能是最便宜的。

    您可能需要戴手套,用钳子或锤子才能使事情变得完美。用断线钳剪掉多余的部分。留下两个垂直的立柱以推入基座。为了安全起见,您想归档切割端。最后,切开两根热缩管,并如下放置在末端:

    这将使回路与路线隔离,从而提供起点/终点或安全区域。另外,如果您没有热缩管,也可以用胶带甚至是吸管。

    现在将电缆连接到课程的一端。您在这里有两个选择:可以焊接,也可以使用鳄鱼夹。鳄鱼夹是较容易的选择,但焊接是更可靠和长期的选择。确保首先用砂纸“弄粗"衣架表面,并使用大量助焊剂。 (以前从来没有焊接过?请学习这里的方法。)

    根据下一步在底座上钻的孔的大小,您可能需要先将电缆穿过安装孔。使用两根绞在一起的线会提高耐用性:

    底座

    是时候创建底座了。这用于将航线保持在直立位置,并提供将电子设备固定到的位置。我使用了一些松木碎片,尽管您可以使用房子周围的任何物品,甚至可以用纸板箱。

    将三块切成“ n"形。只需将这三部分拧(或胶)在一起。切记先在侧板上钻一个导向孔,以防止侧板裂开。您可能需要沉头螺钉(特别是如果要填充然后上漆),因此我强烈建议使用沉头钻头。如果您没有沉头工具或钻孔,则可以使用较大直径的钻头。

    钻两个孔,其距离应足够远,以便安装过程的末端。埋孔底侧,准备粘贴。

    为实际手柄切下一小段销钉。该金属环将插入该手柄中。如果没有销钉,则可以使用皮带或圆盘砂光机将一块方形的软木修圆(也可以使用砂纸,但这会花费很长时间)。

    钻一个洞这个手柄。它必须足够大以适合金属环和导线穿过:

    是的,我很清楚这是一台金属车床(对于任何感兴趣的人,它都是19世纪30年代的Boley制表车床。我认为这是3C,但是如果您对此有更多了解,我很乐意收到您的来信。)

    您还可以使用去除中心的圆珠笔。

    最后,使用热胶将电缆和回路固定到手柄中。热胶会提供牢固的(但不是永久性的)固定装置,因此非常适合。

    将导线束插入底座的孔中。别忘了先添加回路/控制器。再次使用热胶,通过如下方式填充底座底部的沉孔,将路线固定到底座上:

    电路

    这是完整的电路。您不必如此复杂-继续阅读每个部分,继续阅读。

    现在插入金属层并处理:

    一个电阻将电路接地(称为下拉电阻),确保其不“浮动"(这使Arduino能够检测到电路变化)。另一个电阻器保护Arduino。当两个部分接触时,+ 5V进入数字引脚。如果不存在此电阻,则可能会出现短路故障–如果幸运的话,您的计算机将断开USB插座的连接,以吸收过多的电流。

    连接信号线(紫色,如图所示)连接到数字引脚9。

    下一步,将按钮连接到数字引脚2:

    最后,连接七段LED显示器:

    代码

    要使该项目正常工作,您将需要两个附加文件。第一个称为 pitches.h 。该文件仅将音符名称映射到其压电值。例如,您可以简单地说“ NOTE_C3"而不是“ 31",这使编写乐曲变得容易得多。这是在公共领域,可以在Arduino网站上找到。按照说明创建一个名为 pitches.h 的新文件(或者将代码粘贴到现有脚本中)。

    接下来,您需要一种方法来实际演奏音符/旋律在压电上。 Anthony DiGirolamo在Github上撰写的要点包含您需要的代码。复制“ void buzz"和“}}"之间的所有内容并将其粘贴到您的主文件中。作为参考,这里是:

    void buzz(int targetPin, long frequency, long length) { /* Buzzer example function by Rob Faludi http://www.faludi.com https://gist.github.com/AnthonyDiGirolamo/1405180  */ long delayValue = 1000000/frequency/2; // calculate the delay value between transitions //// 1 second's worth of microseconds, divided by the frequency, then split in half since //// there are two phases to each cycle long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing //// multiply frequency, which is really cycles per second, by the number of seconds to //// get the total number of cycles to produce for (long i=0; i < numCycles; i++){ // for the calculated length of time... digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphragm delayMicroseconds(delayValue); // wait for the calculated delay value digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphragm delayMicroseconds(delayValue); // wait again for the calculated delay value }}

    您需要的最后一个库是控制七段显示-如果您不使用它,则可以跳过此步骤。该库名为 TM1637 ,由创建驱动板的同一家公司Seeed创建。

    在Arduino IDE中,转到“管理库"( Sketch >包含库>管理库)。这将调出库管理器。等待几秒钟进行更新,然后在右上方的搜索框“ TM1637"中搜索。将找到两个库-您需要“ TM1637"而不是“ TM1637Display"。选择,然后单击“安装"。

    此库的最后一项任务-它尚未完成!就目前而言,该库只能显示数字0–9和字母A–F。如果这涵盖了您要显示的所有内容,则可以跳过此步骤。如果不是,则需要修改代码。放松!这听起来并不那么困难,并且如果您可以使用Arduino IDE编写代码,则可以执行此操作。

    首先,打开您的库文件夹。这将在您的Arduino文件夹中。在Mac OS X上,该文件位于 / Users / Joe / Documents / Arduino / Libraries 中。打开名为 TM1637 的文件夹。您将需要编辑名为 TM1637.cpp 的文件-您可以安全地忽略扩展名为 .h 的其他文件。代码>。在您喜欢的文本编辑器(对我来说,这是Sublime Text 3),记事本或Arduino IDE中打开此文件。

    修改以下代码的第三行:

    static int8_t TubeTab[] = {0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71};//0~9,A,b,C,d,E,F

    To

    static int8_t TubeTab[] = {	/* defaults */	0x3f, // 0 	0x06, // 1	0x5b, // 2	0x4f, // 3  0x66, // 4 0x6d, // 5 0x7d, // 6 0x07, // 7 	0x7f, // 8 	0x6f, // 9	0x77, // A -- 10	0x7c, // b -- 11	0x39, // C -- 12	0x5e, // d -- 13	0x79, // E -- 14	0x71, // F -- 15	/* additional */	0x174, // h -- 16 0x176, // H -- 17 0x138, // L -- 18 0x15, // M -- 19 0x137, // n -- 20 0x73, // P -- 21 0x67, // q -- 22 0x131, // r -- 23 0x78, // t -- 24 0x240 // - 25};

    您现在可以保存并关闭此文件。在每个元素之后,注释描述了这是什么字符。注释的下一部分是元素的索引。

    是时候编写实际的代码了。首先,包括前面提到的两个库:

    #include <TM1637.h>#include <pitches.h>

    现在创建显示对象:

    TM1637 *_display = new TM1637(12, 13);

    Don’t worry if you don’t understand the syntax — this line tells the Arduino that pins 12 and 13 are attached to a seven segment display, and to configure it appropriately.

    这首歌存储在 melody 中>和速度。这些包含所有音符和音乐的音符持续时间。如果您想更改音乐,请修改这些数组(尽管它不如粘贴音符值那么简单,定时是音乐中非常重要的一部分)。 songState 变量仅存储最后播放的音符的位置。这样可以确保从头到尾播放旋律,而不是前后不停跳动。

    int songState = 0; int melody[] = { NOTE_F4,...}int tempo[] = { 8,...}

    请注意,我已经删除了数组的内容,请参见下面的完整代码。

    该代码是非阻塞的-这意味着Arduino可以同时执行多个任务。请查看此说明以获取更多信息。计时器的设置方法如下:

    unsigned long previousMillis1 = 0;const long interval1 = 1500;

    变量 previousMillis1 将在以后的阶段进行更新以存储当前时间。 interval1 变量存储两次代码执行之间的等待时间-在这种情况下为1.5秒。它被定义为 const ,这意味着它是恒定的,并且永远不会改变,这使Arduino可以进一步优化代码。

    在< code> setup()函数中发生了一些事情。首先,设置输入和输出。这是必须要做的,所以Arduino知道每个引脚都连接了什么:

    pinMode(9, INPUT); // setup circuitpinMode(10, OUTPUT); // setup buzzer 1pinMode(11, OUTPUT); // setup buzzer 2pinMode(2, INPUT); // setup button

    现在,显示器需要配置:

    _display->set(5); // set brightness_display->point(false); // remove colon_display->init(); // start display

    set方法 point init 都包含在< strong> _display 对象。代替点,使用指针(“->")访问它们。再次,不必担心语法(尽管,如果您想了解更多,请查阅C ++指针)。

    主循环有两种游戏模式:挑战和免费游戏。免费游戏允许玩家无限次地玩游戏。挑战模式使用 showCountdown 方法将计时器设置为20秒。它使用按钮来启动和停止计时器。当前,更改游戏模式的唯一方法是手动编辑名为 mode 的变量。看看是否可以添加另一个按钮来执行此操作并适当地修改代码。

    buzz 方法将播放提供给它的注释。与唱歌结合使用。唱歌方法会遍历每个音符并进行演奏。定期调用此方法,尽管仅在自上次演奏以来经过了足够的时间后才会演奏下一个音符。歌曲到达末尾后,会将歌曲重置为1节( songState = 14 )。您可以将其设置为零以从头开始播放歌曲,但是这样做的原因是跳过介绍。简介在Arduino通电后播放一次,然后不再播放。

    showFree showPlay 方法只需将单词“ FrEE"和“ PLAY"写入显示屏。注意,当所有其他字符均为大写时,free中的“ r"如何变为小写。这是七段显示器的局限之一。它们不能显示字母的每个字母,并且它们可以显示的某些字符必须是大小写混合的。

    toggleFreePlay 方法将闪烁在“ FREE"和“ PLAY"之间显示。再次,它以非阻塞方式进行此操作。

    另一个有用的方法是 showNumber 。这样会在显示屏的中间两个字符中写入一个数字,如下所示:

    该显示屏不够智能,无法知道如何显示大数字,必须明确告知该怎么做。此方法使用一些简单的逻辑在每个字符上显示适当的数字。

    最后使用的方法称为 showCountdown 。这将在20处开始计数,并每秒减少1。如果该值达到零,它会嗡嗡响三声,表明时间已到。

    以下是所有代码的总和:

    #include <TM1637.h> // include display library#include <pitches.h> // include pitchesTM1637 *_display = new TM1637(12, 13); // create display object, 12 = CLK (clock), 13 = D10 (data)// musicint songState = 0;int melody[] = { NOTE_F4, NOTE_E4, NOTE_D4, NOTE_CS4, NOTE_C4, NOTE_B3, NOTE_AS3, NOTE_A3, NOTE_G3, NOTE_A3, NOTE_AS3, NOTE_A3,  NOTE_G3, NOTE_C4, 0,   NOTE_C4, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_A3, NOTE_F4, NOTE_C4,  NOTE_C4, NOTE_A3, NOTE_AS3, NOTE_AS3,  NOTE_AS3, NOTE_C4, NOTE_D4, 0,   NOTE_AS3, NOTE_G3, NOTE_G3, NOTE_G3, NOTE_FS3, NOTE_G3, NOTE_E4, NOTE_D4,  NOTE_D4, NOTE_AS3, NOTE_A3, NOTE_A3,  NOTE_A3, NOTE_AS3, NOTE_C4, 0,  NOTE_C4, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_A3, NOTE_A4, NOTE_F4,  NOTE_F4, NOTE_C4, NOTE_B3, NOTE_G4,  NOTE_G4, NOTE_G4, NOTE_G4, 0,  NOTE_G4, NOTE_E4, NOTE_G4, NOTE_G4, NOTE_FS4, NOTE_G4, NOTE_D4, NOTE_G4,  NOTE_G4, NOTE_FS4, NOTE_G4, NOTE_C4,  NOTE_B3, NOTE_C4, NOTE_B3, NOTE_C4, 0};int tempo[] = { 8, 16, 8, 16, 8, 16, 8, 16, 16, 16, 16, 8, 16, 8, 3,  12, 16, 16, 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 16, 4, 12,  12, 16, 16, 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 16, 4, 12,  12, 16, 16, 16, 8, 16, 8, 16, 8, 16, 8, 16, 8, 16, 4, 16,  12, 17, 17, 17, 8, 12, 17, 17,  17, 8, 16, 8, 16, 8, 16, 8, 1 };// non blocking setup// free playunsigned long previousMillis1 = 0; // time words last changedconst long interval1 = 1500; // interval between changing// musicunsigned long previousMillis2 = 0; // time last changedconst long interval2 = 100; // interval between notesint displayStatus = 0; // keep track of what's displayedint mode = 0; // keep track of game mode -- change to 0 or 1 for different modesbool countdown = false;unsigned long previousMillis3 = 0; // time last changedconst long interval3 = 1000; // interval between countdownint count = 20; // challenge mode timervoid setup() {  // put your setup code here, to run once: pinMode(9, INPUT); // setup circuit pinMode(10, OUTPUT); // setup buzzer 1 pinMode(11, OUTPUT); // setup buzzer 2 pinMode(2, INPUT); // setup button  _display->set(5); // set brightness _display->point(false); // remove colon _display->init(); // start display}void loop() { // put your main code here, to run repeatedly: if(mode == 0) { // challenge mode if(digitalRead(2) == HIGH) { delay(25); if(digitalRead(2) == HIGH) { countdown = true; // stop the countdown } else { countdown = false; // stop the countdown } } if(countdown) { showCountdown(); // advance countdown } } else { // free play toggleFreePlay();  } if(digitalRead(10) == HIGH) { delay(25); if(digitalRead(10) == HIGH) { while(digitalRead(10) == HIGH) { buzz(11, NOTE_B0, 1000/24); } } } else sing();}void showCountdown() { // countdown the time remaining unsigned long currentMillis = millis(); // current time if (currentMillis - previousMillis3 >= interval3) { previousMillis3 = currentMillis; --count; showNumber(count); if(count == 0) { // game over countdown = false; count = 20; // reset countdown // buzz 3 times buzz(11, NOTE_B0, 1000/24);  delay(100); buzz(11, NOTE_B0, 1000/24); delay(100); buzz(11, NOTE_B0, 1000/24); } }}void showNumber(int number) { // show numbers (maximum 99) on display _display->display(0, 25); // write - to segment 1 _display->display(3, 25); // write - to segment 4  // write number to middle of display	if(number == 10)	{		 _display->display(1,1);	 _display->display(2,0);	}	else if(number > 9)	{	 _display->display(1,1);	 int newVal = number - 10;	 _display->display(2, newVal);	}	else	{		 _display->display(1,0);	 _display->display(2,number);	}}void toggleFreePlay() { // scroll between words without blocking unsigned long currentMillis = millis(); // current time if (currentMillis - previousMillis1 >= interval1) { previousMillis1 = currentMillis; if(displayStatus == 1)  showPlay(); else showFree(); }}void showPlay() { // write "PLAY" to the display _display->display(0, 21); // write P to segment 1 _display->display(1, 18); // write L to segment 2 _display->display(2, 10); // write A to segment 3 _display->display(3, 4); // write Y to segment 4 displayStatus = 2;}void showFree() { // write "Free" to the display _display->display(0, 15); // write F to segment 1 _display->display(1, 23); // write r to segment 2 _display->display(2, 14); // write E to segment 3 _display->display(3, 14); // write E to segment 4 displayStatus = 1;}void buzz(int targetPin, long frequency, long length) { /* Buzzer example function by Rob Faludi http://www.faludi.com https://gist.github.com/AnthonyDiGirolamo/1405180  */ long delayValue = 1000000/frequency/2; // calculate the delay value between transitions //// 1 second's worth of microseconds, divided by the frequency, then split in half since //// there are two phases to each cycle long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing //// multiply frequency, which is really cycles per second, by the number of seconds to //// get the total number of cycles to produce for (long i=0; i < numCycles; i++){ // for the calculated length of time... digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphragm delayMicroseconds(delayValue); // wait for the calculated delay value digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphragm delayMicroseconds(delayValue); // wait again for the calculated delay value }}void sing() { // play the song in a non blocking way unsigned long currentMillis = millis(); if (currentMillis - previousMillis2 >= interval2) { previousMillis2 = currentMillis; int noteDuration = 1000 / tempo[songState]; buzz(10, melody[songState], noteDuration); int pauseBetweenNotes = noteDuration; delay(pauseBetweenNotes); // stop the tone playing: buzz(10, 0, noteDuration);  ++songState; // start song again if finished if(songState > 79) { songState = 14; // skip intro  }  }}

    将此文件另存为“ buzzwire"(< strong>“文件">“另存为"),然后将其上传到您的面板(“文件">“上载")。如果您不确定如何上传Arduino,或者该代码看起来有点吓人,请查看我们的《 Arduino入门指南》。一切都很好,您现在应该拥有自己的嗡嗡声有线游戏-很棒!

    如果您在阅读本文后做出了一些很棒的事情,我很乐意看到-在下面的评论中让我知道!

    标签: Arduino 电子技术