はじめに
1年越しに動かし始めたArduino。
Lチカの次に挑戦したのは「入力装置(スイッチやセンサ)」の制御です。
前回の「チャルメラ演奏」をさらに進化させ、最終的には光を操って音を奏でる「光テルミン」まで辿り着きました。
1. ボタンを押したらチャルメラ演奏
前回の記事 では、「1秒おきにチャルメラが流れる装置」を作成しました。
Arduinoに書き込んだスケッチ(プログラム)によって演奏タイミングを制御していましたが、今回は物理ボタンである「タクトスイッチ」を追加し、「スイッチを押したらチャルメラが流れる」ように改良します。
スケッチの修正
まずは、前回のスケッチを修正していきます。
「チャルメラ演奏⇒1秒待つ」を繰り返すシンプルな内容でしたが、
「スイッチが押されたかどうか」を判断し、押下時にチャルメラ演奏メソッドを呼び出すようにします。
// 音の高さを定義
#define NOTE_C5 523 // ド
#define NOTE_D5 587 // レ
#define NOTE_E5 659 // ミ
int speakerPin = 8; // スピーカーを繋いだピン番号
int buttonPin = 2; // ボタンを繋いだピン番号
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // ボタンの設定
pinMode(speakerPin, OUTPUT); // ブザーの設定
}
void loop() {
// ボタンの状態を読み取る
// 押されているとLOW(0)、離されているとHIGH(1)となる
int buttonState = digitalRead(buttonPin);
// ボタンが押されたら(LOWになったら)
if(buttonState == LOW){
playCharumera(); // チャルメラを鳴らす
delay(500); // 連続で鳴らないよう少し待つ
}
}
void playCharumera() {
// ドレミーレド
tone(speakerPin, NOTE_C5); delay(200);
tone(speakerPin, NOTE_D5); delay(200);
tone(speakerPin, NOTE_E5); delay(400); // 伸ばす
tone(speakerPin, NOTE_D5); delay(200);
tone(speakerPin, NOTE_C5); delay(300); // 伸ばす
noTone(speakerPin); // 音を止める
delay(200); // 少し間を置く
// ドレミレドレ〜
tone(speakerPin, NOTE_C5); delay(200);
tone(speakerPin, NOTE_D5); delay(200);
tone(speakerPin, NOTE_E5); delay(200);
tone(speakerPin, NOTE_D5); delay(200);
tone(speakerPin, NOTE_C5); delay(200);
tone(speakerPin, NOTE_D5); delay(800); // 最後の余韻
noTone(speakerPin); // 音を止める
}
配線の修正
前回の配線はそのままに、タクトスイッチを追加でブレッドボードに差し込みます。
タクトスイッチの片側をArduinoの2番ピンに、もう片方をGNDに繋ぎます。
起動
成功です。任意のタイミングでチャルメラが流せるようになりました。 これでだいぶ実用的になりました!2. 光を音に変える「光テルミン」
次に挑戦したのが、光センサ(CdSセル)を使った「光テルミン」です。
仕組み
明るさを光センサで 0〜1023 の数値 として読み取り、その値を音の周波数に変換します。
処理のイメージ
- 明るい → 高い音
- 暗い(手をかざす) → 低い音
動作の流れ
- 光センサで明るさを取得(0〜1023)
- 取得した値を周波数にマッピング
- スピーカーから対応する音を出力
スケッチの作成
Geminiを活用して、下記の通りスケッチを作成しました。
// 各音の周波数を定義
#define NOTE_C5 523 // ド
#define NOTE_D5 587 // レ
#define NOTE_E5 659 // ミ
#define NOTE_F5 698 // ファ
#define NOTE_G5 784 // ソ
#define NOTE_A5 880 // ラ
#define NOTE_B5 988 // シ
#define NOTE_C6 1047 // ド(高)
const int sensorPin = A0; // 光センサ
const int speakerPin = 8; // スピーカー
void setup() {
Serial.begin(9600);
}
void loop() {
int val = analogRead(sensorPin);
int toneVal = 0;
// 光量(val)に応じて音を決める
if (val > 900) toneVal = NOTE_C6;
else if (val > 800) toneVal = NOTE_B5;
else if (val > 700) toneVal = NOTE_A5;
else if (val > 600) toneVal = NOTE_G5;
else if (val > 500) toneVal = NOTE_F5;
else if (val > 400) toneVal = NOTE_E5;
else if (val > 300) toneVal = NOTE_D5;
else if (val > 100) toneVal = NOTE_C5;
else toneVal = 0; // 暗すぎると消音
if (toneVal > 0) {
tone(speakerPin, toneVal);
} else {
noTone(speakerPin);
}
delay(100); // 100ミリ秒ごとに更新
}
配線
下記の通り配線しました。
光センサ(CdSセル)をはじめとするアナログセンサを利用する場合、センサ単体の「抵抗値の変化」をマイコンが読める「電圧の変化」に変換する必要があるそうです。そのために、5VピンとGNDの間に抵抗とセンサを直列に繋ぐ 「分圧回路」 を構成しました。
また、入力値の細かな変化(グラデーション)を、0〜1023の連続した数値として正確に捉えるために、Arduinoの アナログ入力ピン(A0〜A5) へと接続しています。これにより、単なるON/OFFではない、滑らかな音の変化を実現できました。
起動
ちゃんと動きました。
思っていたより音程のコントロールが繊細だったため、スケッチでコントロールしている光量の閾値を調整した方が遊びやすいかもなぁ…。
おわりに
今回は入力装置を組み込んだ電子工作を行いました。
入力装置が増えるだけで、かなり実用的なものが作成できるようになったと感じています。
次回以降は、自分の生活が豊かになるようななにかを作れたらいいなぁと考えています。

