ESP32与Android蓝牙通信实现与优化

发布时间:2026/7/23 14:31:43
ESP32与Android蓝牙通信实现与优化 1. ESP32蓝牙通信项目概述ESP32作为一款集成了Wi-Fi和蓝牙双模通信功能的低成本微控制器在物联网领域有着广泛的应用。本项目聚焦于ESP32与Android手机之间的蓝牙通信实现包含文本数据的双向传输功能。这种技术组合非常适合需要短距离无线数据传输的场景比如智能家居控制、传感器数据采集、远程设备配置等。ESP32支持经典蓝牙(BR/EDR)和低功耗蓝牙(BLE)两种模式。在本项目中我们将主要使用经典蓝牙协议因为它更适合持续的数据流传输而BLE更适用于间歇性的小数据包传输。Android系统从4.3版本开始支持BLE但对经典蓝牙的支持更早也更完善。2. 硬件与开发环境准备2.1 所需硬件组件ESP32开发板推荐使用ESP32-WROOM-32系列Android智能手机Android 5.0及以上版本Micro USB数据线用于ESP32供电和编程可选杜邦线、面包板等辅助连接工具2.2 软件开发环境配置ESP32端开发环境推荐使用PlatformIO VSCode组合这是目前最流行的ESP32开发方式安装Visual Studio Code在VSCode扩展市场中搜索并安装PlatformIO IDE创建新项目选择ESP32开发板如Espressif ESP32 Dev Module在platformio.ini配置文件中添加必要的库依赖[env:esp32dev] platform espressif32 board esp32dev framework arduino monitor_speed 115200 lib_deps https://github.com/espressif/arduino-esp32.gitAndroid端开发环境使用Android Studio进行开发下载并安装最新版Android Studio创建新项目选择Empty Activity模板在build.gradle(Module:app)中添加蓝牙权限和依赖android { compileSdkVersion 33 defaultConfig { minSdkVersion 21 targetSdkVersion 33 } } dependencies { implementation androidx.appcompat:appcompat:1.6.1 implementation com.google.android.material:material:1.9.0 }3. ESP32蓝牙服务端实现3.1 初始化蓝牙串口协议(SPP)ESP32端的代码主要基于Arduino框架的BluetoothSerial库这是ESP32 Arduino核心的一部分无需额外安装。#include BluetoothSerial.h BluetoothSerial SerialBT; void setup() { Serial.begin(115200); SerialBT.begin(ESP32_Bluetooth_Device); // 蓝牙设备名称 Serial.println(蓝牙设备已启动等待连接...); } void loop() { if (SerialBT.available()) { String receivedData SerialBT.readString(); Serial.print(收到数据: ); Serial.println(receivedData); // 回传接收到的数据 SerialBT.print(ESP32已收到: ); SerialBT.println(receivedData); } delay(20); }3.2 代码关键点解析BluetoothSerial库这是ESP32 Arduino核心提供的简化蓝牙操作库封装了底层复杂的蓝牙协议栈操作。设备名称设置SerialBT.begin()中的参数将作为蓝牙设备的可见名称显示在手机搜索列表中。数据接收处理使用SerialBT.available()检查是否有数据到达避免阻塞程序运行。数据回传示例中实现了简单的回显功能实际应用中可根据需求处理数据。3.3 常见问题与调试技巧注意如果遇到连接问题首先检查手机是否已配对ESP32设备并确认在代码中使用了正确的服务UUID如果需要。连接不稳定确保ESP32供电充足建议使用USB直接供电而非3.3V引脚检查天线位置避免金属屏蔽降低数据传输速率测试数据丢失增加接收缓冲区大小实现简单的数据校验机制使用readStringUntil(\n)按行读取数据性能优化建议对于高频数据传输考虑使用二进制协议而非文本实现心跳机制保持连接稳定添加连接状态指示灯LED4. Android客户端实现4.1 Android蓝牙权限配置在AndroidManifest.xml中添加必要权限uses-permission android:nameandroid.permission.BLUETOOTH/ uses-permission android:nameandroid.permission.BLUETOOTH_ADMIN/ uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION/ uses-permission android:nameandroid.permission.BLUETOOTH_CONNECT/ uses-permission android:nameandroid.permission.BLUETOOTH_SCAN/对于Android 12及以上版本还需要在Application标签中添加uses-feature android:nameandroid.hardware.bluetooth android:requiredtrue/4.2 蓝牙连接管理类实现创建一个BluetoothHelper类处理所有蓝牙操作public class BluetoothHelper { private static final String TAG BluetoothHelper; private BluetoothAdapter bluetoothAdapter; private BluetoothSocket bluetoothSocket; private BluetoothDevice targetDevice; private InputStream inputStream; private OutputStream outputStream; private Handler handler; // 用于UI更新 public BluetoothHelper(Context context, Handler handler) { this.handler handler; bluetoothAdapter BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter null) { sendMessageToHandler(设备不支持蓝牙); } } public void connectToDevice(String deviceName) { SetBluetoothDevice pairedDevices bluetoothAdapter.getBondedDevices(); for (BluetoothDevice device : pairedDevices) { if (device.getName().equals(deviceName)) { targetDevice device; break; } } if (targetDevice null) { sendMessageToHandler(未找到指定设备); return; } try { bluetoothSocket targetDevice.createRfcommSocketToServiceRecord( UUID.fromString(00001101-0000-1000-8000-00805F9B34FB)); bluetoothSocket.connect(); inputStream bluetoothSocket.getInputStream(); outputStream bluetoothSocket.getOutputStream(); sendMessageToHandler(连接成功); startListening(); } catch (IOException e) { sendMessageToHandler(连接失败: e.getMessage()); } } private void startListening() { new Thread(() - { byte[] buffer new byte[1024]; int bytes; while (true) { try { bytes inputStream.read(buffer); String receivedData new String(buffer, 0, bytes); sendMessageToHandler(收到: receivedData); } catch (IOException e) { sendMessageToHandler(连接断开); break; } } }).start(); } public void sendData(String data) { if (outputStream ! null) { try { outputStream.write(data.getBytes()); outputStream.flush(); } catch (IOException e) { sendMessageToHandler(发送失败: e.getMessage()); } } } private void sendMessageToHandler(String message) { Message msg handler.obtainMessage(); Bundle bundle new Bundle(); bundle.putString(message, message); msg.setData(bundle); handler.sendMessage(msg); } public void disconnect() { try { if (bluetoothSocket ! null) { bluetoothSocket.close(); } sendMessageToHandler(已断开连接); } catch (IOException e) { sendMessageToHandler(断开连接错误: e.getMessage()); } } }4.3 Android UI界面设计一个简单的聊天界面布局示例activity_main.xmlLinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical android:padding16dp TextView android:idid/statusTextView android:layout_widthwrap_content android:layout_heightwrap_content android:text状态: 未连接/ Button android:idid/connectButton android:layout_widthmatch_parent android:layout_heightwrap_content android:text连接ESP32/ EditText android:idid/messageEditText android:layout_widthmatch_parent android:layout_heightwrap_content android:hint输入要发送的消息/ Button android:idid/sendButton android:layout_widthmatch_parent android:layout_heightwrap_content android:text发送/ ScrollView android:layout_widthmatch_parent android:layout_height0dp android:layout_weight1 TextView android:idid/chatTextView android:layout_widthmatch_parent android:layout_heightwrap_content/ /ScrollView /LinearLayout4.4 MainActivity实现public class MainActivity extends AppCompatActivity { private BluetoothHelper bluetoothHelper; private TextView statusTextView, chatTextView; private EditText messageEditText; private final Handler handler new Handler(Looper.getMainLooper()) { Override public void handleMessage(Message msg) { String message msg.getData().getString(message); chatTextView.append(message \n); if (message.startsWith(状态:)) { statusTextView.setText(message); } } }; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); statusTextView findViewById(R.id.statusTextView); chatTextView findViewById(R.id.chatTextView); messageEditText findViewById(R.id.messageEditText); bluetoothHelper new BluetoothHelper(this, handler); findViewById(R.id.connectButton).setOnClickListener(v - { if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_CONNECT}, 1); } else { bluetoothHelper.connectToDevice(ESP32_Bluetooth_Device); } }); findViewById(R.id.sendButton).setOnClickListener(v - { String message messageEditText.getText().toString(); if (!message.isEmpty()) { bluetoothHelper.sendData(message); chatTextView.append(发送: message \n); messageEditText.setText(); } }); } Override protected void onDestroy() { super.onDestroy(); bluetoothHelper.disconnect(); } }5. 项目调试与优化5.1 常见连接问题排查设备不可见确认ESP32蓝牙已正确初始化检查设备名称是否设置正确确保没有其他设备使用相同名称配对失败尝试删除手机蓝牙设置中已保存的ESP32设备重新配对检查蓝牙协议版本兼容性确认没有启用不必要的安全认证数据传输不稳定减小单次传输数据量分片传输增加适当的传输延迟实现简单的重传机制5.2 性能优化建议数据传输协议设计使用固定长度的数据帧添加帧头帧尾标识包含简单的校验和或CRC校验错误处理增强实现自动重连机制添加连接状态监控记录错误日志便于分析电源管理优化ESP32的电源模式合理设置蓝牙发射功率实现空闲时低功耗模式6. 项目扩展与进阶应用6.1 多设备通信通过修改ESP32代码可以实现一个蓝牙服务端同时与多个Android客户端通信// ESP32端需要维护多个客户端连接 #include vector std::vectorBluetoothSerial* clients; void setup() { Serial.begin(115200); SerialBT.begin(ESP32_MultiClient); } void loop() { // 检查新连接 if (SerialBT.hasClient()) { BluetoothSerial* newClient new BluetoothSerial(); if (newClient-connect(ESP32_MultiClient)) { clients.push_back(newClient); Serial.println(新客户端连接); } } // 处理所有客户端数据 for (auto client : clients) { if (client-available()) { String data client-readString(); Serial.print(来自客户端的消息: ); Serial.println(data); // 广播给所有客户端 for (auto c : clients) { c-println(广播: data); } } } delay(100); }6.2 数据加密与安全为蓝牙通信添加简单的加密层// 简单的XOR加密 String encryptDecrypt(String input) { char key K; // 加密密钥 String output input; for (int i 0; i input.length(); i) { output[i] input[i] ^ key; } return output; } void loop() { if (SerialBT.available()) { String received SerialBT.readString(); String decrypted encryptDecrypt(received); SerialBT.print(encryptDecrypt(ESP32收到: decrypted)); } }6.3 结合Wi-Fi实现网关功能ESP32可以同时作为蓝牙-WiFi网关将蓝牙设备数据转发到网络服务器#include WiFi.h #include HTTPClient.h const char* ssid your_SSID; const char* password your_PASSWORD; const char* serverUrl http://yourserver.com/api/data; void setup() { Serial.begin(115200); SerialBT.begin(ESP32_Gateway); WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(WiFi连接成功); } void loop() { if (SerialBT.available()) { String data SerialBT.readString(); if (WiFi.status() WL_CONNECTED) { HTTPClient http; http.begin(serverUrl); http.addHeader(Content-Type, application/json); String payload {\data\:\ data \}; int httpCode http.POST(payload); if (httpCode 0) { String response http.getString(); SerialBT.println(数据已上传: response); } http.end(); } } delay(1000); }在实际项目中蓝牙通信的稳定性和可靠性是关键考量因素。建议在正式应用中加入心跳包机制、数据校验、自动重连等功能并根据具体应用场景优化数据传输协议。对于需要低功耗的场景可以考虑切换到BLE协议并优化通信间隔参数。