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回だけ鳴らすため、ループ内は空です }

0 件のコメント:

コメントを投稿