• Skip to main content
  • Skip to primary sidebar
  • Skip to footer
  • HOME
  • Arduino
    • Arduino初心者編
    • Arduino基礎編
    • Arduino応用編
    • Arduino実践編
  • Raspberry Pi
  • microbit
  • XBee
  • Scratch
  • Contact Us
  • Privacy Policy

STEMSHIP

ものづくりを通して、科学を学ぼう!

現在の場所:ホーム / Arduino / Arduino応用編 / ArduinoでSTEM教育​ 応用編:WAV音源をデータ変換して圧電スピーカから出力する

ArduinoでSTEM教育​ 応用編:WAV音源をデータ変換して圧電スピーカから出力する

2020年1月18日 by STEMSHIP 1 コメント

効果音のような短い音源であれば、SDカードやシールド等を使用しなくても、音源をソースコードに埋め込んで、圧電スピーカから出力することができます。プログラムサイズが容量オーバーしないように、音質を落とす必要がありますが、利用できる機会は多いと思います。

WAV音源を準備する

まずは音源を準備する必要があります。ネットで購入するのが、一番お手軽だと思います。国内サイトだとAudioStock、海外サイトだとAudioJungleがメジャーです。先日、AudioJungleで効果音を2ドルで購入しました。支払いはPayPalで行いました。購入前に音を再生することができますので、色々聴き比べて選ぶことができます。購入したファイルはMP3形式だと思うので、フリーソフト等でWAV形式に変換してください。このあたりの情報は、検索するとたくさん出てきます。

WAV音源からデータ配列に変換する

RAW形式に変換

音声データをArduinoのプログラムに埋め込む必要があるため、多くの場合はステレオからモノラルに変換したり、音質(ビットレート)を落として、データサイズを小さくする必要があります。これは、Audacityというフリーソフトで出来ます。手順は次のとおりです。

  1. AudacityでWAVファイルを開いて、ステレオからモノラルに変換する。
    [トラック] -> [Mix] -> [Mix Stereo down to Mono]
  2. ビットレートを8000Hzにする。
    画面左下の[Project Rate]で8000を選択する。
  3. ファイル形式を指定して出力する。
    [ファイル] -> [Expoprt] -> [選択したオーディオの書き出し] をクリック
    ファイルの種類:その他の非圧縮ファイル
    ヘッダ:RAW(header-less)
    エンコーディング:Unsigned 8-bit PCM

データ配列に変換

作成したRAW形式のファイルをArduinoで取り扱えるデータ配列に変換します。これは、「放課後マイコンクラブ」の「PROGMEM作蔵さん」というHTMLスクリプトを使用すると簡単です。 「PROGMEM作蔵さん」 で変換すると、「 const uint8_t bindata[] PROGMEM = { … };」という形式で出力されます。 他の方法としては、「 xxd -i 」というLinuxコマンドでもできるようですが、Windowsを使用されている方は環境を整えることが難しそうなので、先述の方法をお勧めします。

プログラム

音源ヘッダファイル

先述の方法で出力したデータをヘッダファイル(*.h)で保存します。メインプログラムと分離しておくことで、コードの管理がしやすくなります。PROGMEMはFlashメモリにデータを格納する記述です。プログラムを実行するためのメモリはSRAMですが、容量が2kBしかありません。そこで、比較的容量の大きいFlashメモリ(32kB)に音源を保管します。必要なときに、必要な分だけSRAMに読み込みます。

// file name : OnYourMarks.raw
// file size : 10505 bytes

const uint8_t soundOnYourMarks[] PROGMEM = {
  0x80,0x7f,0x80,0x80,0x7f,0x80,0x7f,0x80,0x80,0x7f,0x7f,0x7f,0x80,0x80,0x7f,0x7f,
  0x80,0x7f,0x80,0x7f,0x80,0x80,0x7f,0x7f,0x7f,0x80,0x80,0x7f,0x7f,0x80,0x80,0x7f,
  
・・・・・・・・・・・・(省略)・・・・・・・・・・・・
  0x7f,0x80,0x80,0x7f,0x80,0x80,0x7f,0x80,0x7f,0x7f,0x80,0x7f,0x80,0x7f,0x7f,0x80,
  0x7f,0x80,0x7f,0x7f,0x80,0x7f,0x80,0x7f,0x80
};

メインプログラム

次にメインのプログラムです。今回は、3つの音源を使用しました。それぞれ冒頭のincludeで読み込みます。圧電スピーカは3番ピン(PWM)で出力します。以下の記述は今まで見たこと無い方が多いと思いますが、これはATmega328Pのデータシートを見ると記載があります。

TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(CS20);

TCCR2A/TCCR2Bは、タイマ/カウンタ2制御レジスタです。「_BV」は、ビットセットで、カッコ内のビットを1にセットします。すなわち、下記のCOM2B1、WGM21、WGM20を1にセットします。

WGM2(波形生成種別)を2’b11にセットすることで、高速PWM動作モードになります。そして、COM2B(比較B出力選択)を2’b10にセットすることで、タイマとOCR2Bとの非反転比較をOC2Bピン(ArduinoのD3ピン)へ出力します。CS2(クロック選択)ビットは、3’b001なので分周無しです。

