基于Arduino自制钢琴实现录音和重放功能

对于那些没有电子知识背景的人来说, Arduino开发板是一个轻松制作小产品的福音。它是一个强大的原型制作工具,并且尝试一些很酷的东西,在本篇文章中我们将使用 Arduino开发板构建一个小而有趣的钢琴。这款钢琴只有8个按钮和一个蜂鸣器。它使用Arduino的tone()函数在 扬声器上创建各种类型的钢琴音符。为了使它更有趣,我们在项目中添加了录制功能,这使我们能够播放曲目并在需要时重复播放。听起来很有趣!!所以让我们一起开始制作……

所需材料:

●     Arduino Uno开发板

●    LCD显示屏1602

●    蜂鸣器

●    电位器10k

●    SPDT开关

●    按钮(8个)

●    电阻

●    面包板

●    连接导线

电路原理图:

完整的 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有一个方便的tone()函数,可用于产生变化的频率信号,可用于使用蜂鸣器产生不同的声音。因此,让我们了解该函数的工作原理以及它如何与 Arduino一起使用。

在此之前,我们应该知道Piezo蜂鸣器的工作原理。我们可能已经在我们学校了解了压电晶体,它只不过是一种将机械振动转化为电能的晶体,反之亦然。在这里,我们应用可变电流(频率),晶体振动,从而产生声音。因此,为了使Piezo蜂鸣器产生一些噪音,我们必须使Piezo电子晶体振动,噪声的音调和音调取决于晶体振动的速度。因此,可以通过改变电流的频率来控制音调和音调。

好的,那么我们如何从 Arduino获得可变频率?这就是tone()函数的用武之地。tone()可以在特定的引脚上产生特定的频率。如果需要,也可以提及持续时间。 tone()的语法是

Syntax
tone(pin, frequency)
tone(pin, frequency, duration)

Parameters
pin: the pin on which to generate the tone
frequency: the frequency of the tone in hertz – unsigned int
duration: the duration of the tone in milliseconds (optional1) – unsigned long

引脚的值可以是您的任何数字引脚。我在这里使用了8号针。可以生成的频率取决于 Arduino板中定时器的大小。对于UNO和大多数其他公共电路板,可产生的最小频率为31Hz,可产生的最大频率为65535Hz。然而,我们人类只能听到2000Hz到5000Hz之间的频率。

 Arduino上演奏钢琴音调:

好吧,在我开始讨论这个主题之前,让我明确表示我是一个有音符或钢琴的新手,所以如果本标题下提到的任何内容都是胡言乱语,请原谅我。

我们现在知道我们可以使用 Arduino中的音调功能来产生一些声音,但是我们如何使用相同的音调播放特定音符的音调。幸运的是,我们有一个名为“pitches.h”的图书馆,由Brett Hagman编写。该库包含有关哪个频率等效于钢琴上的哪个音符的所有信息。我很惊讶这个图书馆实际上能够如何运作并且几乎可以播放钢琴上的每一个音符,我使用同样的方式演奏加勒比海盗,疯狂青蛙,马里奥甚至泰坦尼克号的钢琴音符,它们听起来很棒。哎呀!我们在这里有点偏离主题,所以如果你对使用 Arduino项目播放旋律的感兴趣。您还可以在该项目中找到有关pitches.h库的更多说明。

我们的项目只有8个按钮,因此每个按钮只能播放一个特定的音符,因此我们只能播放8个音符。我在钢琴上选择了最常用的音符,但是你可以选择任何8或甚至用更多按钮扩展项目并添加更多音符。

在此项目中选择的音符是音符C4,D4,E4,F4,G4,A4,B4和C5,它们分别可以使用按钮1至8播放。

编程 Arduino

掌握足够的理论知识后,让我们开始编程 Arduino开发板。在本篇文章的末尾处给出了完整的Arduino程序。

在给出的Arduino程序中,我们必须从引脚A0读取模拟电压,然后预测按下了哪个按钮并播放该按钮的相应音调。在执行此操作时,我们还应记录用户按下了哪个按钮以及他/她按下了多长时间,以便我们可以重新创建用户稍后播放的音调。

在进入逻辑部分之前,我们必须声明我们将播放哪8个音符。然后从pitches.h库中获取音符的相应频率,然后形成如下所示的数组。这里播放音符C4的频率是262,依此类推。

int notes[] = {262, 294, 330, 349, 392, 440, 494, 523}; // Set frequency for C4, D4, E4, F4, G4, A4, B4,

接下来我们要提到LCD显示器连接到哪些引脚。如果您按照上面给出的完全相同的原理图,那么您不必在此处更改任何内容。


const int rs = 8, en = 9, d4 = 10, d5 = 11, d6 = 12, d7 = 13; //Pins to which LCD is connected
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

接下来,在我们的setup函数中,我们只需初始化LCD模块和串行监视器进行调试。我们还会显示一个介绍消息,以确保事情按计划运行。接下来,在主循环函数内部,我们有两个while循环。

