简体中文
English
简体中文
日本語

Arduino 上手教程

2. 设备开发 & 案例程序

5. 拓展模块

6. 应用案例

Module Audio Arduino 使用教程

1. 准备工作

2. 初始化配置

Module Audio 集成了 STM32 主控用于实现耳机接口标准切换,灯光控制,耳机插入检测(仅通道 2 可用),麦克风输入模式配置等功能。

接口标准选择
由于不同的耳机接口标准的所使用的线序不同,使用需根据实际情况使用audio.setHPMode(AUDIO_HPMODE_NATIONAL);函数切换耳机接口标准以实现兼容。OMTP(AUDIO_HPMODE_NATIONAL),CTIA(AUDIO_HPMODE_AMERICAN)。
cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#include <M5Unified.h>
#include <M5Module_Audio.h>

M5ModuleAudio audio;

void setup()
{
    // Initialize M5Unified without the built-in audio devices.
    auto cfg = M5.config();
    cfg.serial_baudrate = 115200;
    cfg.internal_mic = false;
    cfg.internal_spk = false;

    M5.begin(cfg);

    if (!audio.begin(Wire)) {
        Serial.println("Module Audio not found.");

        while (true) {
            delay(1000);
        }
    }

    audio.setHPMode(AUDIO_HPMODE_NATIONAL);
    // audio.setHPMode(AUDIO_HPMODE_AMERICAN);
    audio.setMICStatus(AUDIO_MIC_OPEN);
    audio.setRGBBrightness(100);

    for (uint8_t i = 0; i < 3; ++i) {
        audio.setRGBLED(i, 0x0000FF);
    }
}

void loop()
{
    M5.update();

    bool is_hp_inserted = audio.getHPInsertStatus();

    if (is_hp_inserted) {
        Serial.println("Headphone Inserted");
    } else {
        Serial.println("Headphone Removed");
    }
    delay(500);
}

3. 输入接口配置

接口使用说明
Module Audio 配有两组 3.5mm 音频接口(通道 1 和通道 2),其中通道 1 适用于 3.5mm TRS 音频信号接口的麦克风输入。通道 2 适用于 3.5mm TRRS 复合音频接口设备连接,同时也兼容 TRS 音频信号接口。
  • TRS 音频信号接口接线方式:通道 1 接入 MIC 输入,通道 2 接入音频输出。适用于麦克风与音频输出分离的设备,如电脑头戴耳机等。
  • TRRS 复合音频接口接线方式:通道 2 可接入复合音频输入输出,适用于带有麦克风的有线耳机,同时兼容 TRS 音频接口设备。

在完成初始化后,通过调用以下 API 配置输入输出接口通道选择与音量增益等参数。

cpp
1 2 3 4 5 6 7 8 9 10 11 12
// Use input 1 for both channels.
audio.setMicInputLine(ADC_INPUT_LINPUT1_RINPUT1);

// Use input 2 for both channels.
// audio.setMicInputLine(ADC_INPUT_LINPUT2_RINPUT2);

audio.setSpeakerOutput(DAC_OUTPUT_OUT1);
audio.setMicAdcVolume(100);
audio.setSpeakerVolume(40);
audio.setMicGain(MIC_GAIN_24DB);
audio.setBitsSample(ES_MODULE_ADC, BIT_LENGTH_16BITS);
audio.setSampleRate(SAMPLE_RATE_44K);

4. 录音和播放

使用 TRS 音频信号接口接线方式,配置通道 1 接入 MIC 输入,通道 2 音频输出,实现实时读取 MIC 输入数据和播放。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
#include <M5Unified.h>
#include <M5Module_Audio.h>

M5ModuleAudio audio;

static constexpr size_t AUDIO_BUFFER_SIZE = 512;

static uint8_t audio_buffer[AUDIO_BUFFER_SIZE];

