Skip to content

概述

iBeacon 是苹果公司推出的基于 BLE 广播的信标方案:设备只广播(间隔发送一小包数据,像大喇叭喊话)而不建立连接,手机经过附近时就能识别出它和它携带的信息(UUID、Major、Minor 等)。它常用于商场室内定位、门店推送、寻物标签等场景。本教程让 Ai-WB2 化身一个 iBeacon 信标,用手机 App 验证广播内容。

用大白话讲:iBeacon 就像路边广告牌。广告牌不和你说话、不和你握手,只是立在那里展示内容(「我是谁、我在哪、信号多强」),你路过时抬头看一眼就知道了。本教程就是让开发板变成这样一块「蓝牙广告牌」,手机 App 相当于路过的行人,走近就能看到牌子上的字(UUID 等数据)。

本教程基于安信可官方 SDKAi-Thinker-Open/Ai-Thinker-WB2,版本 release_bl_iot_sdk_1.6.40)的官方示例 applications/bluetooth/ble_ibeacon 编写,代码可在本地 SDK 中直接找到。

🎯本页目标让开发板广播自定义 iBeacon 数据(UUID / Major / Minor / 发射功率),手机 App 能搜到并识别,掌握 BLE 广播的完整流程。
🧰前置条件① Ai-WB2 开发板一块 ② 已按 [SDK 安装](../sdk/sdk_intro) 完成开发环境搭建 ③ 支持 BLE 的手机一台(安装 nRF Connect 等蓝牙调试 App)。
🔗相关章节BLE 概念见 [BLE 简介](./ble_intro);广播的「喊话方/收听方」关系见 [BLE 主机](./ble_master) 的扫描部分。

进入示例工程

本教程直接使用官方 SDK 自带的 ble_ibeacon 示例工程,打开终端进入该工程目录:

cd ~/Ai-Thinker-WB2/applications/bluetooth/ble_ibeacon

说明:cd 是「进入目录」命令,这里进入 iBeacon 示例工程目录;后续的 make 编译、make flash 烧录命令都必须先在这个目录里执行。

工程目录结构说明:

文件 作用
ble_ibeacon/main.c 主程序源码(本工程只有这一个源文件),本教程主要看的文件
ble_ibeacon/bouffalo.mk 工程编译配置,一般无需修改
认识并修改广播内容(可选)

打开 ble_ibeacon/main.c,找到 iBeacon 数据数组 my_ibeacon[],广播出去的内容就在这里(每个字节都是广告牌上的「字」):

char my_ibeacon[]=
{
    0x4C, 0x00, //公司的标志 (0x004C == Apple)
    0x02, 0x15, //iBeacon advertisement indicator
    0xB9, 0x40, ... 0x6D, // iBeacon proximity uuid(16 字节)
    0x00, 0x01, // major(主编号)
    0x00, 0x01, // minor(次编号)
    0xc5 //power(发射功率,用于估算距离)
};
字段 大白话 作用
公司标志 0x4C 0x00 厂家印章 声明这是苹果 iBeacon 格式
UUID(16 字节) 身份证号 标识这组信标属于谁,可自定义
major / minor 分组号/编号 同一 UUID 下再细分(如门店号、货架号)
power 0xc5 音量档位 表示发射功率,手机据此估算距离

💡 示例 UUID 对应 B9407F30-F5F8-466E-AFF9-25556B57FE6D(一个通用的测试 UUID),你可以按自己的需求改这 16 个字节;设备名由宏 IBEACON_NAME 控制(默认 "MY_IBEACON"),想改广播里显示的名字就改它。

编写代码

官方示例代码无需修改即可运行,main.c 完整源码已移至文末,见:

📜 完整代码 — 位于本页「完整代码」章节,默认折叠,点击展开,与官方示例(applications/bluetooth/ble_ibeacon/ble_ibeacon/main.c)完全一致。

代码要点:

