UIAPduinoを使って、音を鳴らしながら遊べる「連打ゲーム」を作ってみましょう。

ボタンを使った入力、LEDの点灯、ブザーの音を組み合わせて、5秒間でどれだけ連打できるかを競うゲームを作ります。

時間の計測、カウント処理など、ゲームづくりに欠かせない基本をマスターしよう!


サンプルのINOファイルをダウンロード

動画で解説もしているので
こちらも参考にしてみてください

UIAPduino_renda

ブザーで音を鳴らしてみよう

圧電ブザーやパッシブブザーは、「電気を流すと少しだけ形が変わる材料」を使った部品です。
この“形が変わる動き”がとても小さい振動になり、それが空気をふるわせて音になります。

圧電ブザー(電子工作ステーション ¥49)

sc8_600


パッシブブザー(電子工作ステーション ¥42)
sc8_599


UIAPduinoにブザーをつないでみましょう。

  • 6番ピン
  • GND

に接続します。

image2


ピン配置図を見てみよう

電子工作をするときは、このピン配置図がとっても大事なので
ちょっとずつ読めるようになっていきましょう!

まずは、UIAPduino公式サイトのピン配置図を見てみましょう。

UIAPduinoにはたくさんのピンがありますが、それぞれに役割があります。

UIAPduino-Pro-Micro-CH32V003-V1dot4-Pinout-Diagram (1)

今回のようにブザーで音を鳴らす場合は、「PWM」の波線マークが書かれたピンをさがします。

PWMピンは、信号を高速でON/OFFさせることができるため、音を鳴らすのに向いています。

波線マークがついている6番ピンを使います。


プログラムを書こう

以下のようにプログラムします。(赤字が追加した部分です)

■ サンプルコード
#define LED 2
#define BUTTON 3
#define BUZZER 6

bool ledState = false;
int lastButton = HIGH;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  startSound();
}

void loop() {
  int nowButton = digitalRead(BUTTON); // 今の状態を読む

  // 「押された瞬間」を見つける(HIGH → LOW)
  if (lastButton == HIGH && nowButton == LOW) {
    ledState = !ledState; // ON/OFFを反転
    delay(50); // チャタリングを防ぐ
  }

  digitalWrite(LED, ledState);

  lastButton = nowButton; // 状態を保存
}

void startSound() {
  tone(BUZZER, 1000, 200);
  delay(500);

  tone(BUZZER, 1000, 200);
  delay(500);

  tone(BUZZER, 1500, 400);
  delay(500);
}

関数でまとめよう

処理をまとめておきたいときに、関数を使います。

ここでは startSound() という関数を作って、音を鳴らすプログラムをまとめました。

setup()の中で呼び出すことで、スタート時に音を鳴らすことができます。

💡 ワンポイント

関数は「処理をまとめた部品」のようなものです。

何度も使う処理や、ひとまとまりにしたい処理を分けて書くことで、プログラムが見やすくなります。


音を鳴らす tone()

tone()は、ピンをとても速くON/OFFさせて、その振動で音を作っています。

この速さを「周波数(Hz)」といい、数値を変えると音の高さが変わります。

tone(ピン番号, 周波数, 音の長さ)

指定された周波数の信号をピンから出して、音を鳴らします。

音の長さを指定しない場合は、ずっと鳴り続けます(noTone()で止めます)


音階を変えてみよう

ドレミの音にも、それぞれ決まった周波数があります。(音階周波数の一覧

  • 523Hz → ド
  • 587Hz → レ
  • 659Hz → ミ
  • 698Hz → ファ
  • 783Hz → ソ
  • 880Hz → ラ
  • 987Hz → シ
  • 1046Hz → ド

「1000」の部分を変えると、好きな音を鳴らすことができます。


動作確認

マイコンに書き込んで、音が鳴るか試してみましょう。

うまくいったら、自分の好きな曲を鳴らしてみるのもおすすめです。



連打ゲームにアレンジしよう

スタートの音が鳴ったあと、連打ゲームが始まるようにしてみましょう。

5秒間で何回ボタンを連打できたかをチェックします。

そのために、押した回数を数えるカウンターや、スタート時刻を保存します。


準備(変数の追加)

■ サンプルコード
#define LED 2
#define BUTTON 3
#define BUZZER 6

bool ledState = false;   // LEDの状態(ON/OFF)
int lastButton = HIGH;   // 1回前のボタンの状態
int count = 0;           // 連打カウンター
unsigned long startTime; // 時間を保存

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  startSound();          // スタート音
  startTime = millis();  // 開始時間を保存
}

時間を扱う変数

