ESP32发射BLE iBeacon信号异常:无法被识别为iBeacon
ESP32发射BLE iBeacon信号无法被识别的问题排查
问题背景
使用**ESP32 Wroom32 DevKit V1/ESP32-D0WD-V3(v3.0版本)**开发板,搭配Arduino IDE(板管理器版本V2.0.7),尝试发射BLE iBeacon信号时出现异常:
- 设备可正常发出蓝牙信号,但无法被识别为iBeacon信号
- 全新裸板有时会出现晶振频率警告:
WARNING: Detected crystal freq 41.01MHz is quite different to normalized freq 40MHz. Unsupported crystal in use? Crystal is 40MHz - 使用默认ESP32 iBeacon Arduino示例代码(如下),上传和串口输出均正常,但nRF Connect应用仅将设备识别为普通蓝牙设备,无iBeacon属性:

所用代码
#include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> #include <BLEBeacon.h> #define DEVICE_NAME "ESP32" #define SERVICE_UUID "7A0247E7-8E88-409B-A959-AB5092DDB03E" #define BEACON_UUID "2D7A9F0C-E0E8-4CC9-A71B-A21DB2D034A1" #define BEACON_UUID_REV "A134D0B2-1DA2-1BA7-C94C-E8E00C9F7A2D" #define CHARACTERISTIC_UUID "82258BAA-DF72-47E8-99BC-B73D7ECD08A5" BLEServer *pServer; BLECharacteristic *pCharacteristic; bool deviceConnected = false; uint8_t value = 0; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; Serial.println("deviceConnected = true"); }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.println("deviceConnected = false"); // Restart advertising to be visible and connectable again BLEAdvertising* pAdvertising; pAdvertising = pServer->getAdvertising(); pAdvertising->start(); Serial.println("iBeacon advertising restarted"); } }; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { Serial.println("*********"); Serial.print("Received Value: "); for (int i = 0; i < rxValue.length(); i++) { Serial.print(rxValue[i]); } Serial.println(); Serial.println("*********"); } } }; void init_service() { BLEAdvertising* pAdvertising; pAdvertising = pServer->getAdvertising(); pAdvertising->stop(); // Create the BLE Service BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID)); // Create a BLE Characteristic pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY ); pCharacteristic->setCallbacks(new MyCallbacks()); pCharacteristic->addDescriptor(new BLE2902()); pAdvertising->addServiceUUID(BLEUUID(SERVICE_UUID)); // Start the service pService->start(); pAdvertising->start(); } void init_beacon() { BLEAdvertising* pAdvertising; pAdvertising = pServer->getAdvertising(); pAdvertising->stop(); // iBeacon BLEBeacon myBeacon; myBeacon.setManufacturerId(0x4c00); myBeacon.setMajor(5); myBeacon.setMinor(88); myBeacon.setSignalPower(0xc5); myBeacon.setProximityUUID(BLEUUID(BEACON_UUID_REV)); BLEAdvertisementData advertisementData; advertisementData.setFlags(0x1A); advertisementData.setManufacturerData(myBeacon.getData()); pAdvertising->setAdvertisementData(advertisementData); pAdvertising->start(); } void setup() { Serial.begin(115200); Serial.println(); Serial.println("Initializing..."); Serial.flush(); BLEDevice::init(DEVICE_NAME); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); init_service(); init_beacon(); Serial.println("iBeacon + service defined and advertising!"); } void loop() { if (deviceConnected) { Serial.printf("*** NOTIFY: %d ***\n", value); pCharacteristic->setValue(&value, 1); pCharacteristic->notify(); value++; } delay(2000); }
问题排查与解决建议
1. 广播数据被覆盖(核心问题)
代码中先调用init_service()启动了带服务UUID的广播,之后调用init_beacon()设置iBeacon广播,但ESP32的BLE广播配置会被最后一次调用覆盖,且init_service()中添加的服务UUID会破坏iBeacon的标准广播格式——iBeacon要求主广播包仅包含苹果0x4C00厂商ID的制造商特定数据,不能混入服务UUID、设备名称等内容。
修复方法:
- 删除
init_service()中的pAdvertising->addServiceUUID(BLEUUID(SERVICE_UUID));语句 - 调整初始化逻辑,将服务信息放在扫描响应包中,主广播包仅保留iBeacon数据(示例见下文修正代码)
2. UUID字节序问题
你定义了反转后的BEACON_UUID_REV,但BLEBeacon的setProximityUUID默认接受标准大端序UUID,尝试直接使用原始的BEACON_UUID替换BEACON_UUID_REV,验证是否能被识别。
3. 晶振频率警告处理
该警告一般不会直接导致iBeacon无法识别,但可能影响BLE稳定性。解决方法:
- 在Arduino IDE的
工具 > 晶振频率中选择40MHz - 若无效,在代码开头添加宏定义强制指定晶振参数:
#define CONFIG_ESP32_XTAL_FREQ 40
4. 断开重连后的广播恢复
onDisconnect回调中重启广播时,使用的是之前的配置,可能不是iBeacon格式。需在回调中重新设置iBeacon广播数据,或确保初始化时的广播配置为最终iBeacon格式。
修正后的核心代码示例
合并初始化逻辑,将服务信息放入扫描响应包,主广播仅保留iBeacon数据:
void init_beacon_and_service() { BLEAdvertising* pAdvertising = pServer->getAdvertising(); pAdvertising->stop(); // 初始化BLE服务 BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID)); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY ); pCharacteristic->setCallbacks(new MyCallbacks()); pCharacteristic->addDescriptor(new BLE2902()); pService->start(); // 配置iBeacon主广播包 BLEBeacon myBeacon; myBeacon.setManufacturerId(0x4c00); myBeacon.setMajor(5); myBeacon.setMinor(88); myBeacon.setSignalPower(0xc5); myBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); // 使用原始UUID BLEAdvertisementData advertisementData; advertisementData.setFlags(0x1A); advertisementData.setManufacturerData(myBeacon.getData()); pAdvertising->setAdvertisementData(advertisementData); // 配置扫描响应包,携带服务UUID和设备名称 BLEAdvertisementData scanResponseData; scanResponseData.setName(DEVICE_NAME); scanResponseData.addServiceUUID(BLEUUID(SERVICE_UUID)); pAdvertising->setScanResponseData(scanResponseData); pAdvertising->start(); } // 修改setup函数,替换原有的init_service()和init_beacon() void setup() { Serial.begin(115200); Serial.println(); Serial.println("Initializing..."); Serial.flush(); BLEDevice::init(DEVICE_NAME); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); init_beacon_and_service(); Serial.println("iBeacon + service defined and advertising!"); }
内容的提问来源于stack exchange,提问作者shutteltje
相关产品推荐
相关产品推荐

