ESP32简单使用实现蓝牙音箱
本文介绍了基于ESP32和MAX98357音频模块实现蓝牙音乐播放功能的开发过程。
·
一、ESP32简介
1.1简介
淘宝购买开发板与官方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(){
}
更多推荐



所有评论(0)