void setup()
{
    // Initialize M5Unified without the built-in audio devices.
    auto cfg = M5.config();
    cfg.serial_baudrate = 115200;
    cfg.internal_mic = false;
    cfg.internal_spk = false;

    M5.begin(cfg);

    // Initialize Module Audio on the internal I2C bus.
    if (!audio.begin(M5.In_I2C)) {
        Serial.println("Module Audio not found.");

        while (true) {
            delay(1000);
        }
    }

    // Configure the Module Audio controller.
    audio.setHPMode(AUDIO_HPMODE_NATIONAL);
    audio.setMICStatus(AUDIO_MIC_OPEN);
    audio.setRGBBrightness(100);

    Serial.printf("HP mode: %d\n", audio.getHPMode());
    Serial.printf("MIC status: %d\n", audio.getMICStatus());

    // Set the status LEDs.
    const uint32_t colors[] = {
        0x00FF00,
        0xFFFF00,
        0xFFFFFF,
    };

    for (uint8_t i = 0; i < 3; ++i) {
        audio.setRGBLED(i, colors[i]);

        Serial.printf(
            "RGB-%u: set=%06X, read=%06X\n",
            i,
            static_cast<unsigned>(colors[i]),
            static_cast<unsigned>(audio.getRGBLED(i)));
    }

    // Configure ES8388 for microphone loopback.
    audio.setMicInputLine(ADC_INPUT_LINPUT2_RINPUT2);
    audio.setMicGain(MIC_GAIN_24DB);
    audio.setMicAdcVolume(100);
    audio.setSpeakerVolume(40);
    audio.setSpeakerOutput(DAC_OUTPUT_OUT1);
    audio.setBitsSample(
        ES_MODULE_ADC_DAC,
        BIT_LENGTH_16BITS);
    audio.setSampleRate(SAMPLE_RATE_44K);

    // Print the ES8388 register values.
    Serial.println("Read ES8388 registers:");

    uint8_t* registers = audio.readAllReg();

    if (registers != nullptr) {
        for (uint8_t i = 0; i < 53; ++i) {
            Serial.printf(
                "Reg-%02u = 0x%02X\r\n",
                i,
                registers[i]);
        }
    }

    Serial.println("Audio loopback started.");
}

void loop()
{
    M5.update();

    // Capture one audio buffer.
    if (!audio.record(audio_buffer, sizeof(audio_buffer))) {
        Serial.println("Audio record failed.");
        delay(100);
        return;
    }

    // Play the captured audio buffer.
    if (!audio.play(audio_buffer, sizeof(audio_buffer))) {
        Serial.println("Audio playback failed.");
        delay(100);
    }
}

5. 播放 microSD WAV

配置通道 2 音频输出,加载 microSD 卡中存储的 WAV 文件,并进行播放。使用前需添加 wav 文件至 microSD 卡,并插入至主控设备卡槽中。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
#include <M5Unified.h>
#include <M5Module_Audio.h>
#include <SPI.h>
#include <SD.h>

M5ModuleAudio audio;
File wav_file;

static constexpr char WAV_PATH[] = "/hello.wav";
static constexpr size_t WAV_HEADER_SIZE = 44;
static constexpr size_t AUDIO_BUFFER_SIZE = 1024;

static uint8_t audio_buffer[AUDIO_BUFFER_SIZE];

bool openWavFile()
{
    if (wav_file) {
        wav_file.close();
    }

    wav_file = SD.open(WAV_PATH, FILE_READ);

    if (!wav_file) {
        Serial.printf("Failed to open %s\n", WAV_PATH);
        return false;
    }

    if (wav_file.size() <= WAV_HEADER_SIZE) {
        Serial.println("Invalid or empty WAV file.");
        wav_file.close();
        return false;
    }

    Serial.printf(
        "WAV file size: %u bytes\n",
        static_cast<unsigned>(wav_file.size()));

    if (!wav_file.seek(WAV_HEADER_SIZE)) {
        Serial.println("Failed to skip WAV header.");
        wav_file.close();
        return false;
    }

    return true;
}

