tags: [source-summary] type: source source: "尚硅谷嵌入式技术之STM32单片机(高级篇)V2.0.1 — BLE章节 + 配套代码12" author: "尚硅谷研究院" date: 2026-07-15
用生活理解:BLE 就像一台"静音待机"的对讲机——平时完全关闭喇叭省电(休眠),每隔几秒悄悄喊一声"我在这呢"(广播)。当有人听到广播后说"跟我连个线吧"(连接请求),通信就建立起来了。连上之后也不是一直说,而是每隔 30ms 说一句(连接间隔),不说话时极低功耗。
| 特性 | 经典蓝牙 (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 频段,但调制方式和信道划分不同,互不兼容。
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 角色 | 行为 | 典型设备 |
|---|---|---|
| Broadcaster | 只发广播(不能连) | 信标(Beacon) |
| Observer | 只扫描广播(不连) | 扫描仪 |
| Peripheral | 广播 + 接受连接 | 传感器节点 |
| Central | 扫描 + 发起连接 | 手机、网关 |
典型连接流程:
Peripheral 广播 → Central 扫描到 → Central 发起连接请求
→ 连接建立 → 双方按连接间隔周期性交互数据 → 一方断开
BLE 的数据按以下层级组织:
Service (服务) 如 "心率服务" UUID: 0x180D
├── Characteristic 如 "心率测量" UUID: 0x2A37
│ ├── Properties read / write / notify / indicate
│ ├── Value 实际数据(心率值)
│ └── Descriptor 配置描述(如 CCCD 使能 notify)
└── Characteristic
├── ...
UUID(唯一标识符):
GATT 角色:
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=被动扫描 |
AT+BLEADVSTART