これまで、Arduinoでの音楽再生として
1.TMRpcm ライブラリ
2.DFPlayer mini
3.DACモジュール
など、いろいろ試してきました。今回は、もっとも簡単な方法です。「microSDカード」にデータを入れて置きます。ですから、カード内のテキストファイルを書き直すことにより曲はいくらでも変更できます。
環境/構成です。
1.Windows 11 Pro
2.Arduino IDE 2.3.6
3.FREENOVE ESP32-S3 WROOM Cam ボード(FNK0085)
microSDカードスロット付き(ただし、カメラモジュールは使わない)
4."SD_MMC.h" ライブラリ
5.microSDカード
6.PWMで音を出すための接続。目でもわかるようにLEDを直列に。
PWM_PIN(14) -> 300Ω -> LED -> 小型speaker-> GND
曲を用意します。有名な「きらきら星」のAパートです。周波数と継続時間(単位は500ms)を順にテキストファイルにします。そして、エンコードutf-8
でカードに保存。ファイル名は何でもよいのでtone.txt
としておきます。
523 2
523 2
784 2
784 2
880 2
880 2
784 4
698 2
698 2
659 2
659 2
587 2
587 2
523 4
スケッチの中で次のように読取り、実行させます。
String s, fn = _rt + "tone.txt";
if (SD_MMC.exists(fn)) {
File fp = SD_MMC.open(fn, FILE_READ);
if (fp) {
s = " --- " + fn + " begin ...";
Serial.println(s);
while (fp.available()) { // read from the file until there's nothing else in it
String line = fp.readStringUntil('\n');
line.trim();
Serial.println(line);
l_buffer.push_back(line);
}
fp.close(); // close the file:
s = " --- " + fn + " ends.";
Serial.println(s);
int tone=0;
while(l_buffer[tone]){
String line=l_buffer[tone];
int n = 2; // "freq duration"
String za[n];
int co[n];
bool flag = true;
if (split(line, ' ', za, n) != n) flag = false;
for (int i = 0; i < n; i++) {
if (!(co[i] = za[i].toInt())) {
flag = false;
break;
}
}
if (flag) {
ledcWriteTone(PWM_PIN, co[0]); // freq
delay(co[1] * 500); // duration
ledcWriteTone(PWM_PIN, 0);
}
tone++;
}
} else { // if the file didn't open, print an error
s = " --- " + fn + " open error.";
Serial.println(s);
}
} else {
s = " --- " + fn + " not exists.";
Serial.println(s);
}
スケッチ全体です。標準の「sd_read_write.cpp」「sread_write.h」をスケッチと同じフォルダーにコピーしておいてください。
#include "sd_read_write.h"
#include "SD_MMC.h"
#include <string>
#include <vector>
using namespace std;
// SD_MMC FREENOVE ESP32-S3 WROOM 内蔵SDスロット使用のため
#define SD_MMC_CMD 38 // MISO. Please do not modify it.
#define SD_MMC_CLK 39 // CLK. Please do not modify it.
#define SD_MMC_D0 40 // MOSI. Please do not modify it.
File fp;
const String _rt = "/";
std::vector<String> l_buffer;
const int PWM_PIN = 14;
void setup() {
Serial.begin(115200);
Serial.println("DOS PC Console Start");
SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0);
if (!SD_MMC.begin("/SD", true, true, SDMMC_FREQ_DEFAULT, 5)) {
Serial.println("Card Mount Failed");
return;
}
SD_Info();
ledcAttach(PWM_PIN, 24000, 8); // for tone
String s, fn = _rt + "tone.txt";
if (SD_MMC.exists(fn)) {
File fp = SD_MMC.open(fn, FILE_READ);
if (fp) {
s = " --- " + fn + " begin ...";
Serial.println(s);
while (fp.available()) { // read from the file until there's nothing else in it
String line = fp.readStringUntil('\n');
line.trim();
Serial.println(line);
l_buffer.push_back(line);
}
fp.close(); // close the file:
s = " --- " + fn + " ends.";
Serial.println(s);
int tone=0;
while(l_buffer[tone]){
String line=l_buffer[tone];
int n = 2; // "freq duration"
String za[n];
int co[n];
bool flag = true;
if (split(line, ' ', za, n) != n) flag = false;
for (int i = 0; i < n; i++) {
if (!(co[i] = za[i].toInt())) {
flag = false;
break;
}
}
if (flag) {
ledcWriteTone(PWM_PIN, co[0]); // freq
delay(co[1] * 500); // duration
ledcWriteTone(PWM_PIN, 0);
}
tone++;
}
} else { // if the file didn't open, print an error
s = " --- " + fn + " open error.";
Serial.println(s);
}
} else {
s = " --- " + fn + " not exists.";
Serial.println(s);
}
}
void loop() {
}
int split(String data, char delimiter, String* dst, int num) {
int index = 0;
int len = data.length();
for (int i = 0; i < len; i++) {
char tmp = data.charAt(i);
if (tmp == delimiter) {
index++;
if (index > num - 1) return -1;
} else {
dst[index] += tmp;
}
}
return index + 1;
}
void SD_Info() {
uint8_t cardType = SD_MMC.cardType(); // カード情報
String s = "Card Type: ";
if (cardType == CARD_MMC) s += "MMC";
else if (cardType == CARD_SD) s += "SDSC";
else if (cardType == CARD_SDHC) s += "SDHC";
else s += "UNKNOWN";
Serial.println(s);
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024 * 1024);
s = "Card Size: " + (String)(cardSize) + "GB";
Serial.println(s);
}
10年以上前、STM32VLDiscoveryでもっと面倒なプログラムでやってました。それの簡易版が作れました。利用される場合は、microSDカードが壊れるかもしれませんので、自己責任で。最後まで見ていただきありがとうございました。