2026年7月27日月曜日
esp32 内蔵DAC成功
http://jh7ubc.web.fc2.com/esp32/ESP32_DAC.htmlで正弦波を音出しできたと思う
チャットくんにきいて内蔵DACのgpio25でドレミファソラシドやっってみた
#include
const int DAC_PIN = 25;
// サンプリング周波数
const float SAMPLE_RATE = 20000.0f;
const int SAMPLE_INTERVAL_US = 50; // 1/20000秒
// ドレミファソラシド(C4~C5)
const float notes[] = {
261.63, // ド
293.66, // レ
329.63, // ミ
349.23, // ファ
392.00, // ソ
440.00, // ラ
493.88, // シ
523.25 // ド
};
const int NOTE_COUNT = sizeof(notes) / sizeof(notes[0]);
int currentNote = 0;
float phase = 0.0f;
unsigned long lastChange = 0;
void setup() {
lastChange = millis();
}
void loop() {
// 0.5秒ごとに次の音へ
if (millis() - lastChange >= 500) {
lastChange += 500;
#include
const int DAC_PIN = 25;
// サンプリング周波数
const float SAMPLE_RATE = 20000.0f;
const int SAMPLE_INTERVAL_US = 50; // 1/20000秒
// ドレミファソラシド(C4~C5)
const float notes[] = {
261.63, // ド
293.66, // レ
329.63, // ミ
349.23, // ファ
392.00, // ソ
440.00, // ラ
493.88, // シ
523.25 // ド
};
const int NOTE_COUNT = sizeof(notes) / sizeof(notes[0]);
int currentNote = 0;
float phase = 0.0f;
unsigned long lastChange = 0;
void setup() {
lastChange = millis();
}
void loop() {
// 0.5秒ごとに次の音へ
if (millis() - lastChange >= 500) {
lastChange += 500;
currentNote++;
if (currentNote >= NOTE_COUNT) {
currentNote = 0;
}
}
// 位相を更新
phase += 2.0f * PI * notes[currentNote] / SAMPLE_RATE;
if (phase >= 2.0f * PI) {
phase -= 2.0f * PI;
}
// 正弦波生成
uint8_t dacValue = (uint8_t)(128 + 127 * sin(phase));
// DAC出力
dacWrite(DAC_PIN, dacValue);
// サンプリング周期を維持
delayMicroseconds(SAMPLE_INTERVAL_US);
}
currentNote++;
if (currentNote >= NOTE_COUNT) {
currentNote = 0;
}
}
// 位相を更新
phase += 2.0f * PI * notes[currentNote] / SAMPLE_RATE;
if (phase >= 2.0f * PI) {
phase -= 2.0f * PI;
}
// 正弦波生成
uint8_t dacValue = (uint8_t)(128 + 127 * sin(phase));
// DAC出力
dacWrite(DAC_PIN, dacValue);
// サンプリング周期を維持
delayMicroseconds(SAMPLE_INTERVAL_US);
}
https://www.farmsoft.jp/2193/#toc6でmax98357aのつかいかたはわかった
この例では次のようにしているが、任意のピンをえらぶ
GAIN と SD は接続していません。音量の制御や出力制御を変更することができますので、必要であれば接続してください。
MAX98357A ESP32開発ボード(38Pin)
LRC GPIO 26 // WSとも呼ばれるWord Select(ワードセレクト / LRCK:左右チャンネル切替信号)
BCLK GPIO 27 // BCLK(Bit Clock)とは、I2S通信で1ビットごとのデータの区切りや転送タイミングを合わせるためのシリアルクロック信号
DIN GPIO 25 // DATA とも呼ばれる DINとは、Data In(データ入力)
GAIN ー
SD ー
GND GND
VIN 5V
https://firtel.blogspot.com/2023/08/esp32-max98357a-i2s-dac.html でも下記だった
#include
#include
// ご指定のピン配置を設定
#define I2S_BCLK 26 // PIN_BCK
#define I2S_LRC 25 // PIN_WS
#define I2S_DIN 22 // PIN_DATA
#define I2S_NUM I2S_NUM_0
#define SAMPLE_RATE 44100 // サンプリング周波数 (44.1kHz)
// I2Sの初期化関数
void initI2S() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // 16bitデータ
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // ステレオ形式
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_BCLK,
.ws_io_num = I2S_LRC,
.data_out_num = I2S_DIN,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM, &pin_config);
}
// 指定した周波数(Hz)の音を指定した時間(ミリ秒)鳴らす関数
void playTone(float frequency, int duration_ms) {
int samples_to_send = (SAMPLE_RATE * duration_ms) / 1000;
int16_t sample_buffer[2]; // [0]=Lch, [1]=Rch
size_t bytes_written;
for (int i = 0; i < samples_to_send; i++) {
// 正弦波の計算 (音量を適度に抑えるために 10000 を掛けています。最大32767)
int16_t sample = (int16_t)(10000.0 * sin(2.0 * M_PI * frequency * i / SAMPLE_RATE));
sample_buffer[0] = sample; // 左チャンネル
sample_buffer[1] = sample; // 右チャンネル
// I2Sへデータを送信
i2s_write(I2S_NUM, sample_buffer, sizeof(sample_buffer), &bytes_written, portMAX_DELAY);
}
// 音の終わりに小さなポップノイズが出るのを防ぐため、無音を出力して締める
sample_buffer[0] = 0;
sample_buffer[1] = 0;
i2s_write(I2S_NUM, sample_buffer, sizeof(sample_buffer), &bytes_written, portMAX_DELAY);
}
void setup() {
Serial.begin(115200);
delay(1000); // シリアルモニターの準備待ち
initI2S();
Serial.println("--- play start ---");
// 440Hz(ラ / A4)の音を 1000ミリ秒(1秒)鳴らす
playTone(440.0, 1000);
delay(200); // 0.2秒の無音
// 少し高めの 880Hz(高いラ)の音を 500ミリ秒鳴らす
playTone(880.0, 500);
Serial.println("--- play end ---");
}
void loop() {
// 起動時に1回だけ鳴らすため、ループ内は空です
}
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