void setup()
{
    auto cfg = M5.config();
    cfg.serial_baudrate = 115200;
    cfg.internal_mic = false;
    cfg.internal_spk = false;

    M5.begin(cfg);

    Serial.printf(
        "Detected board: %d\n",
        static_cast<int>(M5.getBoard()));

    if (!audio.begin(M5.In_I2C)) {
        Serial.println("Module Audio not found.");

        while (true) {
            delay(1000);
        }
    }

    audio.setHPMode(AUDIO_HPMODE_NATIONAL);
    audio.setMICStatus(AUDIO_MIC_OPEN);
    audio.setRGBBrightness(100);

    Serial.printf("HP mode: %d\n", audio.getHPMode());
    Serial.printf("MIC status: %d\n", audio.getMICStatus());

    const uint32_t colors[] = {
        0x00FF00,
        0xFFFF00,
        0xFFFFFF,
    };

    for (uint8_t i = 0; i < 3; ++i) {
        audio.setRGBLED(i, colors[i]);

        Serial.printf(
            "RGB-%u: set=%06X, read=%06X\n",
            i,
            static_cast<unsigned>(colors[i]),
            static_cast<unsigned>(audio.getRGBLED(i)));
    }

    // M5ModuleAudio has already initialized ES8388.
    audio.setMicAdcVolume(100);
    audio.setSpeakerVolume(80);
    audio.setSpeakerOutput(DAC_OUTPUT_OUT1);
    audio.setBitsSample(
        ES_MODULE_ADC_DAC,
        BIT_LENGTH_16BITS);
    audio.setSampleRate(SAMPLE_RATE_44K);

    Serial.println("Read ES8388 registers:");

    uint8_t* registers = audio.readAllReg();

    if (registers != nullptr) {
        for (uint8_t i = 0; i < 53; ++i) {
            Serial.printf(
                "Reg-%02u = 0x%02X\r\n",
                i,
                registers[i]);
        }
    }

    // Get the SD SPI pins for the detected board.
    int sd_sclk = M5.getPin(m5::pin_name_t::sd_spi_sclk);
    int sd_miso = M5.getPin(m5::pin_name_t::sd_spi_miso);
    int sd_mosi = M5.getPin(m5::pin_name_t::sd_spi_mosi);
    int sd_cs   = M5.getPin(m5::pin_name_t::sd_spi_cs);

    Serial.printf("SD SPI: SCLK=%d, MISO=%d, MOSI=%d, CS=%d\n", sd_sclk, sd_miso, sd_mosi, sd_cs);

    SPI.begin(sd_sclk, sd_miso, sd_mosi, sd_cs);

    if (!SD.begin(sd_cs, SPI, 25000000)) {
        Serial.println("Failed to initialize SD card.");

        while (true) {
            delay(1000);
        }
    }

    Serial.println("SD card initialized successfully.");

    if (!openWavFile()) {
        while (true) {
            delay(1000);
        }
    }

    Serial.println("WAV playback started.");
}

void loop()
{
    M5.update();

    if (!wav_file) {
        delay(100);
        return;
    }

    // Restart playback at the beginning of the audio data.
    if (wav_file.available() == 0) {
        if (!wav_file.seek(WAV_HEADER_SIZE)) {
            Serial.println("Failed to restart WAV file.");
            delay(100);
        }

        return;
    }

    size_t bytes_read =
        wav_file.read(audio_buffer, sizeof(audio_buffer));

    if (bytes_read == 0) {
        return;
    }

    if (!audio.play(audio_buffer, bytes_read)) {
        Serial.println("I2S write failed.");
        delay(100);
    }
}

6.RGB LED 控制

Module Audio 侧边集成了 3 颗可编程 RGB LED,可参考以下案例进行控制。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
#include <M5Unified.h>
#include <M5Module_Audio.h>

M5ModuleAudio audio;

void setup()
{
    auto cfg = M5.config();
    cfg.serial_baudrate = 115200;
    cfg.internal_mic = false;
    cfg.internal_spk = false;

    M5.begin(cfg);

    if (!audio.begin(M5.In_I2C)) {
        Serial.println("Module Audio not found.");

        while (true) {
            delay(1000);
        }
    }

    audio.setRGBBrightness(100);
    Serial.println("Module Audio initialized successfully.");
}

void loop()
{
    M5.update();

    // Cycle all LEDs through red, green, and blue.
    for (uint8_t i = 0; i < 3; ++i) {
        audio.setRGBLED(i, 0xFF0000);
    }

    delay(1000);

    for (uint8_t i = 0; i < 3; ++i) {
        audio.setRGBLED(i, 0x00FF00);
    }

    delay(1000);

    for (uint8_t i = 0; i < 3; ++i) {
        audio.setRGBLED(i, 0x0000FF);
    }

    delay(1000);
}
Page Tools
PDF
On This Page