AKBONE2020 で音を鳴らそう

(夏休み企画 1/20)

AKBONE2020 は圧電スピーカを搭載していて、音を鳴らすことができます。
今回はこれを利用して音の実験をしましょう。

AKBONE2020 は Arduino 互換機として使うことができますが、以下の実験は一般的な Arduino などでも外部に圧電スピーカを取り付ければ同様に実験ができます。

# AKBONE 2020 と Arduino について


今回の実験では LED と、サウンドデバイスとして圧電スピーカを使います。

|LED | 圧電スピーカ |
|:---:|:---:|
| A1(D15) | LED_BUILTIN(D13)|

AKBONE2020の割当は上のようになっています。

cf., 「はんだ付けトレーニングキット AKBONE2020」
https://qiita.com/nanbuwks/items/8ff1b2c711d58fc6f85a

一般的なArduinoも、A1(D15)ポートに圧電スピーカをつなげることで同様に実験ができます。

# LEDを点滅

まず、LEDに電気を流したり止めたりしてチカチカ点滅させてみましょう。


```cpp

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
```


# LEDと共に圧電スピーカも動かしてみる

以下のようにすると、LEDと同時に圧電スピーカにも電気を流したり止めたりできます。

```cpp

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(D15, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  digitalWrite(D15, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  digitalWrite(D15, LOW);
  delay(1000);
}
```
プチプチ音が出ています。この 1000 を、 50に替えてみましょう。
プチプチが早くなりましたね。
50 ということは、ONにして0.05秒、OFFにして0.05秒ということで0.1秒おきにON/OFF
しているということです。

ここから先は、ON/OFF を1秒間で何回行っているかを表す Hz (ヘルツ)という単位で説明していきましょう。


Hz で今の説明をやり直すと、 1秒間/0.1秒おき = 10回 で、1秒間に10回の波ということです。


# 可聴域にしてみる

プチプチは音で聞こえますが、普通の音にしてみましょう。人間の耳は20Hz
ぐらいから連続した音に聞こえます。

50 を 5 にすると、5+5で10ミリ秒→0.01秒 なので、1秒間/0.01秒おき =100回で 100Hz
となります。

ブーという音が鳴るようになりましたね。

# 音の高さを変える

周波数を変えると、音の高さが変わります。

5 を 1 にすると、1+1で2ミリ秒→0.002秒 なので、1秒間/0.002秒おき =500回で 500Hz
となります。

先程の音に比べて、音が高くなったでしょうか？ 低くなったでしょうか？


# ブーを1秒だけ鳴らす

millis() は、AKBONE2020(Arduino)が起動してからの時間を千分の1秒単位で表します。
音を鳴らしはじめる時間を記録し、今の時間との差が1000になるまでブーという音を鳴らし続けます。

```cpp
void setup() {
//  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(D15, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // 1秒鳴らす
  long starttime = millis();
  starttime = millis();
  while ( 1000 > millis() - starttime ) {
//    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(5);
//    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(5);
  }
  // 1秒空ける
  delay(1000);
}
```

# 音階を鳴らす

では、先のプログラムを変更して、いろんな音の高さを1秒間ずつ鳴らしてみましょう。

```cpp

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(D15, OUTPUT);
}

void loop() {
  // 1秒鳴らす
  long starttime = millis();
  // 100Hz
  starttime = millis();
  while ( 1000 > millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(5);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(5);
  }
  // 125Hz
  starttime = millis();
  while ( 1000 > millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(4);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(4);
  }
  // 167Hz
  starttime = millis();
  while ( 1000 > millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(3);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(3);
  }
  // 250Hz
  starttime = millis();
  while ( 1000 > millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(2);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(2);
  }
  // 500Hz
  starttime = millis();
  while ( 1000 > millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(1);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(1);
  }
  // 1秒空ける
  delay(1000);
}
```
できましたか？ でも、なんだか、調子ハズレですね！


# ちゃんとドレミファソを鳴らす

今までの実験では次のようになりました。

|Delay|ミリ秒|Hz||
|:---:|:---:|:---:|:---:|
|50|100|10|プチプチ音|
|5|10|100|ブー|
|4|8|125|ビー|
|3|6|167|ポー|
|2|4|250|ピー|
|1|2|500|パー|

なんだか、全然ドレミに聞こえないですね。
それに、これ以上delay で数字を小さくするのは無理があります。

ちゃんとドレミに聞こえるようにするには以下のような周波数に合わせる必要があります。




|||周波数|ミリ秒|ミリ秒の半分|マイクロ秒の半分|
|:---:|:---:|:---:|:---:|:---:|:---:|
|	ド	|C4|	261.626	|	3.82	|	1.91	|	1911	|
|	レ	|D4|	293.665	|	3.40	|	1.70	|	1702	|
|	ミ	|E4|	329.628	|	3.03	|	1.51	|	1516	|
|	ファ	|F4|	349.228	|	2.86	|	1.43	|	1431	|
|	ソ	|G4|	391.995	|	2.55	|	1.27	|	1275	|
|	ラ	|A5|	440	|	2.27	|	1.13	|	1136	|
|	シ	|B5|	493.883	|	2.02	|	1.01	|	1012	|
|	ド	|C5|	523.251	|	1.91	|	0.95	|	955.5	|


では、 delaymicroseconds を使ってみましょう。
delay では千分の1秒単位でしか指定できないので、 1.91 ミリ秒という指定はできなかったのですが、
delaymicroseconds だと  100万分の1秒単位で指定できるので、delaymicroseconds(191) とすると「ド」が出るようになります。

```cpp

  // 261Hzできない！
  if ( 1000 < millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delay(2);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delay(2);
  }
```
↓

```cpp

  // 261Hzできた！
  if ( 1000 < millis() - starttime ) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(D15, HIGH);
    delaymicroseonds(191);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(D15, LOW);
    delaymicroseconds(191);
  }
```

先のプログラムを書き換えて「ドレミファソ」となるようにしてみましょう。