Skip to content

蓝牙模组产品概览

BLE 技术基础

BLE(Bluetooth Low Energy,低功耗蓝牙)是蓝牙 4.0 引入的低功耗版本,专为 IoT 设计。

BLE vs 经典蓝牙

特性经典蓝牙(BR/EDR)BLE
速率1-3Mbps125kbps-2Mbps
功耗高(1W)极低(1mW)
延迟100ms6ms
覆盖10-100m10-400m
主要用途音频、文件传输IoT 传感器、可穿戴
配对时间慢(秒级)快(毫秒级)

BLE 5.x 新特性

版本新增特性关键改进
BLE 5.02× 速率、4× 覆盖、8× 广播容量长距离模式(125kbps,+20dB)
BLE 5.1方向查找(AoA/AoD)厘米级室内定位
BLE 5.2LE Audio、EATT低功耗音频、多流传输
BLE 5.3增强连接更新更低功耗
BLE 5.4广播加密安全性提升

移远 BLE 产品

移远的 BLE 模组主要以组合形式出现(BLE + 蜂窝 或 BLE + Wi-Fi):

型号BLE 版本组合芯片特点
BG95-MiniBLE 5.0NB-IoT + Cat.M + BLE高通超小尺寸
BC660KBLE 5.0NB-IoT + BLE高通低功耗
FC41DBLE 5.0Wi-Fi 6 + BLE联发科高速组合

BLE 协议栈

GATT 架构

GATT(Generic Attribute Profile)是 BLE 数据交换的核心:

Profile(配置文件)
  └── Service(服务)
        └── Characteristic(特征值)
              ├── Value(值)
              ├── Descriptor(描述符)
              └── Properties(属性:Read/Write/Notify/Indicate)

示例:心率服务(Heart Rate Service)
  Service UUID: 0x180D
    Characteristic: Heart Rate Measurement(0x2A37)
      Properties: Notify
      Value: [心率值, RR间期...]
    Characteristic: Body Sensor Location(0x2A38)
      Properties: Read
      Value: [位置:手腕/胸部/手指...]

BLE 广播(Advertising)

BLE 广播用于设备发现和数据广播(无需连接):

广播类型:
  ADV_IND:可连接无向广播(最常用)
  ADV_NONCONN_IND:不可连接广播(Beacon)
  ADV_DIRECT_IND:可连接定向广播
  
广播数据格式(AD Structure):
  Length | Type | Data
  
  常用 Type:
  0x01:Flags(LE General Discoverable Mode)
  0x02/0x03:16位 UUID 列表
  0x08/0x09:设备名称(缩写/完整)
  0xFF:厂商自定义数据(iBeacon 使用此类型)
  
iBeacon 数据格式:
  公司标识:0x004C(Apple)
  类型:0x02
  长度:0x15
  UUID:16字节
  Major:2字节
  Minor:2字节
  TX Power:1字节(用于距离估算)

BLE 开发示例

Python BLE 扫描(树莓派/Linux)

python
import asyncio
from bleak import BleakScanner, BleakClient

async def scan_devices():
    """扫描附近 BLE 设备"""
    print("扫描 BLE 设备...")
    devices = await BleakScanner.discover(timeout=5.0)
    
    for device in devices:
        print(f"设备: {device.name or '未知'}")
        print(f"  地址: {device.address}")
        print(f"  RSSI: {device.rssi} dBm")
        print(f"  距离估算: {estimate_distance(device.rssi):.1f} m")
        print()

def estimate_distance(rssi, tx_power=-59, n=2.0):
    """基于 RSSI 估算距离(粗略)"""
    if rssi == 0:
        return -1
    ratio = rssi / tx_power
    if ratio < 1.0:
        return ratio ** 10
    else:
        return 0.89976 * (ratio ** 7.7095) + 0.111

async def read_heart_rate(device_address):
    """读取心率设备数据"""
    HEART_RATE_SERVICE = "0000180d-0000-1000-8000-00805f9b34fb"
    HEART_RATE_CHAR = "00002a37-0000-1000-8000-00805f9b34fb"
    
    async with BleakClient(device_address) as client:
        print(f"已连接: {device_address}")
        
        # 读取设备信息
        services = await client.get_services()
        
        # 订阅心率通知
        def heart_rate_handler(sender, data):
            # 解析心率数据
            flags = data[0]
            if flags & 0x01:  # 16位心率值
                heart_rate = int.from_bytes(data[1:3], 'little')
            else:  # 8位心率值
                heart_rate = data[1]
            print(f"心率: {heart_rate} bpm")
        
        await client.start_notify(HEART_RATE_CHAR, heart_rate_handler)
        await asyncio.sleep(30)  # 监听30秒
        await client.stop_notify(HEART_RATE_CHAR)

asyncio.run(scan_devices())

Android BLE 开发

java
// Android BLE 扫描和连接
public class BLEManager {
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothLeScanner scanner;
    private BluetoothGatt gatt;
    
    // 扫描回调
    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BluetoothDevice device = result.getDevice();
            int rssi = result.getRssi();
            
            Log.d("BLE", "Found: " + device.getName() + 
                  " (" + device.getAddress() + ") RSSI: " + rssi);
            
            // 找到目标设备后连接
            if ("MyDevice".equals(device.getName())) {
                scanner.stopScan(scanCallback);
                connectToDevice(device);
            }
        }
    };
    
    public void startScan() {
        ScanSettings settings = new ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .build();
        
        scanner.startScan(null, settings, scanCallback);
    }
    
    private void connectToDevice(BluetoothDevice device) {
        gatt = device.connectGatt(context, false, new BluetoothGattCallback() {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, 
                                                int status, int newState) {
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    Log.d("BLE", "Connected!");
                    gatt.discoverServices();
                }
            }
            
            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                // 获取心率服务
                BluetoothGattService hrService = gatt.getService(
                    UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb")
                );
                
                if (hrService != null) {
                    BluetoothGattCharacteristic hrChar = hrService.getCharacteristic(
                        UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")
                    );
                    
                    // 开启通知
                    gatt.setCharacteristicNotification(hrChar, true);
                }
            }
            
            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt,
                                                BluetoothGattCharacteristic characteristic) {
                byte[] data = characteristic.getValue();
                int heartRate = data[1] & 0xFF;
                Log.d("BLE", "Heart Rate: " + heartRate + " bpm");
            }
        });
    }
}

褚成志的笔记