TCCR2A
TCCR2B

次に、「OCR2B = pgm_read_byte_near(&soundArray[i]);」について説明します。 pgm_read_byte_near は、Flashメモリから1バイトのデータをSRAMに読み出します。引数はアドレスです。ヘッダファイルでPROGMEMで音源をメモリに入れているので、そのアドレスを引き渡します。OCR2B(タイマ/カウンタ2比較B値)は、継続的にTCNT2( タイマ/カウンタ2計数値値)と比較される8ビットの値です。

OCR2B

そして、「delayMicroseconds(125);」についてですが、音源データを作成する際に、8000Hzを選択しました。なので、1秒÷8000=125マイクロ秒のdelayを設けます。

//www.stemship.com
//2020.01.03

#include "On-Your-Marks.h"
#include "Get-Set.h"
#include "Go.h"

const int speakerPin = 3; //PWM

void setup() {
  pinMode(speakerPin, OUTPUT);
  TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS20);
}

void loop() {
    playAudio(soundOnYourMarks, sizeof soundOnYourMarks / sizeof soundOnYourMarks[0]);
    delay(5000);
    playAudio(soundGetSet, sizeof soundGetSet / sizeof soundGetSet[0]);
    delay(3000);
    playAudio(soundGo, sizeof soundGo / sizeof soundGo[0]);
    delay(5000);
}

void playAudio(const uint8_t* soundArray, unsigned int soundArrayLength) {
  for (int i = 0; i < soundArrayLength; i++) {
    OCR2B = pgm_read_byte_near(&soundArray[i]);
    delayMicroseconds(125);
  }
}

回路

スピーカのプラス端子を3番ピンに接続し、マイナス端子をGNDに接続します。

接続図

まとめ

ファイルサイズを小さくするために、音質をかなり落としましたが、意外とまともな音を再生できました。効果音や短い音声であれば、十分使える方法だと思います。ATmega328Pのレジスタ設定について、いろいろ書きましたが、なかなか理解することは難しいと思います。まずは、ソースコードをコピーして、とにかく動く状態を確認し、そこからソースコードを自分で少し変えながら理解を深めていくのが良いと思います。

Filed Under: Arduino応用編 関連タグ:スピーカ, 音楽

Reader Interactions

コメントを残す コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。

最初のサイドバー

CONTACT US

  • Facebook
  • Twitter
  • Youtube

More to See

Arduinoベースのセンサノード:XBeeデータ収集ノードの製作

2021年9月27日 By STEMSHIP

Arduinoベースのセンサノード:Arduinoを使った温度センサの作製

2021年9月21日 By STEMSHIP

XBeeモジュールとBMP280センサを使用してデータ収集する

2021年5月31日 By STEMSHIP

XBeeモジュールでMicroPythonを使ってセンサを読み取る

2021年5月24日 By STEMSHIP

XBeeモジュールでセンサを読み取る:センサノードの設定と測定

2021年5月17日 By STEMSHIP

カテゴリー

  • Arduino (44)
    • Arduino初心者編 (15)
    • Arduino基礎編 (11)
    • Arduino実践編 (4)
    • Arduino応用編 (11)
    • Arduino番外編 (3)
  • MakeyMakey (1)
  • microbit (11)
  • Raspberry Pi (13)
  • Scratch (6)
  • STEM教育 (5)
  • XBee (15)
  • ものづくり教育 (2)
  • 子供の教育 (2)
  • 科学 (6)
  • 算数 (5)

Tags

BLE DCモータ EEPROM ELEGOO ESP32 ESP8266 IoT LCD LED makeymakey MQTT Node-RED scratch STEM教育 WiFi XBee アニメーション オンラインゲーム カメラ クローン ゲーム コスチュームの変更 サーボモータ ステッピングモータ ステートマシン スピーカ タイマー ピンポン ブロック定義 ペン ライントレース ラジコン リスト 分数 割り込み 実験 工作 幼児 当たり判定 温度センサ 無線通信 物理 角度制御 重力 音楽

Footer

最近の投稿

  • Arduinoベースのセンサノード:スケッチ(プログラム)の作製
  • Arduinoベースのセンサノード:XBeeデータ収集ノードの製作
  • Arduinoベースのセンサノード:Arduinoを使った温度センサの作製
  • XBeeモジュールとBMP280センサを使用してデータ収集する
  • XBeeモジュールでMicroPythonを使ってセンサを読み取る

タグ

BLE DCモータ EEPROM ELEGOO ESP32 ESP8266 IoT LCD LED makeymakey MQTT Node-RED scratch STEM教育 WiFi XBee アニメーション オンラインゲーム カメラ クローン ゲーム コスチュームの変更 サーボモータ ステッピングモータ ステートマシン スピーカ タイマー ピンポン ブロック定義 ペン ライントレース ラジコン リスト 分数 割り込み 実験 工作 幼児 当たり判定 温度センサ 無線通信 物理 角度制御 重力 音楽

Search

2023年3月
月 火 水 木 金 土 日
 12345
6789101112
13141516171819
20212223242526
2728293031  
« 10月    

Copyright © 2023 · STEMSHIP.COM