风筝
发表于: 2018-10-10 14:10:26 | 显示全部楼层

嗨,大家好,在过去几周里,我一直在努力重新拾起对吉他的热爱。弹奏吉他是我几年前在弹奏萨克斯管之前选择放松的方式。回到吉他上,经过3年很少弹奏和弦之后,我发现不再知道每根琴弦应该如何发声,用我朋友的话说,“我的听力不能调音”,因此,如果没有我后来下载的键盘或移动应用程序的帮助,我无法调整吉他。几个星期过去了,直到几天前我变得有动力,决定建立一个基于Arduino的吉他调音器。在今天的文章中,我将分享如何DIY制作自己的Arduino吉他调音器。


吉他调音器如何工作

在我们介绍电子产品之前,了解制作背后的原理非常重要。字母表中有7个主要音符:A、B、C、D、E、F、G。通常以另一个A结束,A总是比第一个A高八度。在音乐中,这些音符的几个版本存在,如第一个A和最后一个A。这些音符通过称为音高的声音特征之一来区分每一个与它们的变化和彼此之间的区别。音高被定义为声音的响度或低度,并且由声音的频率指示。由于这些音符的频率是已知的,为了确定吉他是否被调谐,我们只需要将特定弦乐音符的频率与弦乐所代表的音符的实际频率进行比较。


7个音符的频率是:

A = 27.50Hz

B = 30.87Hz

C = 16.35Hz

D = 18.35Hz

E = 20.60Hz

F = 21.83Hz

G = 24.50Hz


这些音符的每个变化总是等于FxM的音高,其中F是频率,M是非零整数。因此,对于如前所述的最后一个A,比第一个A高八度,频率为;

27.50 x 2 = 55Hz。

吉他通常有六根弦,用开口弦上的音符E、A、D、G、B、E表示。像往常一样,最后一个E将比第一个E高八度。我们将设计我们的吉他调音器,以帮助使用这些音符的频率调整吉他。


根据标准吉他调音,每个琴弦的音符和相应频率如下表所示。

声调
频率
符号
1(E)
329.63赫兹
E4
2(B)
246.94赫兹
B3
3(G)
196.00赫兹
G3
4(D)
146.83赫兹
D3
5(A)
110.00赫兹
A2
6(E)
82.41赫兹
E2

Guitar-Tuners.jpg


项目流程非常简单;我们将吉他产生的声音信号转换为频率,然后与正在调谐的弦的确切频率值进行比较。当值相近时,使用LED通知吉他手。


频率检测/转换涉及3个主要阶段;

1.   放大

2.   电平移动

3.   模数转换(采样)


产生的声音信号太弱,无法让Arduino的ADC识别,因此我们需要放大信号。放大后,为了将信号保持在Arduino ADC可识别的范围内以防止信号削波,我们会抵消信号的电压。在偏移之后,信号然后被传递到Arduino开发板的ADC,在那里对其进行采样并获得该声音的频率。


必需的组件

制作此项目需要以下组件;

●    Arduino Uno开发板

●    LM386运算放大器

●    电容器

●    麦克风/音频插孔

●    10k电位器

●    5mm黄色LED

●    5mm绿色LED

●    常开按钮

●    跳线

●    面包板


原理图

按照下面的吉他调音器电路图所示连接组件。

Arduino-Guitar-Tuner-Circuit-Diagram.png

按钮连接时没有上拉/下拉电阻,因为将使用Arduino内置的上拉电阻。这是为了确保电路尽可能简单。

Arduino-Guitar-Tuner-Circuit.jpg


吉他调音器的Arduino代码

这个吉他调谐器项目代码背后的算法很简单。为了调整特定的弦乐,吉他手通过按下相应的按钮来选择弦乐,并将弹奏弦打开。声音由放大级收集并传递到Arduino ADC。频率被解码和比较。当来自弦的输入频率小于指定频率时,对于该弦,其中一个黄色LED亮起,表示应该收紧弦。当测量的频率大于该串的规定频率时,另一个LED亮起。当频率在该弦的规定范围内时,绿色LED指示灯亮起以引导吉他手。本文末尾处给出了完整的Arduino代码,这里我们简要介绍了代码的重要部分。


