16-BLE低功耗蓝牙.md 7.9 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

软件设计

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

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ble.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

// 全局变量定义,数据缓冲区及其长度
uint8_t rxBuff[1024];
uint16_t rxLen;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  // MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

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

  // BLE初始化
  BLE_Init();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    // 读取数据
    BLE_ReadData(rxBuff, &rxLen);

    // 如果收到数据,原样发送回去
    if (rxLen > 0)
    {
      printf("收到数据:数据长度 = %d, 内容 = %.*s\n", rxLen, rxLen, rxBuff);

      BLE_SendData(rxBuff, rxLen);

      // 清空长度0
      rxLen = 0;
    }
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

核心速查表

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