在这个有趣的项目中,我们将学习如何使用Arduino制作嗡嗡声有线游戏。您可以在入门工具包(入门工具包中有什么?)和房屋周围找到许多所需的零件。该项目使用Arduino,尽管您几乎可以使用周围的任何微控制器(以下是5美元的微控制器之间的比较,以获取一些启发)。
查看最终结果-它甚至可以播放音乐:
您需要什么
以下是完成此项目所需的核心部分:
1 x Arduino UNO或类似产品。
1 x金属衣架。
2 x 220欧姆电阻。
1 x面包板。
1 x压电蜂鸣器。
2 x鳄鱼夹。
各种热缩管。
公对公连接线。
以下是一些可选部件增强构造:
1 x附加压电蜂鸣器。
1 x定位杆。
1 x四个七段式显示器。
1 x 220欧姆电阻。
1 x瞬时按钮。
公对母连接线。
木板(用于保护箱)。
各种木螺钉。
只要有足够的引脚,几乎所有的Arduino都可以使用。如果不确定您的需求,请查看此购买指南。
构建计划
虽然这可能看起来很复杂,这实际上是一个非常简单的项目。我将从基本游戏开始,然后添加其他组件以增加复杂性。您可以根据自己的需要选择“选择”。
核心机制由线形和手柄上的环组成。玩家必须引导整个路线的循环,而不能使两个方向接触。如果两者接触,则电路完成,并且蜂鸣器响起。当然也可以不使用微控制器来构建该电路,但是这样做的乐趣何在(以及还能听到Monty Python的“ Flying Circus”主题曲)?
课程 strong》
这是玩家指导自己的回合的形状。这是整个游戏的基础,所以做得好!我选择先降一小点,然后再进行一次大的爬升。将金属衣架弯曲成所需的形状。黄铜线或铜管也可以正常工作,尽管衣架可能是最便宜的。
您可能需要戴手套,用钳子或锤子才能使事情变得完美。用断线钳剪掉多余的部分。留下两个垂直的立柱以推入基座。为了安全起见,您想归档切割端。最后,切开两根热缩管,并如下放置在末端:
这将使回路与过程绝缘,从而提供一个起点/末端或安全区域。另外,如果您没有热缩管,也可以用胶带甚至是吸管。
现在将电缆连接到课程的一端。您在这里有两个选择:可以焊接,也可以使用鳄鱼夹。鳄鱼夹是较容易的选择,但焊接是更可靠和长期的选择。确保首先用砂纸“弄粗”衣架表面,并使用大量助焊剂。 (以前从来没有焊接过?请学习这里的方法。)
根据下一步在底座上钻的孔的大小,您可能需要先将电缆穿过安装孔。使用两根绞在一起的电线会提高耐用性:
使用电钻来做这有很大帮助:
基础
是时候创建基础了。这用于将航线保持在直立位置,并提供将电子设备固定到的位置。我使用了一些松木碎片,尽管您可以使用房子周围的任何物品,甚至可以用纸板箱。
将三块切成“ n”形。只需将这三部分拧(或胶)在一起。切记先在侧板上钻一个导向孔,以防止侧板裂开。您可能需要沉头螺钉(特别是如果要填充然后上漆),因此我强烈建议使用沉头钻头。如果您没有沉头工具或钻孔,则可以使用较大直径的钻头。
钻两个孔,其距离应足够远,以便安装过程的末端。 ink孔下面的东西,准备粘贴。
手柄
现在是时候制作回路/控制器了。在一端扭曲一小部分衣架,以形成带有小金属手柄的环。确保锉平切割边缘,然后在必要时用胶带/泡沫覆盖。
这将形成电路的另一半-当此循环接触到当然它将完成电路(就像一个开关)。将另一根线焊接(或使用鳄鱼夹)到其底部,与之前在该过程中所做的完全相同。
为实际手柄切去一小段销钉。该金属环将插入该手柄中。如果没有销钉,则可以使用皮带或圆盘砂光机将一块方形的软木修圆(也可以使用砂纸,但这会花费很长时间)。
钻一个洞这个手柄。它必须足够大以适合金属环和导线穿过:
尽管很棘手,但这可以在立柱钻机上完成。 Alathe可以完美地完成这项工作:
是的,我很清楚这是金属车床(对于感兴趣的人,这是Boley制表车床,来自1930年代。我认为这是3C,但是如果您对此有所了解,我希望能收到您的来信。)
您还可以使用去除中心的圆珠笔。
最后,使用热胶将电缆和回路固定到手柄中。热胶会提供牢固的(但不是永久性的)固定装置,因此非常适合。
完成
将导线束插入底座的孔中。不要忘了先添加回路/控制器。再次使用热熔胶,通过如下方式填充底座底部的沉孔,将路线固定到底座上:
电路 》
这是完整的电路。您不必如此复杂—在分解每个部分时请继续阅读。
首先,将两个压电元件连接到数字引脚10和11极性无关紧要:
您不必使用两个压电体-我这样做的唯一原因是在出现以下情况时会发出更大的嗡嗡声电线接触。将一侧连接到数字引脚,另一侧接地。
现在插入金属层并处理:
同样,它不会无论这两个连接方式如何。电路的这一部分就像按钮或开关一样,当循环触碰到路线时,玩家将完成电路。确保同时包括两个电阻。
一个电阻将电路接地(称为下拉电阻),以确保其不会“浮空”(这使Arduino能够检测到电路的变化)。另一个电阻器保护Arduino。当两个部分接触时,+ 5V进入数字引脚。如果不存在此电阻,则可能会出现短路故障–如果幸运的话,您的计算机将断开USB插座的连接,以吸收过多的电流。
连接信号线(紫色,如图所示)连接到数字引脚9。
下一步,将按钮连接到数字引脚2:
最后,连接七段式LED显示屏:
该特殊型号来自Seeed。它使用TM1637驱动四个显示器-这意味着仅需要两个数字引脚。将 GND 连接到Arduino地面,将 VCC 连接到Arduino + 5V。将 D10 连接到Arduino数字引脚13,将 CLK 连接到数字引脚12。
代码
要使该项目正常工作将需要两个附加文件。第一个称为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
为此:
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
#include
现在创建显示对象:
TM1637 *_display = new TM1637(12, 13);
不要担心,如果您不了解语法-此行告诉Arduino,将针脚12和13连接到七段显示器,并进行适当配置。
这首歌存储在melody和tempo。这些包含所有音符和音乐的音符持续时间。如果您想更改音乐,请修改这些数组(尽管它不如粘贴音符值那么简单,定时是音乐中非常重要的一部分)。 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进一步优化代码。
在setup()函数中,有一些事情继续。首先,设置输入和输出。这是必须要做的,因此Arduino知道每个引脚都连接了什么:
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
方法set,point和init全部包含在_display对象中。代替点,使用指针(“-》”)访问它们。再次,不必担心语法(尽管,如果您想了解更多,请查阅C ++指针)。
主循环有两种游戏模式:挑战和免费游戏。免费游戏允许玩家无限次地玩游戏。挑战模式使用showCountdown方法将计时器设置为20秒。它使用按钮来启动和停止计时器。当前,更改游戏模式的唯一方法是手动编辑名为mode的变量。看看是否可以添加另一个按钮来执行此操作并适当地修改代码。
buzz方法将播放为其提供的注释。与sing结合使用。唱歌方法会遍历每个音符并进行演奏。定期调用此方法,尽管仅在自上次演奏以来经过了足够的时间后才会演奏下一个音符。一旦歌曲到达结尾,它将把歌曲重置为1节(songState = 14)。您可以将其设置为零以从头开始播放歌曲,但是这样做的原因是跳过介绍。简介会在Arduino通电后播放一次,然后不再播放。
showFree和showPlay方法只需将单词“ FrEE”和“ PLAY”写入”显示。注意,当所有其他字符均为大写时,free中的“ r”如何变为小写。这是七段显示器的局限之一。它们不能显示字母表中的每个字母,并且它们可以显示的某些字符必须是大小写混合的。
toggleFreePlay方法在“ FREE”和“ PLAY”之间闪烁显示。再次,它以非阻塞方式进行此操作。
另一个有用的方法是showNumber。这样会在显示屏的中间两个字符中写入一个数字,如下所示:
显示屏不够智能,无法知道如何显示大数字,它必须明确告知该怎么做。此方法使用一些简单的逻辑在每个字符上显示适当的数字。
最后使用的方法称为showCountdown。这将在20处开始计数,并每秒减少1。如果该值达到零,它会嗡嗡响三声,表明时间已用完。
所有代码都放在这里:
#include // include display library
#include // include pitches
TM1637 *_display = new TM1637(12, 13); // create display object, 12 = CLK (clock), 13 = D10 (data)
// music
int 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 play
unsigned long previousMillis1 = 0; // time words last changed
const long interval1 = 1500; // interval between changing
// music
unsigned long previousMillis2 = 0; // time last changed
const long interval2 = 100; // interval between notes
int displayStatus = 0; // keep track of what’s displayed
int mode = 0; // keep track of game mode -- change to 0 or 1 for different modes
bool countdown = false;
unsigned long previousMillis3 = 0; // time last changed
const long interval3 = 1000; // interval between countdown
int count = 20; // challenge mode timer
void 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”(文件》另存为),然后将其上传到您的开发板上(文件》上传)。如果您不确定如何上传Arduino,或者该代码看起来有些吓人,请查看我们的《 Arduino入门指南》。一切都很好,您现在应该拥有自己的嗡嗡声有线游戏-很棒!
责任编辑:wv
-
Arduino
+关注
关注
187文章
6461浏览量
186557
发布评论请先 登录
相关推荐
评论