只要将SPDT开关置于录音模式,就会执行一次循环。在录音模式下,用户可以听到所需的音调,同时也可以保存正在播放的音调。所以while循环如下所示

 while (digitalRead(6) == 0) //If the toggle switch is set in recording mode
  {
    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读取模拟电压,并将其与某些预定义值进行比较,以找出按下了哪个按钮。可以通过使用上面的分压计算器或使用串行监视器来确定每个按钮读取的模拟值。

void Detect_button()
{
  analogVal = analogRead(A0); //read the analog voltag on pin A0
  pev_button = button; //remember the previous button pressed by the user

  if (analogVal < 550)
    button = 8;

  if (analogVal < 500)
    button = 7;

  if (analogVal < 450)
    button = 6;

  if (analogVal < 400)
    button = 5;

  if (analogVal < 300)
    button = 4;

  if (analogVal < 250)
    button = 3;

  if (analogVal < 150)
    button = 2;

  if (analogVal < 100)
    button = 1;

  if (analogVal > 1000)
    button = 0;
   
/****Rcord the pressed buttons in a array***/
  if (button != pev_button && pev_button != 0)
  {
    recorded_button[button_index] = pev_button;
    button_index++;
    recorded_button[button_index] = 0;
    button_index++;
  }
/**End of Recording program**/
}

如上所述,在此函数中,我们还记录按下按钮的顺序。记录的值存储在名为recorded_button []的数组中。我们首先检查是否按下了一个新按钮,如果按下则我们还检查它是否不是按钮0.其中按钮0只是没有按下按钮。在if循环中,我们将值存储在变量button_index给出的索引位置上,然后我们也增加了这个索引值,这样我们就不会在同一个位置上重写。

/****Rcord the pressed buttons in a array***/
  if (button != pev_button && pev_button != 0)
  {
    recorded_button[button_index] = pev_button;
    button_index++;
    recorded_button[button_index] = 0;
    button_index++;
  }
/**End of Recording program**/

Play_tone()函数内部,我们将使用多个if条件播放按下按钮的相应音调。我们还将使用名为recorded_time []的数组,我们将在其中保存按下按钮的持续时间。该操作类似于记录按钮序列,我们使用millis()函数来确定按下每个按钮的时间,也用于减小变量的大小,我们将值除以10.对于按钮0,这意味着用户不是按任何我们在相同的持续时间内不播放任何音调。函数内的完整代码如下所示。

void Play_tone()
{

/****Rcord the time delay between each button press in a array***/

  if (button != pev_button)
  {
    lcd.clear(); //Then clean it
    note_time = (millis() - start_time) / 10;
    recorded_time[time_index] = note_time;
    time_index++;
    start_time = millis();
  }
  /**End of Recording program**/

  if (button == 0)
  {
    noTone(7);
    lcd.print("0 -> Pause..");
  }

  if (button == 1)
  {
    tone(7, notes[0]);
    lcd.print("1 -> NOTE_C4");
  }

  if (button == 2)
  {
    tone(7, notes[1]);
    lcd.print("2 -> NOTE_D4");
  }

  if (button == 3)
  {
    tone(7, notes[2]);
    lcd.print("3 -> NOTE_E4");
  }

  if (button == 4)
  {
    tone(7, notes[3]);
    lcd.print("4 -> NOTE_F4");
  }

  if (button == 5)
  {
    tone(7, notes[4]);
    lcd.print("5 -> NOTE_G4");
  }

  if (button == 6)
  {
    tone(7, notes[5]);
    lcd.print("6 -> NOTE_A4");
  }

  if (button == 7)
  {
    tone(7, notes[6]);
    lcd.print("7 -> NOTE_B4");
  }

  if (button == 8)
  {
    tone(7, notes[7]);
    lcd.print("8 -> NOTE_C5");
  }
}

最后,在录制之后,用户必须将DPST切换到另一个方向以播放录制的音调。完成此操作后,程序会打断上一个while循环并进入第二个while循环,我们在按下的按钮序列中按下之前记录的持续时间播放音符。以下展示了执行该操作作的代码

while (digitalRead(6) == 1) //If the toggle switch is set in Playing mode
  {
  lcd.clear();
  lcd.setCursor(0, 0);  lcd.print("Now Playing..");

  for (int i = 0; i < sizeof(recorded_button) / 2; i++)
  {
    delay((recorded_time[i]) * 10); //Wait for before paying next tune

    if (recorded_button[i] == 0)
      noTone(7); //user dint touch any button
    else
      tone(7, notes[(recorded_button[i] - 1)]); //play the sound corresponding to the button touched by the user
  }
  }

播放,录制,重播和再次重复! :

按照所示的电路图制作硬件,并将代码上传到 Arduino板及其显示的时间。将SPDT置于录制模式并开始播放您选择的音色,按下每个按钮将产生不同的音调。在此模式下,LCD将显示“Recording …”,在第二行,您将看到当前正在按下的音符的名称,如下所示

一旦你演奏了音调,将SPDT开关切换到另一侧,液晶显示屏应显示“Now Playing……”,然后开始播放刚播放的音调。只要拨动开关保持在如下图所示的位置,就会一次又一次地播放相同的音调。

Similar Posts

Leave a Reply