You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32 BLE外设无法被Android手机及Windows笔记本发现的技术求助

ESP32 MicroPython BLE外设无法被Android/Windows设备发现的解决办法

我在ESP32上使用MicroPython搭建BLE服务器,想要实现与中心设备(如智能手机或其他ESP32)的BLE通信,但ESP32无法被Android手机及Windows笔记本发现,以下是我使用的代码:

from machine import Pin
from machine import Timer
from time import sleep_ms
import ubluetooth

message = ""

class ESP32_BLE():
    def __init__(self, name):
        # Create internal objects for the onboard LED
        # blinking when no BLE device is connected
        # stable ON when connected
        self.led = Pin(2, Pin.OUT)
        self.timer1 = Timer(0)
        
        self.name = name
        self.ble = ubluetooth.BLE()
        self.ble.active(True)
        self.disconnected()
        self.ble.irq(self.ble_irq)
        self.register()
        self.advertiser()

    def connected(self):
        self.led.value(1)
        self.timer1.deinit()

    def disconnected(self):        
        self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))

    def ble_irq(self, event, data):
        global message
        
        if event == 1: #_IRQ_CENTRAL_CONNECT:
                       # A central has connected to this peripheral
            self.connected()

        elif event == 2: #_IRQ_CENTRAL_DISCONNECT:
                         # A central has disconnected from this peripheral.
            self.advertiser()
            self.disconnected()
        
        elif event == 3: #_IRQ_GATTS_WRITE:
                         # A client has written to this characteristic or descriptor.          
            buffer = self.ble.gatts_read(self.rx)
            message = buffer.decode('UTF-8').strip()
            print(message)
            
    def register(self):        
        # Nordic UART Service (NUS)
        NUS_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
        RX_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
        TX_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
            
        BLE_NUS = ubluetooth.UUID(NUS_UUID)
        BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
        BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
            
        BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
        SERVICES = (BLE_UART, )
        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)

    def send(self, data):
        self.ble.gatts_notify(0, self.tx, data + '\n')

    def advertiser(self):
        name = bytes(self.name, 'UTF-8')
        adv_data = bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name
        self.ble.gap_advertise(100, adv_data)
        print(adv_data)
        print("\r\n")
                # adv_data
                # raw: 0x02010209094553503332424C45
                # b'\x02\x01\x02\t\tESP32BLE'
                #
                # 0x02 - General discoverable mode
                # 0x01 - AD Type = 0x01
                # 0x02 - value = 0x02
                
                # https://jimmywongiot.com/2019/08/13/advertising-payload-format-on-ble/
                # https://docs.silabs.com/bluetooth/latest/general/adv-and-scanning/bluetooth-adv-data-basics



led = Pin(2, Pin.OUT)
but = Pin(0, Pin.IN)
ble = ESP32_BLE("ESP32")

def buttons_irq(pin):
    led.value(not led.value())
    ble.send('LED state will be toggled.')
    print('LED state will be toggled.')   
but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq)

while True:
    if message == "STATUS":
        message = ""
        print('LED is ON.' if led.value() else 'LED is OFF')
        ble.send('LED is ON.' if led.value() else 'LED is OFF')
    sleep_ms(100)

问题分析与修正方案

核心问题

  1. 广播模式配置错误:原代码中广播Flags设为0x02(有限可发现模式),仅在短时间内可被扫描,导致大部分设备无法持续发现它。
  2. 引脚资源冲突:全局和类内重复初始化Pin(2),可能导致LED控制异常。
  3. 广播间隔过小:100ms的广播间隔可能被部分系统过滤,降低设备被发现的概率。

修正后的代码

from machine import Pin
from machine import Timer
from time import sleep_ms
import ubluetooth

message = ""

class ESP32_BLE():
    def __init__(self, name):
        # 板载LED:未连接时闪烁,连接后常亮
        self.led = Pin(2, Pin.OUT)
        self.timer1 = Timer(0)
        
        self.name = name
        self.ble = ubluetooth.BLE()
        # 确认BLE激活状态,便于排查初始化问题
        ble_active = self.ble.active(True)
        print(f"BLE激活状态: {ble_active}")
        self.disconnected()
        self.ble.irq(self.ble_irq)
        self.register()
        self.advertiser()

    def connected(self):
        self.led.value(1)
        self.timer1.deinit()

    def disconnected(self):        
        # 降低闪烁频率,减少资源占用
        self.timer1.init(period=500, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))

    def ble_irq(self, event, data):
        global message
        
        if event == 1: #_IRQ_CENTRAL_CONNECT:
            self.connected()

        elif event == 2: #_IRQ_CENTRAL_DISCONNECT:
            self.disconnected()
            self.advertiser()
        
        elif event == 3: #_IRQ_GATTS_WRITE:
            buffer = self.ble.gatts_read(self.rx)
            message = buffer.decode('UTF-8').strip()
            print(message)
            
    def register(self):        
        # Nordic UART Service (NUS)
        NUS_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
        RX_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
        TX_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
            
        BLE_NUS = ubluetooth.UUID(NUS_UUID)
        BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
        BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
            
        BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
        SERVICES = (BLE_UART, )
        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)

    def send(self, data):
        self.ble.gatts_notify(0, self.tx, data + '\n')

    def advertiser(self):
        name = bytes(self.name, 'UTF-8')
        # 修改Flags为通用可发现模式(0x03 = 通用可发现 + 不支持BR/EDR)
        adv_data = bytearray(b'\x02\x01\x03') + bytearray((len(name) + 1, 0x09)) + name
        # 调整广播间隔为300ms,提升跨系统兼容性
        self.ble.gap_advertise(300, adv_data)
        print(f"广播数据: {adv_data}")


but = Pin(0, Pin.IN)
ble = ESP32_BLE("ESP32_BLE")

def buttons_irq(pin):
    ble.led.value(not ble.led.value())
    ble.send('LED状态已切换')
    print('LED状态已切换')   
but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq)

while True:
    if message == "STATUS":
        message = ""
        status_msg = 'LED已开启' if ble.led.value() else 'LED已关闭'
        print(status_msg)
        ble.send(status_msg)
    sleep_ms(100)

关键调整说明

  • 将广播Flags改为0x03,开启通用可发现模式,确保设备持续处于可扫描状态
  • 增大广播间隔至300ms,避免被系统过滤
  • 移除全局LED引脚初始化,避免资源冲突
  • 添加BLE激活状态打印,方便排查初始化故障
  • 统一中文提示信息,便于调试

内容的提问来源于stack exchange,提问作者Sahil Chabra09

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:17:06