一、ESP32简介

1.1简介

Arduino开发

官方

淘宝购买开发板与官方ESP32-DevKitC类似,按这个型号进行学习

在这里插入图片描述
主要用途

1.2引脚定义

在这里插入图片描述

二、MAX98357

2.1 介绍
MAX98357A模块引脚 引脚说明
VIN 电源正(2.5V-5.5V)
GND 电源地
SD 关机和频道选择。SD MODE拉低以将器件处于关断状态,当处于不同电压范围时,则有配置不同的频道
GAIN 增益和频道选择。在TDM模式下,增益固定为12dB
DIN 数字信号输入
BCLK 位时钟输入
LRC I2S与LJ模式的左/右时钟。同步时钟用于TDM模式
2.2 主要用途

MAX98357的主要用途是作为数字脉冲编码调制(PCM)输入的D类功率放大器。它能够提供AB类音频性能,同时具有D类的效率,适用于电池供电的应用。MAX98357可以直接接收I2S数字音频数据,简化电路设计,减少元件数量,并降低噪声和失真。它支持多种I2S数据格式,并能够在单电源供电下为4Ω负载提供高达3.2W的输出功率,或为8Ω负载提供1.8W的输出功率,效率高达92%

三、使用Arduino开发实现蓝牙播放音乐功能

具体配置参考网上其他教程
1.下载Arduino IDE
2.下载ESP32开发板包
可以下载开发包手动安装安装包下载,双击exe就可快速安装
也可以在线下载
在这里插入图片描述

3.下载A2DP、I2S等库文件
github下载A2DP,下载完成后手动添加
在这里插入图片描述

4.连接模块电路

5.编写代码实现蓝牙播放

A2DP 蓝牙协议,仅提供音频流,它还支持与 A2DP 配合使用的音频/视频远程控制协议(AVRCP)
常用函数

a2dp_sink.play();//播放音乐
a2dp_sink.pause();//暂停音乐
a2dp_sink.next();//下一首
a2dp_sink.previous();// 上一首

下面代码实现了串口接收指令以及控制等

#include <Arduino.h>
#include <HardwareSerial.h>
#include "BluetoothA2DPSink.h"
 
BluetoothA2DPSink a2dp_sink;
bool connection = 0;
enum ParserState {
  WAIT_START,
  WAIT_LEN,
  WAIT_CMD,
  WAIT_FEEDBACK,
  WAIT_PARA1,
  WAIT_PARA2,
  WAIT_CHECKSUM_H,
  WAIT_CHECKSUM_L,
  WAIT_END
};
ParserState currentState = WAIT_START;
byte expectedLength = 0;
byte receivedCMD = 0;
byte receivedFeedback = 0;
byte receivedPara1 = 0;
byte receivedPara2 = 0;
uint16_t calculatedChecksum = 0;
uint16_t receivedChecksum = 0;
// 发送反馈数据
void send_response(byte cmd, byte status, byte para1 = 0, byte para2 = 0) {
  byte response[9] = {0x7E, 0x04, cmd, 0x01, para1, para2, 0x00, 0x00, 0xEF};
  
  // 计算校验和 (Len到para2)
  uint16_t checksum = 0;
  for(int i = 1; i <= 5; i++) { // 索引1-5: Len(0x04), CMD, Feedback, para1, para2
    checksum += response[i];
  }
  
  response[6] = (byte)(checksum >> 8);   // 校验和高字节
  response[7] = (byte)(checksum & 0xFF); // 校验和低字节
  
  Serial.write(response, sizeof(response));
}