API 作用
bl_sys_init() 初始化系统时钟等基础资源,用 BLE 必须先调用它,漏掉直接死机
ble_controller_init(configMAX_PRIORITIES - 1) 初始化 BLE 协议栈(蓝牙通信的大脑),不初始化后面蓝牙函数全部无效
hci_driver_init() 初始化蓝牙硬件驱动,负责 CPU 和蓝牙射频「传话」,漏掉就无法广播
bt_enable(NULL) 打开蓝牙协议栈,相当于手机「打开蓝牙开关」,不打开无法广播
bt_le_adv_start(&param, ibeacon_data, ...) 真正开始「大喇叭喊话」,喊的内容就是 ibeacon_data,不调用手机搜不到
bt_set_name(IBEACON_NAME) 给设备起名(MY_IBEACON),手机搜索列表显示的就是它
编译工程

在工程目录执行编译:

make -j8

说明:make 是「编译」命令,把代码变成开发板能运行的固件(烧进开发板的程序);-j8 表示用 8 个 CPU 核并行编译,更快。

编译成功后生成固件 build_out/ble_ibeacon.bin

⚠️ 若提示 riscv64-unknown-elf-gcc: command not found,说明工具链权限未配置,先执行 cd toolchain/riscv/Linux && . chmod755.sh 再重新编译。

烧录固件

开发板保持 USB 连接,确认串口设备号后执行烧录:

make flash p=/dev/ttyUSB0 b=921600

说明:make flash 是「烧录」命令,把编译好的固件写进开发板芯片。p= 后面是串口设备号(要改成你电脑上实际的串口,可用 ls /dev/ttyUSB* 查看),b=921600 是烧录波特率(串口传数据的速度),保持默认即可。

⏳ 烧录过程中按提示长按开发板 EN 键进入下载模式(部分开发板自动进入),等待进度条完成即烧录成功。

运行验证

烧录完成后开发板自动重启运行。先看串口日志——注意!本示例代码把串口波特率设成了 115200bl_uart_init(0, 16, 7, 255, 255, 115200)),串口助手要选 115200 而不是 921600:

AXK BLE IBEACON
ble_controller_init
hci_driver_init
bt_enable

再打开手机蓝牙调试 App(如 nRF Connect,Android/iOS 均可),扫描周围设备,应能看到名为 MY_IBEACON 的设备,或识别出 UUID B9407F30-F5F8-466E-AFF9-25556B57FE6D 的 iBeacon 信标。

串口打印出 AXK BLE IBEACON 且手机 App 能搜到 MY_IBEACON 即为成功;如果串口没输出,先检查波特率是否选成了 115200;如果手机搜不到 MY_IBEACON,见文末 FAQ。

💡 进阶验证:把手机放在开发板 0.5~5 米范围内走动,部分 iBeacon App 会显示距离估算(power 字段就是用来算这个的),说明广播数据被完整解析。

代码执行流程

例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):


本文 API 汇总

bl_sys_init

初始化系统时钟、外设等基础资源,使用 BLE 前必须先调用(本示例在 main() 里调用)。

返回值:成功返回 0;失败返回负值错误码

bl_uart_init(id, tx_pin, rx_pin, cts_pin, rts_pin, baudrate)

初始化串口(UART,电脑和开发板之间逐位传数据的通道),本例把日志串口设为 115200 波特率(传输速度)。

参数

  • id:串口号,可选值:0/1,本示例用 0
  • tx_pin:发送引脚,本示例 16
  • rx_pin:接收引脚,本示例 7
  • cts_pin:流控引脚,不用传 255
  • rts_pin:流控引脚,不用传 255
  • baudrate:波特率(串口传数据的「语速」,两端必须一致),本示例 115200

返回值:成功返回 0;失败返回负值错误码

ble_controller_init(task_priority)

初始化 BLE 协议栈(蓝牙通信的「大脑」),所有 BLE 功能的第一步。

参数

  • task_priority:协议栈任务优先级(uint8_t),官方示例传 configMAX_PRIORITIES - 1(系统最高优先级)

返回值:无

hci_driver_init

初始化蓝牙硬件驱动,负责 CPU 与蓝牙射频芯片之间的数据传递。

返回值:成功返回 0;失败返回负值错误码

bt_enable(cb)

打开蓝牙协议栈,相当于手机「打开蓝牙开关」,不调用则无法广播/连接。

参数

  • cb:协议栈就绪回调(bt_ready_cb_t),形如 void cb(int err),不需要可传 NULL