我们首先创建一个数组来保存开关引脚。

  1. int buttonarray[] = {13, 12, 11, 10, 9, 8}; // [E2, A2, D3, G3, B3, E4]
复制代码

接下来,我们创建一个数组来保存每个字符串的相应频率。

  1. float freqarray[] = {82.41, 110.00, 146.83, 196.00, 246.94, 329.63};//all in Hz
复制代码

完成此操作后,我们将声明LED所连接的引脚以及用于从ADC获取频率的其他变量。

  1. int lowerLed = 7;
  2. int higherLed = 6;
  3. int justRight = 5;
  4. #define LENGTH 512
  5. byte rawData[LENGTH];
  6. int count;
复制代码

接下来是void setup()函数。

在这里,我们首先启用Arduino的内部上拉,用于连接开关的每个引脚。之后,我们将LED连接的引脚设置为输出,并启动串行监视器以显示数据。

  1. void setup()
  2. {
  3.   for (int i=0; i<=5; i++)
  4.   {
  5.     pinMode(buttonarray[i], INPUT_PULLUP);
  6.   }
  7.   pinMode(lowerLed, OUTPUT);
  8.   pinMode(higherLed, OUTPUT);
  9.   pinMode(justRight, OUTPUT);
  10.   Serial.begin(115200);
  11. }
复制代码

接下来,是void loop()函数,我们实现了频率检测和比较。

  1. void loop(){
  2.   if (count < LENGTH)
  3.   {
  4.     count++;
  5.     rawData[count] = analogRead(A0)>>2;
  6.   }
  7.   else {
  8.     sum = 0;
  9.     pd_state = 0;
  10.     int period = 0;
  11.     for(i=0; i < len; i++)
  12.     {
  13.       // Autocorrelation
  14.       sum_old = sum;
  15.       sum = 0;
  16.       for(k=0; k < len-i; k++) sum += (rawData[k]-128)*(rawData[k+i]-128)/256;
  17.       // Serial.println(sum);
  18.       // Peak Detect State Machine
  19.       if (pd_state == 2 && (sum-sum_old) <=0)
  20.       {
  21.         period = i;
  22.         pd_state = 3;
  23.       }
  24.       if (pd_state == 1 && (sum > thresh) && (sum-sum_old) > 0) pd_state = 2;
  25.       if (!i) {
  26.         thresh = sum * 0.5;
  27.         pd_state = 1;
  28.       }
  29.     }
  30.     // Frequency identified in Hz
  31.     if (thresh >100) {
  32.       freq_per = sample_freq/period;
  33.       Serial.println(freq_per);
  34.       for (int s=0; s<=5; s++)
  35.       {
  36.         if (digitalRead(buttonarray[i])== HIGH)
  37.         {
  38.           if (freq_per - freqarray[i] < 0)
  39.           {
  40.             digitalWrite(lowerLed, HIGH);
  41.           }
  42.           else if(freq_per - freqarray[i] > 10)
  43.           {
  44.             digitalWrite(higherLed, HIGH);
  45.           }
  46.           else
  47.           {
  48.             digitalWrite(justRight, HIGH);
  49.           }
  50.         
  51.         }
  52.       }
  53.     }
  54.     count = 0;
  55.   }
  56. }
复制代码

下面给出完整代码。 将代码上传到您的Arduino开发板,然后随意弹出。


代码

本文使用的完整代码如下所示: main.rar (1002 Bytes, 下载次数: 64)

跳转到指定楼层
你好世界
发表于: 2018-12-31 13:44:41 | 显示全部楼层

请问您是如何实现频率的接收的呢
回复

使用道具 举报

风筝
发表于: 2019-5-20 21:18:06 | 显示全部楼层

你好世界 发表于 2018-12-31 13:44
请问您是如何实现频率的接收的呢

频率由麦克风采集,经过信号放大、电平移动和模数转换,送到Aduino的ADC引脚。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 700 | 回复: 1479



手机版|

GMT+8, 2024-3-28 16:22 , Processed in 0.096831 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表