16-BLE低功耗蓝牙.md 6.4 KB


tags: [source-summary] type: source source: "尚硅谷嵌入式技术之STM32单片机(高级篇)V2.0.1 — BLE章节 + 配套代码12" author: "尚硅谷研究院" date: 2026-07-15

created: 2026-07-15

BLE低功耗蓝牙

用生活理解:BLE 就像一台"静音待机"的对讲机——平时完全关闭喇叭省电(休眠),每隔几秒悄悄喊一声"我在这呢"(广播)。当有人听到广播后说"跟我连个线吧"(连接请求),通信就建立起来了。连上之后也不是一直说,而是每隔 30ms 说一句(连接间隔),不说话时极低功耗。


BLE vs 经典蓝牙

特性 经典蓝牙 (BR/EDR) BLE (Bluetooth Low Energy)
功耗 ~1W(持续发送) ~0.01W(广播时 5~10mA,休眠时 μA 级)
峰值速率 1~3 Mbps 125Kbps~2Mbps
连接延迟 ~100ms ~3ms
数据包 长包(可达 339 字节) 短包(最大 251 字节 ATT MTU)
信道 79 个 1MHz 信道 40 个 2MHz 信道(3 个广播 + 37 个数据)
语音 支持(SCO 链路) 不支持(需通过协议栈上层实现)
主要应用 音频流、文件传输 IoT、传感器、可穿戴设备

BLE 和经典蓝牙工作在相同 2.4GHz ISM 频段,但调制方式和信道划分不同,互不兼容。


BLE 协议栈架构

Application(应用层)
    ↓
GAP (Generic Access Profile) — 广播、扫描、连接、角色
GATT (Generic Attribute Profile) — 数据读写、服务/特征值结构
    ↓
ATT (Attribute Protocol) — 属性读/写/通知/指示
L2CAP (Logical Link Control and Adaptation Protocol) — 数据分包/重组
    ↓
HCI (Host Controller Interface) — 主机与控制器通信接口
    ↓
Link Layer (链路层) — 广播/数据信道管理、加密
Physical Layer (物理层) — 2.4GHz GFSK 调制

GAP 角色模型

GAP 角色 行为 典型设备
Broadcaster 只发广播(不能连) 信标(Beacon)
Observer 只扫描广播(不连) 扫描仪
Peripheral 广播 + 接受连接 传感器节点
Central 扫描 + 发起连接 手机、网关

典型连接流程

Peripheral 广播 → Central 扫描到 → Central 发起连接请求
→ 连接建立 → 双方按连接间隔周期性交互数据 → 一方断开

GATT 数据架构

BLE 的数据按以下层级组织:

Service (服务)         如 "心率服务" UUID: 0x180D
├── Characteristic     如 "心率测量" UUID: 0x2A37
│   ├── Properties       read / write / notify / indicate
│   ├── Value            实际数据(心率值)
│   └── Descriptor       配置描述(如 CCCD 使能 notify)
└── Characteristic
    ├── ...

UUID(唯一标识符)

  • 16 位标准 UUID:由 Bluetooth SIG 定义(0x180D = 心率服务)
  • 128 位自定义 UUID:用户自定义服务/特征

GATT 角色

  • GATT Server:提供数据(如传感器)
  • GATT Client:读写数据(如手机 App)

实验:STM32 + BLE 模块通信

STM32 通过串口连接 BLE 透传模块(支持 AT 指令),实现 BLE 数据收发。

项目路径stm32/12_ble_server_hal

软件设计

// BLE 模块初始化(Peripheral 模式 + 广播)
void BLE_Init(void)
{
    // 1. 设置为 Peripheral(从机)模式
    AT_SendCmd("AT+BLEINIT=2\r\n", "OK", 2000);
    // AT+BLEINIT: 0=关闭BLE, 1=Central, 2=Peripheral

    // 2. 设置设备名称(广播时显示)
    AT_SendCmd("AT+BLENAME=\"STM32_BLE_Device\"\r\n", "OK", 1000);

    // 3. 设置广播间隔(单位 0.625ms,默认 100 = 62.5ms)
    AT_SendCmd("AT+BADVINT=100\r\n", "OK", 1000);
    // 值越小 → 被发现越快 → 功耗越高

    // 4. 设置广播数据(自定义数据)
    AT_SendCmd("AT+BLEADVDATA=\"020106\"\r\n", "OK", 1000);
    // 02=长度, 01=标志类型, 06=LE General Discoverable + BR/EDR Not Support

    // 5. 启动广播
    AT_SendCmd("AT+BLEADVSTART\r\n", "OK", 2000);
    printf("BLE 广播中...\r\n");
}

// 发送数据(通过 GATT 通知)
void BLE_SendData(uint8_t *data, uint16_t len)
{
    char cmd[64];
    // 格式: AT+BLESEND=conn_id,len\r\n
    // 之后发送 len 字节的数据
    sprintf(cmd, "AT+BLESEND=0,%d\r\n", len);
    AT_SendCmd(cmd, ">", 3000);

    // 发送实际数据
    HAL_UART_Transmit(&huart2, data, len, 1000);
}

// BLE 数据接收(串口主动上报)
// 当手机发送数据给 STM32 时,BLE 模块通过串口上报:
// +BLEDATA: conn_id,len,data
void BLE_ProcessRxData(uint8_t *buffer, uint16_t len)
{
    if (strstr((char *)buffer, "+BLEDATA:"))
    {
        // 解析数据并处理
        char *data_ptr = strstr((char *)buffer, ",");
        if (data_ptr)
        {
            data_ptr = strstr(data_ptr + 1, ",");
            if (data_ptr)
            {
                data_ptr++;  // 跳过逗号,指向实际数据
                printf("Received BLE: %s\r\n", data_ptr);
            }
        }
    }
}

核心速查表

BLE 操作 AT 指令 说明
初始化(Peripheral) AT+BLEINIT=2 2=从机模式
初始化(Central) AT+BLEINIT=1 1=主机模式
设置名称 AT+BLENAME="name" 最长 29 字节
设置广播间隔 AT+BADVINT=N N×0.625ms,默认 100 (62.5ms)
设置广播数据 AT+BLEADVDATA="hex" 16 进制字符串
开始广播 AT+BLEADVSTART Peripheral 模式
停止广播 AT+BLEADVSTOP
发送数据 AT+BLESEND=conn,len → 数据
查询连接状态 AT+BLECONN? 返回当前连接
断开连接 AT+BLEDISCONN=n n=连接 ID
扫描设备 AT+BLESCAN=0 0=被动扫描

常见问题与避坑

  1. 手机扫描不到设备 → 检查广播是否启动、名称是否设置、广播功率是否太低
  2. 连接后数据发不出去 → 确保 GATT Server 已启动、通知/写属性已配置、MTU 大小(默认 23 字节)
  3. 功耗高 → 广播间隔增大(100ms+)、连接间隔增大(30ms+)、不用时停止广播
  4. 断开连接后需要显式重连 → BLE 不会自动重连,Peripheral 需重新调用 AT+BLEADVSTART
  5. 连接间隔与功耗的关系:间隔越短→延迟越低→功耗越高;传感器场景推荐 30~50ms