void connection_state_changed(esp_a2d_connection_state_t state, void* ptr) {
  if(state == ESP_A2D_CONNECTION_STATE_CONNECTED){
    Serial.println("Connected");
    connection = 1;
  }
  else{
    Serial.println("Disconnected");
    connection = 0;
  }
  
}
void process_command() {
  switch(receivedCMD) {
    case 0x1A: // 查询蓝牙连接状态
      if(receivedFeedback == 0x01) {
        byte status = a2dp_sink.is_connected() ? 0x01 : 0x00;
        send_response(receivedCMD, status);
      }
      break;
      
    case 0x1B: // 启动连接
      // 蓝牙作为从设备通常自动处理连接
      if(receivedFeedback == 0x01) {
        send_response(receivedCMD, 0x01);
      }
      break;
      
    case 0x1C: // 播放
      a2dp_sink.play();
      if(receivedFeedback == 0x01) {
        send_response(receivedCMD, 0x01);
      }
      break;
      
    case 0x1D: // 暂停
      a2dp_sink.pause();
      if(receivedFeedback == 0x01) {
        send_response(receivedCMD, 0x01);
      }
      break;
      
    case 0x1E: // 下一首
      a2dp_sink.next();
      if(receivedFeedback == 0x01) {
        send_response(receivedCMD, 0x01);
      }
      break;
      
    case 0x1F: // 上一首
      a2dp_sink.previous();
      if(receivedFeedback == 0x01) {
        send_response(receivedCMD, 0x01);
      }
      break;
      
    case 0x20: // 循环播放当前歌曲
      // A2DP库不直接支持,可通过自定义逻辑实现
      if(receivedFeedback == 0x01) {
        send_response(receivedCMD, 0x01);
      }
      break;
  }
}

// 解析串口数据
void parse_serial_data(byte data) {
  switch(currentState) {
    case WAIT_START:
      if(data == 0x7E) {
        currentState = WAIT_LEN;
        calculatedChecksum = 0; // 重置校验和
      }
      break;
      
    case WAIT_LEN:
      expectedLength = data;
      calculatedChecksum += data; // 添加Len到校验和
      currentState = WAIT_CMD;
      break;
      
    case WAIT_CMD:
      receivedCMD = data;
      calculatedChecksum += data;
      currentState = WAIT_FEEDBACK;
      break;
      
    case WAIT_FEEDBACK:
      receivedFeedback = data;
      calculatedChecksum += data;
      currentState = WAIT_PARA1;
      break;
      
    case WAIT_PARA1:
      receivedPara1 = data;
      calculatedChecksum += data;
      currentState = WAIT_PARA2;
      break;
      
    case WAIT_PARA2:
      receivedPara2 = data;
      calculatedChecksum += data;
      currentState = WAIT_CHECKSUM_H;
      break;
      
    case WAIT_CHECKSUM_H:
      receivedChecksum = (uint16_t)data << 8;
      currentState = WAIT_CHECKSUM_L;
      break;
      
    case WAIT_CHECKSUM_L:
      receivedChecksum |= data;
      currentState = WAIT_END;
      break;
      
    case WAIT_END:
      if(data == 0xEF) {
        // 验证校验和
        if(calculatedChecksum == receivedChecksum) {
          process_command();
        }
      }
      currentState = WAIT_START; // 无论成功与否都重置状态机
      break;
  }
}
void setup(){
 
 Serial.begin(115200); // 初始化串口通信
 i2s_pin_config_t my_pin_config = {
        .bck_io_num = 26,//输入 bck
        .ws_io_num = 25,//输入 
        .data_out_num = 27,//输出
        .data_in_num = I2S_PIN_NO_CHANGE
    };
  a2dp_sink.set_pin_config(my_pin_config);

  a2dp_sink.set_on_connection_state_changed(connection_state_changed);

  a2dp_sink.start("BabyCar");
 
}
 
 
void loop(){
  while(Serial.available() > 0) {
    byte incomingByte = Serial.read();
    parse_serial_data(incomingByte);
  }
}

精简版代码

#include <Arduino.h>
#include "BluetoothA2DPSink.h"
 
BluetoothA2DPSink a2dp_sink;

void setup(){
 i2s_pin_config_t my_pin_config = {
        .bck_io_num = 26,//输入 bck
        .ws_io_num = 25,//输入 
        .data_out_num = 27,//输出
        .data_in_num = I2S_PIN_NO_CHANGE
    };
  a2dp_sink.set_pin_config(my_pin_config);

  a2dp_sink.start("BabyCar");
 
}
 
 
void loop(){

}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