返回值:成功返回 0;失败返回负值错误码

bt_set_name(name)

设置蓝牙设备名称,手机搜索列表里显示的就是它。

参数

  • name:设备名字符串,必填(本示例 "MY_IBEACON"

返回值:成功返回 0;失败返回负值错误码

bt_le_adv_start(param, ad, ad_len, sd, sd_len)

开始 BLE 广播(大喇叭喊话),广播数据由 ad 数组指定。

参数

  • param:广播参数结构体指针,含广播间隔(interval_min/interval_max)、选项(可连接/带设备名)等
  • ad:广播数据数组(bt_data_t),本示例为 ibeacon_data(含 iBeacon 数据)
  • ad_len:广播数据条数,本示例 ARRAY_SIZE(ibeacon_data)(2 条)
  • sd:扫描应答数据数组,不需要传 NULL
  • sd_len:扫描应答数据条数,传 0

返回值:成功返回 0;失败返回负值错误码

vTaskDelay(ms)

让当前任务挂起指定毫秒数,期间让出 CPU 给其他任务。

参数

  • ms:延时毫秒数,本示例 10(等待 BLE 硬件就绪)

返回值:无

xTaskCreate(task, name, stack, param, prio, handle)

创建任务并加入就绪队列,由调度器按优先级调度执行。

参数

  • task:任务入口函数指针,形如 void task(void *arg),必填
  • name:任务名称字符串(调试用),本示例 "ibeacon"
  • stack:任务栈大小(单位:字),本示例 1024
  • param:传给入口函数的参数指针,无参传 NULL
  • prio:任务优先级,可选值:0(最低)~19(最高,SDK 配置),本示例 15
  • handle:任务句柄输出指针,不需要可传 NULL

返回值:成功返回 pdPASS;失败返回 pdFAIL(如内存不足)


完整代码

以下为 ble_ibeacon/main.c 完整源码,与官方示例(applications/bluetooth/ble_ibeacon/ble_ibeacon/main.c)完全一致:

📜 点击展开 main.c 完整代码
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(&param,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);
}

常见问题与踩坑提示

⚠️ 手机搜不到 MY_IBEACON
原因:广播没启动、距离太远,或手机蓝牙/定位权限没开
解决:确认串口打印了 bt_enable 之后程序没卡死;Android 手机扫描 BLE 必须开启「定位权限」;手机靠近开发板(0.5~5 米)再扫;iBeacon 类 App 有缓存,先杀掉 App 重开

⚠️ 串口完全没有日志输出
原因:串口助手波特率选错——本例代码把串口设成了 115200,不是常用的 921600
解决:把串口助手波特率改成 115200 再重新打开;确认串口号选对(ls /dev/ttyUSB* 查看)

⚠️ 改了 UUID/名字,手机还是显示旧的
原因:修改后没有重新编译烧录,或手机 App 缓存了旧数据
解决:改完 my_ibeacon[]/IBEACON_NAME 后重新 make -j8 && make flash p=/dev/ttyUSB0 b=921600;手机端重启 App、关闭再打开手机蓝牙

⚠️ 烧录一直卡住等待,进度条不动
原因:未进入下载模式,或数据线只能充电不能传数据
解决:烧录时按提示长按 EN 键进入下载模式;换一根能传数据的 Type-C 数据线后重试

⚠️ 串口找不到设备 / 打不开
原因:USB 转串口驱动未装、权限不足,或设备号不对
解决:Linux 用 lsusb/dmesg 查看设备,权限不足执行 sudo usermod -aG dialout $USER 后重新登录;Windows 到设备管理器查看 COM 口

⚠️ 执行 make 报找不到 Makefile
原因:在错误的目录执行了编译命令
解决:先执行 cd ~/Ai-Thinker-WB2/applications/bluetooth/ble_ibeacon 进入工程目录,再执行 make -j8

运行自检

串口依次打印 AXK BLE IBEACONble_controller_inithci_driver_initbt_enable,且手机蓝牙 App 能搜到名为 MY_IBEACON 的设备(iBeacon UUID B9407F30-F5F8-466E-AFF9-25556B57FE6D),即广播功能验证通过。

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23