startTime には、少し大きな数を扱える型が使われています。
unsigned long(アンサインドロング)型は、「符号なしlong整数型」です。

簡単にいうと、マイナスを数えられないかわりに、プラスの値をたくさん保存しておける変数です。

  • int型 → 約3万まで(-32,768 ~ 32,767)
  • long型 → 約20億まで(-2,147,483,648 ~ 2,147,483,647)
  • unsigned long型 → 約42億まで(0 ~ 4,294,967,295)

今回は時間(ミリ秒)を扱うため、たくさん数えられる unsigned long を使います。

💡 ワンポイント

millis() を使うと、マイコンが起動してからの時間(ミリ秒)を取得できます。

1秒 = 1000ミリ秒なので、時間を計るときに便利です。


連打ゲームの処理


つぎに、loop()の中に、連打ゲームのプログラムを書きましょう。
■ サンプルコード
void loop() {
  if (millis() - startTime < 5000) {      // 5秒以内なら
    int nowButton = digitalRead(BUTTON);

    if (lastButton == HIGH && nowButton == LOW) {
      count++;    // カウントアップ
      delay(50);  // チャタリング防止
    }

    lastButton = nowButton;
  }
  else {
    resultSound(count); // 結果発表
    while (true);       // 終了
  }
}

時間のはかり方

次の式で、どれくらい時間が経ったかを調べています。

millis() - startTime

スタート時の時間を引くことで、「経過時間」を計算できます。

この値が5000(=5秒)より小さい間だけ、ゲームを続けます。

⏱ ワンポイント

delay() を使わずに時間を測れるのが millis() のポイントです。

プログラムを止めずに時間を管理できるので、ゲームなどに向いています。


カウントの仕組み

トグルボタンの仕組みと同じように、「押した瞬間」だけをカウントしています。

  • HIGH → LOW の変化で検出
  • 押しっぱなしでは増えない

ゲーム終了

5秒が経過したらゲーム終了です。

resultSound(count); を呼び出して、結果を音で発表します。

その後、while (true); で処理を止めています。

⚡ ワンポイント

while (true); は、その場所でずっと止まる命令です。

これ以上プログラムを進めないことで、ゲームを終了させています。


結果発表のプログラムをしよう

さいごに、音とランプで連打回数を知らせる関数を作りましょう。

■ サンプルコード
// 結果発表:連打した数だけLEDとブザーでカウント
void resultSound(int c) {
  for (int i = 0; i < c; i++) {

    digitalWrite(LED, HIGH);
    tone(BUZZER, 1200);
    delay(80);

    digitalWrite(LED, LOW);
    noTone(BUZZER);
    delay(80);
  }
}

引数ってなに?

void resultSound(int c)int c の部分を「引数」といいます。

引数とは、関数を呼び出すときに値を受け渡しするための変数です。

たとえば resultSound(5) のように呼び出すと、関数の中では c = 5 として処理されます。

💡 ワンポイント

引数を使うと、「同じ処理を、違う値で使い回す」ことができます。

今回は、連打回数に応じて音とLEDの回数を変えています。


UIAPduinoに書き込んでみよう


UIAPduinoのリセットボタンを押しながらケーブルを差し込み
プログラムを書き込んでみましょう。

もう一度リセットボタンを押すと、スタート音のあとにゲームがはじまります。
ボタンを連打してみましょう。


5秒後、連打した回数だけ、LEDが光って音が鳴ります。

  • 5回 → 5回ピカピカ+ピッピッ
  • 10回 → 10回ピカピカ+ピッピッ

ちょっとアレンジ(音を変えてみよう)

同じ音だけだと回数が分かりづらいので、「ドレミファソラシド」を繰り返すようにしてみましょう。

■ サンプルコード(アレンジ)
// 結果発表:連打した数だけLEDとブザーでカウント
void resultSound(int c) {

  int scale[] = {523, 587, 659, 698, 783, 880, 987, 1046};
  int index = 0;
  int size = sizeof(scale) / sizeof(scale[0]);

  for (int i = 0; i < c; i++) {

    digitalWrite(LED, HIGH);
    tone(BUZZER, scale[index]);
    delay(80);

    digitalWrite(LED, LOW);
    noTone(BUZZER);
    delay(80);

    index = (index + 1) % size;
  }
}

配列を使おう

配列に音階のヘルツ数を入れておくことで、順番に音を取り出すことができます。

index を使って、配列の中の音を1つずつ選んでいます。

🎵 ワンポイント

index = (index + 1) % size; とすることで、最後までいったら最初に戻ります。

これによって、ドレミファソラシドを繰り返すことができます。


これで、連打ゲームの完成です!
ぜひ記録更新にチャレンジしてみましょう。