Arduino对于那些不具备电子学背景的人来说,轻松构建东西是一个福音。它曾经是一个很棒的原型制作工具,或者尝试一些很棒的东西,在这个项目中,我们将使用Arduino来构建一个小型而有趣的钢琴。这架钢琴只有8个按钮和蜂鸣器,非常普通。它使用Arduino的 tone() 函数在扬声器上创建各种类型的钢琴音符。为了给它增添些许趣味,我们在项目中添加了录音功能,这使我们可以播放音乐并在需要时重复播放。听起来很有趣吧!因此,让我们开始构建…。
所需材料:
- Arduino Uno
- 16 * 2 LCD显示屏
- 蜂鸣器
- 微调10k
- SPDT开关
- 按钮(8个)
- 电阻器(10k,560R,1.5k,2.6k,3.9,5.6k,6.8k,8.2k,10k)
- 面包板
- 连接线
电路原理图:
完整的Arduino钢琴项目可以建立在带有一些连接线的面包板上。下图显示了使用fritzing制作的电路图,该电路图显示了项目的试验板视图
只需按照电路图并相应地连接电线,与PCB模块一起使用的按钮和蜂鸣器即可,但在实际硬件中,我们仅使用了开关和蜂鸣器,它不会让您感到困惑,因为它们的引脚类型相同。您也可以参考下面的硬件图像进行连接。
左起的电阻值按以下顺序排列:10k,560R,1.5k,2.6k,3.9、5.6k,6.8k,8.2k和10k。如果没有相同的DPST开关,则可以使用普通的拨动开关,如上面的电路图所示。现在,让我们看一下项目的示意图,以了解为什么建立以下连接。
原理图和说明:
下面给出了上面显示的电路图的原理图,它也是使用Fritzing制作的。
我们必须了解的一个主要连接是如何通过模拟A0引脚将8个按钮连接到Arduino。基本上,我们需要8个输入引脚,可以将其连接到8个输入按钮,但是对于这样的项目,我们不能仅将微控制器的8个引脚用于按钮,因为我们以后可能需要它们。在我们的案例中,我们需要连接LCD显示器。
因此,我们使用Arduino的模拟引脚并形成一个电阻值可变的分压器以完成电路。这样,当每个按钮被按下时,将向模拟引脚提供不同的模拟电压。仅显示两个电阻和两个按钮的示例电路如下所示。
在这种情况下,当不按下按钮时,ADC引脚将接收+ 5V电压;如果按下第一个按钮,则分压器通过560R电阻器完成;如果按下第二个按钮,则分压器使用1.5竞争。 k电阻。这样,ADC引脚接收的电压将根据分压器的公式而变化。如果您想进一步了解分压器的工作原理以及如何计算ADC引脚接收到的电压值,则可以使用此分压器计算器页面。
除此之外,所有的连接都是直截了当的,LCD连接到引脚8、9、10、11和12。蜂鸣器连接到引脚7,SPDT开关连接到Arduino的引脚6。整个项目通过笔记本电脑的USB端口供电。您也可以通过DC插孔将Arduino连接到9V或12V电源,项目仍将正常运行。
了解
Arduino具有方便的tone()函数,可用于生成变化的频率信号,该信号可通过蜂鸣器产生不同的声音。因此,让我们了解该函数如何工作以及如何与Arduino一起使用。
在此之前,我们应该知道压电蜂鸣器的工作原理。我们可能在学校里学到了压电晶体,无非就是将机械振动转换成电或反之亦然的晶体。在这里,我们施加一个可变电流(频率),使晶体振动,从而产生声音。因此,为了使压电蜂鸣器产生一些噪声,我们必须使压电晶体振动,噪声的音调和音调取决于晶体振动的速度。因此,可以通过改变电流的频率来控制音调和音调。
好的,我们如何从Arduino获得可变频率?这是音频()函数的作用所在。音频()可以在特定的引脚上生成特定的频率。如果需要,还可以提及持续时间。tone()的语法是
语法tone(引脚,频率)tone(引脚,频率,持续时间)参数pin:在其上生成音频的引脚频率:以赫兹为单位的音频频率–无符号int持续时间:以毫秒为单位的音频持续时间(可选1) –无符号长
引脚的值可以是任何数字引脚。我在这里使用了8号针。可以产生的频率取决于Arduino开发板中计时器的大小。对于UNO和大多数其他通用板,可以产生的最小频率是31Hz,可以产生的最大频率是65535Hz。但是,我们人类只能听到2000Hz至5000 Hz之间的频率。
在Arduino上弹钢琴音:
好的,在我开始这个话题之前,请先明确我是音符或钢琴的新手,因此,如果本标题下提到的任何内容令人讨厌,请原谅我。
现在我们知道可以在Arduino中使用音调功能来产生一些声音,但是如何使用相同的音调来演奏特定音符的音调。对我们来说幸运的是,有一个由Brett Hagman编写的名为“ pitches.h”的库。该库包含有关哪个频率等于钢琴上的音符的所有信息。我很惊讶这个库实际上能很好地工作并弹奏钢琴上的每个音符,我用它来演奏加勒比海盗,疯狂青蛙,马里奥甚至泰坦尼克号的钢琴音符,它们听起来很棒。糟糕!我们在这里没有话题,所以如果您对使用Arduino项目演奏旋律感兴趣的话。您还将在该项目中找到有关 pitches.h 库的更多说明。
我们的项目只有8个按钮,因此每个按钮只能演奏一个特定的音符,因此我们总共只能演奏8个音符。我选择了钢琴上最常用的音符,但是可以选择任意8个音符,甚至可以用更多按钮扩展项目并添加更多音符。
在该项目中选择的音符是音符C4,D4,E4,F4,G4,A4,B4和C5,可以分别使用按钮1至8进行演奏。
编程Arduino:
足够的理论知识让我们开始进行Arduino编程的有趣部分。在完整的Arduino计划在本页面末尾给出,如果你渴望你能跳了下去或者进一步阅读,以了解如何代码工作。
在我们的Arduino程序中,我们必须从引脚A0读取模拟电压,然后预测按下了哪个按钮并播放该按钮的相应音调。在执行此操作时,我们还应该记录用户按下了哪个按钮以及他/她按下了多长时间,以便我们可以稍后重新创建用户播放的音调。
在进行逻辑部分之前,我们必须声明要演奏的8个音符。然后从 pitchs.h 库中获取音符的相应频率,然后形成一个数组,如下所示。在这里,演奏音符C4的频率为262,依此类推。
内部注释= {262,294,330,349,392,440,494,523}; //设置C4,D4,E4,F4,G4,A4,B4,
接下来,我们必须提到LCD显示器连接到哪个引脚。如果您遵循上面给出的完全相同的原理图,则无需在此处进行任何更改。
const int rs = 8,en = 9,d4 = 10,d5 = 11,d6 = 12,d7 = 13;// LCD连接到 LiquidCrystal LCD的引脚(rs,en,d4,d5,d6,d7);
接下来,在 设置 功能中,我们仅初始化LCD模块和串行监视器以进行调试。我们还会显示介绍性消息,以确保一切按计划进行。接下来,在 主 循环函数中,我们有两个while循环。
只要将 SPDT开关置于更多录音位置,就会执行一会循环。在录制模式下,用户可以支付所需的音调,同时还将保存正在播放的音调。所以while循环如下所示
while(digitalRead(6)== 0)//如果拨动开关设置为录制模式{lcd.setCursor(0,0); lcd.print(“ Recording..”); lcd.setCursor(0,1); Detect_button(); Play_tone(); }
您可能已经注意到,while循环中有两个函数。第一个功能 Detect_button() 用于查找用户按下了哪个按钮,第二个功能 Play_tone() 用于播放相应的音调。 除此 功能外, Detect_button() 函数还记录按下哪个按钮,而 Play_tone() 函数则记录按下按钮的时间。
在 Detect_button() 函数内部,我们从引脚A0读取模拟电压,并将其与一些预定义值进行比较,以找出按下了哪个按钮。该值可以通过使用上面的分压器计算器或使用串行监视器来检查每个按钮读取的模拟值来确定。
无效Detect_button() { AnalogVal = AnalogRead(A0); //读取A0引脚上的模拟电压标签 pev_button = button; // 如果(analogVal <550) button = 8; 请记住用户按下的上一个按钮;如果(analogVal <500) 按钮= 7; 如果(analogVal <450) 按钮= 6; 如果(analogVal <400) 按钮= 5; 如果(analogVal <300) 按钮= 4; 如果(analogVal <250) 按钮= 3; 如果(analogVal <150) 按钮= 2; 如果(analogVal <100) 按钮= 1; 如果(analogVal> 1000) 按钮= 0; / ****记录数组中的按下按钮*** / if(button!= pev_button && pev_button!= 0) { 录制的 按钮= pev_button; button_index ++; record_button = 0; button_index ++; } / **录制程序结束** / }
如前所述,在此功能内,我们还记录了按下按钮的顺序。记录的值存储在名为 recorded_button 的数组中 。 我们首先检查是否有一个新的按钮被按下,如果被按下,我们还将检查它是否不是按钮0。其中按钮0什么都不是,但是没有按钮被按下。在if循环内,我们将值存储在变量button_index给定的索引位置上,然后还增加该索引值,以免在同一位置上过度写入。
/ ****记录数组*** /中的按下按钮,如果(button!= pev_button && pev_button!= 0){ recorded_button = pev_button; button_index ++; record_button = 0; button_index ++; } / **录制程序结束** /
在 Play_tone() 函数内部,我们将通过使用多个 if 条件来为按下的按钮播放相应的声音。同样,我们将使用一个名为 recorded_time 的数组,其中将保存按下按钮的持续时间。该操作类似于记录按钮序列,方法是使用 millis() 函数确定每个按钮被按下的时间,此外,为了减小变量的大小,我们将该值除以10。对于按钮0,这意味着用户不是按下任何东西我们在相同的时间内都不会发出音调。函数内部的完整代码如下所示。
void Play_tone() { / ****记录数组中每个按钮按下之间的时间延迟*** / if(button!= pev_button) { lcd.clear(); //然后清理它 note_time =(millis()-start_time)/ 10; record_time = note_time; time_index ++; start_time = millis(); } / **录制程序结束** // (按钮== 0) { noTone(7); lcd.print(“ 0-> Pause..”); } if(button == 1) { tone(7,notes); lcd.print(“ 1-> NOTE_C4”); } if(button == 2) { tone(7,notes); lcd.print(“ 2-> NOTE_D4”); } if(button == 3) { 语气(7,笔记); lcd.print(“ 3-> NOTE_E4”); } if(button == 4) { tone(7,notes); lcd.print(“ 4-> NOTE_F4”); } if(button == 5) { tone(7,notes); lcd.print(“ 5-> NOTE_G4”); } if(button == 6) { tone(7,notes); lcd.print(“ 6-> NOTE_A4”); } if(button == 7) { tone(7,notes); lcd.print(“ 7-> NOTE_B4”); } if(button == 8) { tone(7,notes); lcd.print(“ 8-> NOTE_C5”); } }
最后,在录制之后,用户必须将DPST切换到另一个方向才能播放录制的音调。完成此操作后,程序会跳出上一个 while 循环,并进入第二个while循环,在该循环中,我们按按钮的顺序播放音符,持续时间为先前记录的时间。执行以下操作的代码如下所示。
while(digitalRead(6)== 1)//如果切换开关设置为播放模式 { lcd.clear(); lcd.setCursor(0,0); lcd.print(“正在播放..”); for(int i = 0; i <sizeof(recorded_button)/ 2; i ++) { delay((recorded_time)* 10); // 如果(recorded_button == 0) noTone(7); 等待下一次收音 //用户轻触其他任何按钮, tone(7,notes-1)]); //播放与用户触摸的按钮相对应的声音 } } }
播放,录制,重播和重复!:
按照所示的电路图制作硬件,然后将代码上传到Arduino板及其显示的时间。将SPDT置于录音模式并开始播放您选择的音调,按每个按钮将产生不同的音调。在此模式下,液晶显示屏将显示“ Recording…” ,在第二行中,您将看到当前按下的音符名称,如下所示
弹奏完音后,将SPDT开关拨到另一侧,液晶显示屏应显示“ Now Play..” ,然后开始播放刚播放的音调。只要将拨动开关保持在下图所示的位置,就会反复播放相同的音调。
该项目的完整工作可以在下面的视频中找到。希望您理解该项目并喜欢构建它。如果您在构建此文档时遇到任何问题,请在评论部分中发布它们,或使用论坛获取有关您项目的技术帮助。另外,请不要忘记查看下面的演示视频。