概述
BLE(Bluetooth Low Energy,低功耗蓝牙,蓝牙技术里专为省电设计的版本:功耗低、连接快、只传小数据)是物联网设备最常用的近距离无线通信方式。Ai-WB2 模组内置 BLE 4.2 蓝牙协议栈,可同时与 Wi-Fi 工作:Wi-Fi 负责大流量联网,BLE 负责轻量连接。本页是 BLE 系列的概念篇,先讲清楚 BLE 世界里的「角色」和「规矩」,为后面的动手教程打基础;本系列共 5 篇,从本页开始,依次为 iBeacon 广播 → BLE 主机 → BLE 从机 → blufi 配网。
用大白话讲:BLE 就像一个小巧省电的「信使」。普通蓝牙像大功率广播站,费电、能传大文件;BLE 像低声细语的信使,省电、只传小数据。通信过程像「交朋友」:一方先广播(像大喇叭喊话:「我在这里!」),另一方扫描听到后过来连接,连上之后双方按约定的规矩(GATT)互相递纸条。你的手环、耳机、遥控器用的都是这套流程。
本教程基于安信可官方 SDK(Ai-Thinker-Open/Ai-Thinker-WB2,版本
release_bl_iot_sdk_1.6.40),本系列全部示例来自官方applications/bluetooth/目录,代码可在本地 SDK 中直接找到。
- BLE(Bluetooth Low Energy,低功耗蓝牙)是蓝牙技术里专为省电设计的版本:连接快、功耗低、只传小数据。你的手机、手环、耳机用的就是它。
- 与普通「经典蓝牙」(传音频/文件,费电)相比,BLE 就像「低声细语的信使」:跑腿少、耗电小,特别适合传感器、遥控器这类用电池的小设备。
💡 Ai-WB2 的 Wi-Fi 和 BLE 可以同时工作、互不干扰:Wi-Fi 负责大流量联网,BLE 负责轻量连接(比如下面的配网)。
- 广播(Advertising):从机间隔一定时间向外发送一小包数据(含设备名、MAC 地址、自定义内容),就像大喇叭喊话:「我在这里,我是 XX!」。广播不建立连接,谁都能听到。
- 扫描(Scanning):主机打开「耳朵」听周围谁在喊话,拿到广播内容后决定要不要过来连接。
💡 iBeacon(苹果推出的蓝牙信标方案)就只广播不连接,像路边广告牌——路人看得到内容,但不用和它「握手」。本系列 iBeacon 教程 会亲手实现它。
- GATT(Generic Attribute Profile)是蓝牙设备之间通信的「规矩」:规定数据怎么组织、怎么读写。BLE 设备连上后,就按这套规矩交换数据。
- GATT 里的数据按层级组织,像「App 里的应用 → 按钮」:
- 服务 Service:一个功能模块(如「心率服务」「电池服务」),相当于手机里的一个 App。
- 特征值 Characteristic:服务里的具体开关或数据(如「心率数值」「电量百分比」),相当于 App 里的一个按钮或文本框。
- 和某台设备通信的步骤就是:找到它有哪些服务 → 找到服务里的特征值 → 读写特征值。就像先打开 App,再点里面的按钮。
💡 本系列 BLE 从机 教程会注册一个自定义服务,用手机 App 读写它的特征值,体会这套「规矩」。
- UUID(Universally Unique Identifier,通用唯一标识符):蓝牙世界的「身份证号」,16 字节,写作
B9407F30-F5F8-466E-AFF9-25556B57FE6D这种格式,用来唯一标识某个服务或特征值。 - MAC 地址:每台蓝牙设备的「门牌号」(6 字节,如
88:88:88:88:88:88),主机靠它找到并连接特定设备。
| 名词 | 大白话 | 干什么用 |
|---|---|---|
| UUID | 身份证号 | 标识服务/特征值,告诉别人「这个数据是什么」 |
| MAC 地址 | 门牌号 | 标识设备,告诉别人「我是哪台设备」 |
概念就位,接下来 4 篇全部动手(顺序即侧边栏顺序):
- iBeacon 广播:让开发板化身「路边广告牌」,只广播不连接
- BLE 主机:开发板当「手机」,主动扫描连接从机并双向透传数据
- BLE 从机:开发板当「手环」,提供透传服务,等手机/主机来连接
- blufi 配网:用手机 App 通过蓝牙给开发板「录入」Wi-Fi 账号密码(配网,把 Wi-Fi 账号密码发给设备的过程,像给门锁录入指纹)
📜 想看「一个 BLE 程序长什么样」?文末 完整代码 预览了官方 iBeacon 示例的入口代码,逐行讲解见 iBeacon 教程。
本文 API 汇总
本页为概念篇,未运行任何代码;下面预览本系列动手教程即将用到的核心 BLE API(签名与官方 SDK 头文件一致,详细讲解见各篇):
ble_controller_init(task_priority)
初始化 BLE 协议栈(蓝牙通信的「大脑」),是 BLE 代码的第一步。
参数:
task_priority:协议栈任务优先级(uint8_t),官方示例传configMAX_PRIORITIES - 1(最高优先级)
返回值:无
bt_enable(cb)
打开蓝牙协议栈,相当于手机「打开蓝牙开关」。
参数:
cb:协议栈就绪回调(bt_ready_cb_t),形如void cb(int err),不需要可传NULL
返回值:成功返回 0;失败返回负值错误码
bt_le_adv_start(param, ad, ad_len, sd, sd_len)
开始 BLE 广播(「大喇叭喊话」),广播数据由 ad 数组指定。
参数:
param:广播参数结构体指针(bt_le_adv_param_t),含广播间隔、可连接选项等ad:广播数据数组(bt_data_t),必填ad_len:广播数据条数sd:扫描应答数据数组,不需要传NULLsd_len:扫描应答数据条数,传0
返回值:成功返回 0;失败返回负值错误码
完整代码
本页为概念介绍页,本身没有示例工程;这里预览官方 iBeacon 示例工程 的 main.c 入口代码,与官方示例(applications/bluetooth/ble_ibeacon/ble_ibeacon/main.c)完全一致,让你对「一个 BLE 程序长什么样」有直观印象,逐行讲解见 iBeacon 教程:
📜 点击展开 iBeacon 示例 main.c 完整代码(预览)
/*
* Copyright (c) 2020 Bouffalolab.
*
* This file is part of
* *** Bouffalolab Software Dev Kit ***
* (see www.bouffalolab.com).
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Bouffalo Lab nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <blog.h>
#include <stdio.h>
#include <cli.h>
#include <blog.h>
#include <bl_uart.h>
#include <bl_sys.h>
#include "hci_driver.h"
#include "ble_lib_api.h"
#include "bluetooth.h"
#include "gatt.h"
#include "uuid.h"
#include <hosal_uart.h>
#define PRIORITIE_OFFSET 4
/*set ibeacon name*/
#define IBEACON_NAME "MY_IBEACON"
/*ibeacon data*/
char my_ibeacon[]=
{
0x4C, 0x00, //公司的标志 (0x004C == Apple)
0x02, 0x15, //iBeacon advertisement indicator
0xB9, 0x40, 0x7F, 0x30, 0xF5, 0xF8, 0x46, 0x6E, 0xAF, 0xF9, 0x25, 0x55, 0x6B, 0x57, 0xFE, 0x6D, // iBeacon proximity uuid
0x00, 0x01, // major
0x00, 0x01, // minor
0xc5 //power
};
static struct bt_data ibeacon_data[2] =
{
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA(BT_DATA_MANUFACTURER_DATA, my_ibeacon, sizeof(my_ibeacon)),//
};
/*start ble advertise*/
void ble_start_advertise(void)
{
struct bt_le_adv_param param;
param.id = BT_ID_DEFAULT;
param.interval_min = BT_GAP_ADV_FAST_INT_MIN_2;
param.interval_max = BT_GAP_ADV_FAST_INT_MAX_2;
//param.options = BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME;
param.options = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME;
/*Get mode, 0:General discoverable, 1:non discoverable, 2:limit discoverable*/
bt_le_adv_start(¶m,ibeacon_data, ARRAY_SIZE(ibeacon_data),NULL,0);
bt_set_name(IBEACON_NAME);
}
/*BLE ibeacon init*/
void ble_ibeacon_init(void)
{
printf("ble_controller_init\r\n");
ble_controller_init(configMAX_PRIORITIES - 1); //ble协议栈初始化
printf("hci_driver_init\r\n");
hci_driver_init();//初始化驱动
printf("bt_enable\r\n");
bt_enable(NULL);
ble_start_advertise();//开启广播
}
static void app_init_thread(void *param)
{
vTaskDelay(10 / portTICK_RATE_MS);
ble_ibeacon_init();
vTaskDelete(NULL);
}
static void app_init_entry(void)
{
if(xTaskCreate(app_init_thread, ((const char*)"app_init"), 1024*6, NULL, tskIDLE_PRIORITY + 3 + PRIORITIE_OFFSET, NULL) != pdPASS)
printf("\n\r%s xTaskCreate(init_thread) failed", __FUNCTION__);
}
static void ble_loop_proc(void *pvParameters)
{
app_init_entry();
vTaskDelete(NULL);
}
void main(void)
{
bl_uart_init(0, 16, 7, 255, 255, 115200);//set uart baud 115200
printf("AXK BLE IBEACON\r\n");//log
bl_sys_init(); //if use ble,must init
xTaskCreate(ble_loop_proc, (char*)"ibeacon", 1024, NULL, 15, NULL);
}常见问题与踩坑提示
⚠️ BLE 和普通蓝牙有什么区别
原因:两者虽然都叫蓝牙,但用途不同
解决:BLE(低功耗蓝牙)省电、连接快、只传小数据,适合传感器/手环;经典蓝牙耗电大,适合音频、文件传输。Ai-WB2 内置的是 BLE 4.2
⚠️ 手机搜不到开发板广播的设备
原因:广播没开启、距离太远,或手机蓝牙/定位权限没开
解决:确认程序调用了 bt_le_adv_start();Android 手机搜索 BLE 设备需要开启「定位权限」;把手机靠近开发板(0.5~5 米内)再扫
⚠️ BLE 传数据快吗?一次能传多少
原因:BLE 为省电牺牲了速率
解决:BLE 4.2 理论速率约 1Mbps,单次「通知」通常几十字节,适合传感器读数、遥控指令这类小数据;传大文件请用 Wi-Fi
⚠️ 我的设备该当主机还是从机
原因:角色取决于「谁主动」
解决:需要主动连接别人(如手机 App 连手环)就当主机;需要一直广播等别人来连(如手环、传感器、电子价签)就当从机
⚠️ 配网是什么?为什么要用蓝牙配网
原因:设备没有屏幕和键盘,输不了 Wi-Fi 密码
解决:配网就是把 Wi-Fi 账号密码发给设备的过程,像给门锁录入指纹。用 BLE 配网不用额外硬件,手机 App 直接连上设备把密码「递」过去,本系列 blufi 配网 教程就是干这个的
运行自检
本页为概念篇,无需编译运行代码。能用自己的话讲清「主机/从机、广播、GATT(服务/特征值)、UUID、MAC 地址」五个概念,并能说出本系列 4 篇动手教程分别做什么,即为通过。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

