ESP32双模蓝牙开发实战:从经典串口到BLE传感器应用

发布时间:2026/7/30 10:34:09

ESP32双模蓝牙开发实战:从经典串口到BLE传感器应用 1. 项目概述为什么ESP32的蓝牙能力值得深挖如果你玩过Arduino大概率接触过各种无线模块比如WiFi模块、2.4G射频模块。但当你拿到一块ESP32开发板时你会发现它自带了一个强大的“瑞士军刀”——双模蓝牙。这不仅仅是“又一个蓝牙模块”而是意味着你可以用同一块芯片同时玩转经典蓝牙比如连接音响播放音乐和低功耗蓝牙BLE比如做一个智能手环传感器。我最初接触时也以为就是简单的串口透传但实际用下来发现从简单的数据透传到复杂的音频流、设备配对管理这里面门道不少。很多朋友卡在第一步我该用经典蓝牙还是BLE代码框架怎么搭为什么手机能搜到但连不上这篇文章我就结合自己踩过的坑和项目经验把ESP32在Arduino环境下的双模蓝牙用法掰开揉碎了讲清楚目标是让你看完就能动手做出点东西无论是做个蓝牙遥控小车还是做个温湿度数据采集器都能找到清晰的路径。2. 核心概念辨析经典蓝牙与BLE的本质区别在动手写代码之前必须搞清楚你手里的“武器”有两种截然不同的模式。这不是简单的“新旧版本”关系而是设计目标和应用场景的根本不同。理解这个能帮你省下大量盲目调试的时间。2.1 经典蓝牙为持续大数据流而生经典蓝牙Bluetooth Classic以前也叫BR/EDR它的核心设计是为了实现稳定的、高带宽的、持续的数据通道。你可以把它想象成一条铺设好的双向高速公路一旦建立连接这条公路就专为你服务持续占用资源来保证数据流畅。典型应用场景音频传输连接蓝牙音箱、耳机A2DP协议传输音乐数据流。串口透传替代有线串口实现设备间的稳定数据通信SPP协议。很多传统的HC-05、HC-06模块就是经典蓝牙串口模块。人机交互设备连接蓝牙键盘、鼠标HID协议。在ESP32上的特点功耗相对较高连接建立过程稍慢但连接稳定后延迟低、带宽大理论上可达2-3 Mbps。它通常需要明确的配对过程。2.2 低功耗蓝牙为间歇性小数据而优化低功耗蓝牙Bluetooth Low Energy, BLE从名字就能看出它的首要目标是节能。它不像经典蓝牙那样维持一条常开的高速公路而是更像一个高效的邮差系统。设备大部分时间在睡觉广播或扫描也是间歇性的需要通信时才快速“醒来”收发一个小数据包然后继续睡觉。典型应用场景传感器数据上报温湿度传感器、心率带、智能门锁等每隔几秒或几分钟上报一次数据。信标iBeacon, Eddystone用于室内定位或信息推送。设备状态同步手环与手机同步运动数据。在ESP32上的特点功耗极低连接建立快速但传输带宽较小初期约1KB/s通过协商可提高延迟可能因连接间隔设置而波动。BLE采用“服务器-客户端”模型通信基于“服务”和“特征值”。2.3 如何选择一张表说清楚特性维度经典蓝牙 (Bluetooth Classic)低功耗蓝牙 (BLE)核心目标高数据吞吐、持续连接超低功耗、间歇性连接功耗水平高数十mA级极低微安到毫安级连接速度较慢数秒极快毫秒级数据带宽高~2-3 Mbps低初期~0.8 KB/s通信模型点对点、串流服务器/客户端、基于属性典型协议SPP, A2DP, HIDGATT, ATT适用场景音频、文件传输、串口替代传感器、信标、状态同步ESP32开发接口类似Serial易上手需理解GATT结构概念稍复杂实操心得选择的关键看你的数据特征。如果是持续不断的音频流、文件传输或实时遥控指令流选经典蓝牙。如果是偶尔上报的传感器读数、触发指令或者需要极低功耗待机选BLE。有个常见的误区想用BLE做实时音频这非常困难因为带宽和延迟天生不足。3. 开发环境搭建与核心库解析工欲善其事必先利其器。在Arduino IDE里玩转ESP32蓝牙第一步就是把环境配好并了解我们要用的“武器库”。3.1 Arduino IDE与ESP32开发板的配置安装Arduino IDE建议使用较新版本1.8.15以上或2.0稳定性更好。添加ESP32开发板支持打开Arduino IDE进入“文件”-“首选项”。在“附加开发板管理器网址”中填入https://espressif.github.io/arduino-esp32/package_esp32_index.json如果已有其他URL用逗号分隔。打开“工具”-“开发板”-“开发板管理器”搜索“esp32”找到由“Espressif Systems”提供的包点击安装。这个过程可能需要一些时间取决于网络。选择开发板与端口安装完成后在“工具”-“开发板”中选择你的ESP32型号如“ESP32 Dev Module”。将ESP32通过USB线连接电脑在“端口”中选择对应的串口。3.2 ESP32 Arduino核心库中的蓝牙相关库ESP32的Arduino核心包已经内置了强大的蓝牙库无需额外安装。主要分为两大阵营经典蓝牙相关类BluetoothSerial这是最常用的经典蓝牙串口库使用方式几乎和硬件Serial一模一样极大降低了上手门槛。BluetoothA2DPSource与BluetoothA2DPSink用于实现音频的发送作为音源和接收作为音箱。BluetoothHID用于将ESP32模拟成蓝牙键盘、鼠标等HID设备。低功耗蓝牙相关类BLE命名空间下的各类这是BLE功能的入口采用面向对象的Server、Service、Characteristic、Descriptor模型来构建GATT服务器。BLEDeviceBLE设备初始化总入口。BLEServer、BLEService、BLECharacteristic构建GATT服务的核心类。BLEAdvertising用于管理设备广播。注意事项ESP32的蓝牙功能依赖于其底层协议栈。在代码中经典蓝牙和BLE不能同时处于活跃工作状态。虽然芯片支持双模但在同一时刻你只能以一种模式作为主机进行通信例如作为BLE服务器广播或者作为经典蓝牙串口等待连接。当然它可以同时被另一种模式的设备连接例如ESP32作为BLE服务器同时手机也可以用它经典蓝牙的SPP连接它但这需要非常谨慎地管理资源。4. 经典蓝牙实战从串口透传到音频播放让我们先从接口最简单的经典蓝牙开始实现两个最常用的功能。4.1 实现蓝牙串口透传这是最基础的应用用蓝牙虚拟出一个串口替代USB线进行通信。#include BluetoothSerial.h // 检查蓝牙是否可用 #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) #error 蓝牙未启用请在菜单中启用它工具 - 蓝牙已启用 #endif BluetoothSerial SerialBT; // 创建蓝牙串口对象 void setup() { Serial.begin(115200); // 启动硬件串口用于调试输出 SerialBT.begin(ESP32_Classic_BT); // 启动蓝牙串口设备名为“ESP32_Classic_BT” // 你也可以使用 begin() 时不传参数使用默认名“ESP32” Serial.println(设备已启动现在可以配对了); Serial.println(设备名称: ESP32_Classic_BT); } void loop() { // 从硬件串口读取数据并通过蓝牙串口发送 if (Serial.available()) { char data Serial.read(); SerialBT.write(data); Serial.print([Sent via BT]: ); Serial.println(data); } // 从蓝牙串口读取数据并通过硬件串口打印 if (SerialBT.available()) { char data SerialBT.read(); Serial.write(data); Serial.print([Rcvd from BT]: ); Serial.println(data); } delay(20); // 短暂延迟避免CPU占用过高 }代码解析与实操要点BluetoothSerial SerialBT;这行代码创建了一个全局的蓝牙串口对象后续所有操作都通过它进行。SerialBT.begin(YourDeviceName)初始化蓝牙串口并设置设备名称。手机或电脑搜索蓝牙时看到的就是这个名字。SerialBT.available()和SerialBT.read()用法与硬件串口Serial完全一致用于检查是否有数据可读并读取数据。连接测试上传代码后打开手机蓝牙搜索名为“ESP32_Classic_BT”的设备并配对连接配对码通常是1234或0000。然后使用任意串口APP如“蓝牙串口”等连接该设备即可与ESP32互相收发数据。同时你可以在Arduino IDE的串口监视器看到所有通信日志。避坑技巧如果手机搜不到设备首先检查代码中的CONFIG_BT_ENABLED和CONFIG_BLUEDROID_ENABLED是否已定义。更常见的原因是你的ESP32开发板在之前可能运行过BLE程序蓝牙协议栈模式被锁定了。最有效的解决方法是完全断电重启开发板然后重新上传当前经典蓝牙程序。4.2 进阶应用打造蓝牙音频接收器利用BluetoothA2DPSink库我们可以将ESP32变成一个蓝牙音箱接收手机播放的音乐并通过I2S接口输出到DAC或MAX98357这类功放模块。#include BluetoothA2DPSink.h BluetoothA2DPSink a2dp_sink; // 创建A2DP接收器对象 // I2S引脚定义根据你的硬件连接修改 #define I2S_BCLK 26 // 位时钟 #define I2S_LRC 25 // 左右声道时钟帧时钟 #define I2S_DOUT 22 // 数据输出 void setup() { Serial.begin(115200); // 配置I2S引脚 static const i2s_config_t i2s_config { .mode (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), .sample_rate 44100, // CD音质采样率 .bits_per_sample I2S_BITS_PER_SAMPLE_16BIT, .channel_format I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format I2S_COMM_FORMAT_I2S, .intr_alloc_flags ESP_INTR_FLAG_LEVEL1, .dma_buf_count 8, .dma_buf_len 64, .use_apll false, .tx_desc_auto_clear true, .fixed_mclk 0 }; static const i2s_pin_config_t pin_config { .bck_io_num I2S_BCLK, .ws_io_num I2S_LRC, .data_out_num I2S_DOUT, .data_in_num I2S_PIN_NO_CHANGE // 我们只输出不输入 }; // 初始化A2DP接收器并传入I2S配置 a2dp_sink.set_i2s_config(i2s_config); a2dp_sink.set_pin_config(pin_config); a2dp_sink.start(ESP32_A2DP_Speaker); // 启动设置设备名 Serial.println(蓝牙音频接收器已启动设备名: ESP32_A2DP_Speaker); Serial.println(请用手机连接并播放音乐。); } void loop() { // 主循环可以空着或者处理其他任务 // 音频数据接收和解码由库在后台任务处理 delay(1000); }硬件连接与调试你需要一个I2S接口的音频DAC模块如MAX98357或直接使用ESP32开发板上的I2S引脚连接音频放大器。正确连接BCLK、LRC、DOUT三根线到对应模块。上传代码后用手机蓝牙搜索“ESP32_A2DP_Speaker”并连接然后在手机上播放音乐声音就会从你的功放喇叭输出。常见问题如果没有声音首先检查硬件连接和供电功放模块可能需要独立供电。其次检查I2S的采样率、位宽等配置是否与你的DAC模块匹配。可以在setup()中增加a2dp_sink.set_sample_rate(44100);等函数进行微调。5. 低功耗蓝牙实战构建一个温湿度传感器服务器BLE的开发思维与经典蓝牙不同它围绕“服务”和“特征值”展开。我们以一个标准的温湿度传感器为例创建一个包含温度和湿度数据的BLE服务。5.1 BLE GATT模型快速理解你可以把BLE设备服务器想象成一个提供信息的“橱窗”。服务橱窗里的一个柜台比如“环境数据柜台”。特征值柜台里具体摆放的商品比如“温度计”和“湿度计”。每个特征值都包含一个具体的数值。属性商品的标签标明这个商品是“只读的”传感器数据、“可写的”控制指令还是“可通知的”数据变化时主动推送。客户端浏览橱窗的顾客通常是手机APP它可以读取Read商品信息写入Write指令或者订阅通知Notify当商品信息更新时柜台会主动告诉顾客。5.2 创建温湿度BLE服务代码假设我们使用DHT11传感器但代码框架适用于任何传感器。#include BLEDevice.h #include BLEUtils.h #include BLEServer.h #include DHT.h #define DHTPIN 4 // DHT传感器数据引脚 #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); // 定义服务UUID和特征值UUID // 可以使用在线UUID生成器生成或使用标准的16位UUID #define SERVICE_UUID 4fafc201-1fb5-459e-8fcc-c5c9c331914b #define CHARACTERISTIC_UUID_TEMP beb5483e-36e1-4688-b7f5-ea07361b26a8 #define CHARACTERISTIC_UUID_HUMI beb5483e-36e1-4688-b7f5-ea07361b26a9 // 全局变量用于存储服务器、服务、特征值等对象指针 BLEServer* pServer NULL; BLECharacteristic* pCharacteristicTemp NULL; BLECharacteristic* pCharacteristicHumi NULL; bool deviceConnected false; bool oldDeviceConnected false; // 服务器回调类处理连接事件 class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected true; Serial.println(客户端已连接); }; void onDisconnect(BLEServer* pServer) { deviceConnected false; Serial.println(客户端已断开); // 断开后重新开始广播以便其他设备可以连接 pServer-getAdvertising()-start(); Serial.println(重新开始广播...); } }; void setup() { Serial.begin(115200); dht.begin(); Serial.println(启动BLE温湿度传感器...); // 1. 初始化BLE设备设置设备名称 BLEDevice::init(ESP32_BLE_Sensor); // 2. 创建BLE服务器并设置回调 pServer BLEDevice::createServer(); pServer-setCallbacks(new MyServerCallbacks()); // 3. 创建一个服务 BLEService *pService pServer-createService(SERVICE_UUID); // 4. 为服务创建特征值 // 温度特征值可读、可通知 pCharacteristicTemp pService-createCharacteristic( CHARACTERISTIC_UUID_TEMP, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY ); // 湿度特征值可读、可通知 pCharacteristicHumi pService-createCharacteristic( CHARACTERISTIC_UUID_HUMI, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY ); // 5. 启动服务 pService-start(); // 6. 开始广播让客户端能发现我们 BLEAdvertising *pAdvertising BLEDevice::getAdvertising(); pAdvertising-addServiceUUID(SERVICE_UUID); pAdvertising-setScanResponse(true); pAdvertising-setMinPreferred(0x06); // 有助于提高某些手机的连接成功率 pAdvertising-setMinPreferred(0x12); BLEDevice::startAdvertising(); Serial.println(设备正在广播等待客户端连接...); Serial.println(设备名称: ESP32_BLE_Sensor); } void loop() { // 处理连接状态变化 if (!deviceConnected oldDeviceConnected) { delay(500); // 给蓝牙栈一点时间 oldDeviceConnected deviceConnected; } if (deviceConnected !oldDeviceConnected) { oldDeviceConnected deviceConnected; } // 如果设备已连接则读取传感器数据并更新特征值 if (deviceConnected) { float humidity dht.readHumidity(); float temperature dht.readTemperature(); // 检查读数是否有效 if (isnan(humidity) || isnan(temperature)) { Serial.println(读取DHT传感器失败); return; } // 将浮点数转换为字符串以便通过BLE发送 char tempStr[8]; char humiStr[8]; dtostrf(temperature, 6, 2, tempStr); // 格式宽度6保留2位小数 dtostrf(humidity, 6, 2, humiStr); // 设置特征值 pCharacteristicTemp-setValue(tempStr); pCharacteristicHumi-setValue(humiStr); // 发送通知如果客户端订阅了 pCharacteristicTemp-notify(); pCharacteristicHumi-notify(); // 在串口打印数据 Serial.printf(温度: %s °C, 湿度: %s %%\n, tempStr, humiStr); // 每2秒更新一次 delay(2000); } }5.3 手机端测试与数据读取代码上传后你需要一个BLE扫描APP来测试。推荐使用nRF Connect或LightBlue。打开手机蓝牙和APP扫描设备找到名为“ESP32_BLE_Sensor”的设备并连接。连接后APP会列出该设备提供的服务。找到UUID为4fafc201...的服务。展开该服务你会看到两个特征值分别对应温度和湿度。点击“读”按钮可以手动读取当前值。点击“通知”图标通常是一个三个箭头环绕的符号启用通知。启用后每当ESP32更新数据代码中每2秒notify()一次手机APP就会自动收到并显示新的数值无需手动读取。核心技巧PROPERTY_NOTIFY属性配合notify()方法是BLE传感器应用的灵魂。它实现了服务器主动向客户端推送数据而不是让客户端不断轮询这既实时又节能。务必在特征值创建时添加此属性。6. 经典蓝牙与BLE的混合应用与深度优化在实际项目中我们可能需要根据场景切换模式或者对连接进行更精细的控制。6.1 模式管理与共存策略如前所述ESP32不能同时主动运行两种蓝牙协议栈。但我们可以通过程序逻辑来管理它们。策略一分时复用在setup()中根据条件初始化其中一种蓝牙在需要时完全停止它再初始化另一种。这比较耗时适合模式切换不频繁的场景。void switchToClassicBT() { // 如果BLE正在运行先释放资源 if (BLEDevice::getInitialized()) { BLEDevice::deinit(); delay(100); } // 初始化经典蓝牙 SerialBT.begin(ESP32_Switchable); } void switchToBLE() { // 如果经典蓝牙正在运行先结束 if (SerialBT.hasClient()) { // 如果有连接先断开 SerialBT.disconnect(); } SerialBT.end(); // 结束经典蓝牙 delay(100); // 初始化BLE BLEDevice::init(ESP32_Switchable); // ... 后续BLE服务器设置代码 }策略二主从模式选择在项目规划阶段就确定设备的主要角色。例如一个智能家居中控可能主要作为BLE服务器被传感器连接同时偶尔作为经典蓝牙客户端连接音响播放提示音。这时需要精心设计任务调度避免资源冲突。6.2 经典蓝牙的深度配置BluetoothSerial库提供了一些高级APISerialBT.register_callback()可以注册回调函数监听连接、断开、数据接收等事件。SerialBT.setPin()设置固定的蓝牙配对码提升安全性。SerialBT.disconnect()主动断开当前连接。SerialBT.available()和SerialBT.readBytes()用于读取不定长的数据包。示例设置配对码和处理连接事件#include BluetoothSerial.h BluetoothSerial SerialBT; // 连接状态回调 void btCallback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { if (event ESP_SPP_SRV_OPEN_EVT) { Serial.println(蓝牙客户端已连接); } else if (event ESP_SPP_CLOSE_EVT) { Serial.println(蓝牙客户端已断开); } } void setup() { Serial.begin(115200); SerialBT.register_callback(btCallback); // 注册回调 SerialBT.setPin(1234); // 设置配对码为1234 if (!SerialBT.begin(ESP32_Secure)) { Serial.println(蓝牙初始化失败); while(1); } Serial.println(蓝牙已启动配对码: 1234); }6.3 BLE的连接参数与安全配置BLE的连接间隔、延迟等参数直接影响功耗和响应速度。这些参数通常在连接时由客户端如手机发起协商但服务器可以给出偏好设置。// 在BLE服务器启动广播前可以设置连接参数 BLEAdvertising *pAdvertising pServer-getAdvertising(); pAdvertising-setMinInterval(0x20); // 最小连接间隔 0x20 * 1.25ms 40ms pAdvertising-setMaxInterval(0x40); // 最大连接间隔 0x40 * 1.25ms 80ms pAdvertising-setMinPreferred(0x06); // 这些值有助于某些iOS设备连接 pAdvertising-setMaxPreferred(0x12);安全性与绑定 对于需要安全通信的设备如智能锁可以使用BLE绑定。这需要在特征值上设置权限并在代码中实现配对请求处理。// 创建一个需要加密写操作的特征值 BLECharacteristic* pCharacteristicLock pService-createCharacteristic( CHAR_LOCK_UUID, BLECharacteristic::PROPERTY_WRITE_NR | // 加密写 BLECharacteristic::PROPERTY_READ ); // 设置安全权限 pCharacteristicLock-setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); // 在BLEDevice::init后设置IO能力例如仅显示密码 BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); BLEDevice::setSecurityCallbacks(new MySecurityCallbacks());实现完整的绑定流程较为复杂需要处理ESP_LE_AUTH_REQ_SC_MITM_BOND等安全请求事件。7. 常见问题排查与实战调试技巧调试蓝牙问题尤其是无线通信问题需要系统性的方法。以下是我总结的常见问题清单和排查步骤。7.1 通用问题排查表现象可能原因排查步骤手机搜不到设备1. 蓝牙未正确初始化。2. 设备未进入广播/可发现模式。3. 协议栈模式冲突之前运行了另一种蓝牙程序。4. 硬件问题。1. 检查串口输出确认初始化成功。2. 确认代码中执行了startAdvertising()或begin()。3.给ESP32完全断电重启再重新上传程序。这是最有效的办法之一。4. 换一部手机或电脑测试。可以搜索到但连接失败1. 配对码错误。2. 设备已达最大连接数。3. 系统蓝牙缓存冲突。1. 确认代码中设置的PIN码与手机输入一致经典蓝牙。BLE通常无需配对码。2. ESP32作为服务器有连接数限制。3. 在手机蓝牙设置中“忘记”该设备重新尝试。连接成功但无法收发数据1. 服务/特征值UUID不匹配。2. 未找到正确的服务或特征值。3. 数据格式错误。4. 未启用通知对于BLE数据接收。1. 使用nRF Connect确认手机读到的UUID与代码中定义的是否完全一致大小写敏感。2. 检查APP是否订阅了正确的特征值。3. 经典蓝牙检查串口波特率BLE检查setValue()的数据类型。4. 对于BLE在APP上手动点击“启用通知”。连接不稳定频繁断开1. 信号干扰WiFi、USB3.0、其他2.4G设备。2. 电源不稳定。3. 代码中有看门狗复位或崩溃。1. 远离路由器、USB3.0接口。尝试更换信道在WiFi代码中设置。2. 为ESP32提供独立、稳定的电源尤其是使用音频或电机等外设时。3. 检查串口日志是否有异常复位信息。编译错误BluetoothSerial.h: No such fileESP32 Arduino核心未正确安装或版本太旧。1. 检查开发板管理器中ESP32的版本更新到最新。2. 检查“工具”-“开发板”是否已选择正确的ESP32型号。7.2 高级调试手段串口日志与空中抓包1. 启用详细蓝牙日志在Arduino IDE中提高串口监视器的波特率如921600并在setup()最前面添加以下代码可以开启ESP32的蓝牙调试信息。注意这会输出大量信息仅用于深度调试。#include esp_bt.h #include esp_bt_main.h void setup() { Serial.begin(921600); // 设置蓝牙日志级别可选 esp_log_level_set(*, ESP_LOG_VERBOSE); // 输出所有级别的日志 // ... 你的蓝牙初始化代码 }2. 使用专业工具进行空中抓包硬件层面对于极其棘手的连接、协议问题可以使用专用的蓝牙嗅探器如Ellisys、Frontline或nRF Sniffer。nRF Sniffer相对亲民配合Wireshark可以直观看到广播包、连接请求、数据包等是定位协议层问题的终极武器。不过这需要额外的硬件投入和学习成本。7.3 功耗优化要点针对BLE项目如果你的项目是电池供电功耗至关重要。延长广播间隔在BLEAdvertising中设置setMinInterval()和setMaxInterval()为更大的值如100ms以上减少广播频率。优化连接参数与客户端协商更长的连接间隔Connection Interval如100ms以上。这需要在客户端手机APP也进行相应设置。使用深度睡眠在数据上报间隔很长时如每分钟一次可以让ESP32在两次广播或连接间隙进入深度睡眠模式此时功耗可降至微安级。但醒来后需要重新初始化蓝牙。关闭无用外设与功能在初始化蓝牙前确保关闭了未使用的WiFi、ADC、引脚上拉等。// 示例配置低功耗广播 BLEAdvertising *pAdvertising pServer-getAdvertising(); pAdvertising-setMinInterval(0x0640); // 1000ms 0x0640 * 0.625ms pAdvertising-setMaxInterval(0x0C80); // 2000ms pAdvertising-start();折腾ESP32的蓝牙功能从最初的“点灯”式通信到后来做出稳定可用的产品最大的体会就是无线通信的稳定性一半在代码一半在工程环境。代码逻辑要清晰错误处理要完备而物理环境中的电源质量、天线布局、外部干扰往往才是那些“玄学”问题的根源。我建议任何一个严肃的项目在原型阶段就要考虑电源滤波尽量使用板载PCB天线或外接天线的型号并远离强干扰源。最后多利用Serial.print()输出关键状态这是成本最低、最有效的调试方式。当你看到手机APP上稳定跳动的传感器数据或者听到从自己打造的蓝牙音箱里流出的音乐时那种成就感就是驱动我们这些开发者不断折腾的最好回报。

相关新闻