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


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

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/12_ble_server_hal

ESP32-C3 同时支持 WiFi 和 BLE。BLE 实验使用 ESP32-C3 的 BLE 功能作为 GATT Server(从机),通过串口 AT 指令控制。ble.c 中包含了完整的 BLE 初始化流程和 SPP 透传模式切换。

软件设计

文件:stm32/12_ble_server_hal/Core/Src/main.c

#include "main.h"
#include "usart.h"
#include "gpio.h"

#include "ble.h"

uint8_t rxBuff[1024];
uint16_t rxLen;

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  printf("尚硅谷BLE实验...\n");

  BLE_Init();

  while (1)
  {
    BLE_ReadData(rxBuff, &rxLen);

    if (rxLen > 0)
    {
      printf("收到数据:数据长度 = %d, 内容 = %.*s\n", rxLen, rxLen, rxBuff);

      BLE_SendData(rxBuff, rxLen);
      rxLen = 0;
    }
  }
}

文件:stm32/12_ble_server_hal/App/BLE/ble.h

#ifndef __BLE_H
#define __BLE_H

#include "esp32.h"

void BLE_Init(void);
void BLE_SendData(uint8_t txBuff[], uint16_t txLen);
void BLE_ReadData(uint8_t rxBuff[], uint16_t *rxLen);

#endif

文件:stm32/12_ble_server_hal/App/BLE/ble.c(包含完整的 BLE AT 指令序列和 SPP 透传处理):

#include "ble.h"

void BLE_Init(void)
{
    ESP32_Init();

    // 1. 设置蓝牙角色为 Peripheral(服务器)
    printf("设置蓝牙角色为服务器...\n");
    uint8_t *cmd = "AT+BLEINIT=2\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 2. 创建 GATT 服务
    printf("创建GATT服务...\n");
    cmd = "AT+BLEGATTSSRVCRE\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 3. 启动 GATT 服务
    printf("启动GATT服务...\n");
    cmd = "AT+BLEGATTSSRVSTART\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 4. 获取本机 MAC 地址
    printf("获取本机MAC地址...\n");
    cmd = "AT+BLEADDR?\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 5. 配置广播参数
    //    参数含义:最小间隔,最大间隔,广播类型,过滤策略,信道,广播策略
    //    最小/最大间隔单位 0.625ms,50 = 31.25ms
    printf("配置广播参数...\n");
    cmd = "AT+BLEADVPARAM=50,50,0,0,7,0\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 6. 设置广播数据
    //    参数:设备名,自定义UUID,厂商数据,长度类型
    printf("设置广播数据...\n");
    cmd = "AT+BLEADVDATAEX=\"atguigu-ble\",\"A123\",\"0102030405\",1\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 7. 开始广播
    printf("开始广播...\n");
    cmd = "AT+BLEADVSTART\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 8. 配置 BLE SPP 透传参数
    //    参数含义:SPP使能,最大连接数,MTU大小,是否使能通知,分段大小
    printf("配置 BLE SPP 参数...\n");
    cmd = "AT+BLESPPCFG=1,1,7,1,5\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 9. 设置系统消息指示
    //    4 = 只输出连接/断开事件通知
    printf("设置系统提示信息...\n");
    cmd = "AT+SYSMSG=4\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));
}

void BLE_SendData(uint8_t txBuff[], uint16_t txLen)
{
    HAL_UART_Transmit(&huart2, txBuff, txLen, 1000);
}

static uint8_t BLE_IsConnChanged(uint8_t msg[]);

void BLE_ReadData(uint8_t rxBuff[], uint16_t *rxLen)
{
    HAL_UARTEx_ReceiveToIdle(&huart2, rxBuff, 1024, rxLen, 1000);

    if (*rxLen == 0)
        return;

    if ( BLE_IsConnChanged(rxBuff) )
        *rxLen = 0;
}

static uint8_t BLE_IsConnChanged(uint8_t msg[])
{
    // 收到 +BLECONN: 连接建立 → 进入 SPP 透传
    if (strstr((char *)msg, "+BLECONN:") != NULL)
    {
        printf("有BLE客户端连接,准备进入SPP模式...\n");
        uint8_t * cmd = "AT+BLESPP\r\n";
        ESP32_SendCmd(cmd, strlen((char *)cmd));
        return 1;
    }
    // 收到 +BLEDISCONN: 断开连接 → 退出 SPP 透传
    else if (strstr((char *)msg, "+BLEDISCONN:") != NULL)
    {
        printf("BLE客户端断开连接,准备退出SPP模式...\n");
        HAL_UART_Transmit(&huart2, "+++", 3, 1000);
        HAL_Delay(2000);
        return 1;
    }
    // 过滤 WiFi 网络事件(ESP32-C3 为 WiFi+BLE 双模芯片)
    else if(strstr((char *)msg, "WIFI CONNECTED") != NULL
        || strstr((char *)msg, "WIFI GOT IP") != NULL
        || strstr((char *)msg, "+DIST_STA_IP:") != NULL)
    {
        return 1;
    }

    return 0;
}

核心速查表

BLE 操作 AT 指令 说明
GATT Server 初始化(从机) AT+BLEINIT=2 2=从机模式
GATT Client 初始化(主机) AT+BLEINIT=1 1=主机模式
创建 GATT 服务 AT+BLEGATTSSRVCRE 创建标准服务
启动 GATT 服务 AT+BLEGATTSSRVSTART 服务上线
获取 MAC 地址 AT+BLEADDR? 查询本机地址
设置名称 AT+BLENAME="name" 最长 29 字节
设置广播间隔 AT+BLEADVPARAM=min,max,... 单位 0.625ms
设置广播数据 AT+BLEADVDATAEX="name","uuid","data",1 16 进制字符串
开始广播 AT+BLEADVSTART Peripheral 模式
停止广播 AT+BLEADVSTOP
发送数据(非透传) AT+BLESEND=conn,len → 数据
SPP 透传配置 AT+BLESPPCFG=1,1,7,1,5 使能透传
进入 SPP 透传 AT+BLESPP 连接之后调用
退出透传 +++(无换行,20ms 间隔)
查询连接状态 AT+BLECONN? 返回当前连接
断开连接 AT+BLEDISCONN=n n=连接 ID
扫描设备 AT+BLESCAN=0 0=被动扫描
连接事件通知 AT+SYSMSG=4 仅输出连接/断开

常见问题与避坑

  1. 手机扫描不到设备 → 检查广播是否启动、名称是否设置、广播功率是否太低
  2. 连接后数据发不出去 → 确保 GATT Server 已启动、SPP 使能配置正确、MTU 大小
  3. 功耗高 → 广播间隔增大(100ms+)、连接间隔增大(30ms+)、不用时停止广播
  4. 断开连接后需要显式重连 → BLE 不会自动重连,Peripheral 需重新调用 AT+BLEADVSTART
  5. SPP 透传意外退出 → 数据中不能出现连续 +++,否则会被误判为退出命令
  6. WiFi+BLE 同芯片干扰 → ESP32-C3 是单射频双模,BLE 通信时 WiFi 性能会下降