3、固件开发环境搭建:Keil/IAR/ESP-IDF环境配置、SDK导入、第一个蓝牙广播程序

好,咱们进入第三章。这一章是动手前的最后一道坎——把开发环境搭起来。说实话,我见过太多同学卡在这一步,工具链没配好,折腾一整天,代码一行没写。别急,咱们一步步来。

3.1 三种主流IDE,你选哪个?

做蓝牙固件开发,市面上主流的工具链就三个:Keil、IAR、ESP-IDF。我个人的建议是:

  • Keil MDK:最常用,尤其适合 Nordic nRF5 系列。上手快,调试方便。
  • IAR Embedded Workbench:编译优化强,代码体积小。适合对性能有要求的项目。
  • ESP-IDF:乐鑫官方的框架,基于 CMake + GCC。适合 ESP32 系列,开源且灵活。

你可能会问:「我该学哪个?」我的回答是:看你手头的芯片。如果是 nRF52832,那就 Keil;如果是 ESP32,那就 ESP-IDF。别纠结,工具是拿来用的。

我的经验:我在项目中遇到过用 Keil 编译好好的代码,换到 IAR 就报错。原因?IAR 对 C 标准的检查更严格。所以,选定一个工具链就别轻易换。

3.2 Keil 环境配置与 SDK 导入

咱们先讲 Keil。这是最经典的一套流程。

3.2.1 安装 Keil MDK

  1. 去 Keil 官网下载 MDK-ARM 安装包。注意版本,我建议用 5.38 或更新版。
  2. 安装时一路默认就行。但记得勾选「C51」和「C251」?不,咱们做 ARM,只勾 ARM 编译器。
  3. 安装完成后,打开 Keil,点 Pack Installer,安装对应芯片的 Device Family Pack。比如 nRF52832 就搜「NordicSemiconductor.nRF_DeviceFamilyPack」。

注意:Pack 版本要和 SDK 匹配。我曾经因为 Pack 版本太新,导致 SDK 里的某些寄存器定义对不上,编译报错。折腾了两小时才发现。

3.2.2 导入 Nordic SDK

Nordic 官方提供了 nRF5 SDK,里面包含了蓝牙协议栈、外设驱动、示例工程。

  1. 下载 nRF5 SDK,解压到某个路径。比如 C:\nRF5_SDK_17.1.0
  2. 打开 Keil,点 Project → Open Project,找到 SDK 里的示例工程。路径一般是:examples\ble_peripheral\ble_app_beacon\pca10040\s132\arm5_no_packs
  3. 编译前,先配置一下工程选项。右键工程名,选 Options for Target
  4. C/C++ 选项卡里,把 Include Paths 指向 SDK 的头文件目录。这个很重要,不然编译会报找不到头文件。

小技巧:我习惯把 SDK 路径设成环境变量,比如 NRF5_SDK_ROOT。这样换电脑或换路径时,只需要改一个变量,不用改所有工程配置。

3.3 IAR 环境配置

IAR 的配置流程和 Keil 类似,但有几个坑要注意。

3.3.1 安装 IAR

  1. 下载 IAR Embedded Workbench for ARM。注意,IAR 是收费软件,但可以试用 30 天。
  2. 安装时选择「Full Installation」,确保所有组件都装上。
  3. 安装完成后,同样需要安装芯片支持包。IAR 里叫「Device Support」。

3.3.2 导入 SDK 工程

Nordic SDK 里也提供了 IAR 的工程文件,后缀是 .eww

  1. 直接双击 ble_app_beacon.eww 打开工程。
  2. IAR 会自动加载所有源文件。但有时候链接脚本(.icf)的路径会不对,需要手动指定。
  3. Project → Options → Linker 里,把 Linker configuration file 指向 SDK 里的 .icf 文件。

避坑指南:我曾经在 IAR 里编译一个工程,明明代码没问题,就是链接报错。后来发现是 IAR 的编译器版本和 SDK 要求的版本不一致。IAR 对版本兼容性要求很严格,建议用 SDK 文档里推荐的版本。

3.4 ESP-IDF 环境配置

如果你用的是 ESP32,那 ESP-IDF 是绕不开的。这套工具链基于 Python 和 CMake,和 Keil/IAR 的思路完全不同。

3.4.1 安装 ESP-IDF

  1. 打开终端,执行 git clone --recursive https://github.com/espressif/esp-idf.git
  2. 进入 esp-idf 目录,运行 ./install.sh(Windows 下是 install.bat)。
  3. 安装完成后,运行 . ./export.sh 设置环境变量。每次打开新终端都要执行这一步,或者你可以把它加到 .bashrc 里。

我的习惯:我一般用 VS Code 配合 ESP-IDF 插件开发。插件会自动帮你配置环境变量,省去手动 export 的麻烦。

3.4.2 创建第一个工程

ESP-IDF 提供了一个示例工程模板,咱们直接用它。

# 复制示例工程
cp -r $IDF_PATH/examples/get-started/blink ./my_ble_app

# 进入工程目录
cd ./my_ble_app

# 配置工程(选择芯片型号)
idf.py set-target esp32

# 编译
idf.py build

# 烧录
idf.py -p /dev/ttyUSB0 flash

# 查看日志
idf.py -p /dev/ttyUSB0 monitor

嗯,这里要注意:第一次编译会下载工具链,时间比较长。建议找个网络好的时候做。

3.5 第一个蓝牙广播程序

环境搭好了,咱们写个最简单的蓝牙广播程序。说白了,就是让设备不断往外发「我在这儿」的信号。

3.5.1 基于 Nordic SDK 的 Beacon 示例

Nordic SDK 里自带了 Beacon 示例,咱们直接用它。

// 在 main.c 中,核心代码就这几行
static void advertising_init(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;

    // 初始化广播数据
    memset(&advdata, 0, sizeof(advdata));
    advdata.name_type          = BLE_ADVDATA_FULL_NAME;
    advdata.include_appearance = true;
    advdata.flags              = BLE_ADVDATA_FLAGS_BLE_GAP_DISC_MODE_GENERAL;

    // 设置广播数据
    err_code = ble_advdata_set(&advdata, NULL);
    APP_ERROR_CHECK(err_code);
}

static void advertising_start(void)
{
    uint32_t err_code;

    // 开始广播
    err_code = sd_ble_gap_adv_start(&m_adv_params, APP_BLE_CONN_CFG_TAG);
    APP_ERROR_CHECK(err_code);
}

这段代码做了两件事:初始化广播数据,然后开始广播。你烧录到板子上,用手机上的 nRF Connect 就能搜到设备。

我的经验:第一次跑这个程序时,我死活搜不到设备。后来发现是天线没接好。嗯,硬件问题往往比软件问题更隐蔽。

3.5.2 基于 ESP-IDF 的 iBeacon 示例

ESP32 这边也有现成的 iBeacon 示例。

# 进入 iBeacon 示例目录
cd $IDF_PATH/examples/bluetooth/bluedroid/ble/ble_ibeacon

# 编译烧录
idf.py build flash monitor

代码里主要配置了广播包的内容,包括 UUID、Major、Minor 等字段。这些数据会被手机上的 iBeacon 应用解析。

注意:ESP32 的蓝牙协议栈有两种:Bluedroid 和 NimBLE。Bluedroid 功能全但占内存大,NimBLE 轻量但功能少。咱们这个示例用的是 Bluedroid。

3.6 常见问题与调试技巧

环境搭建过程中,你可能会遇到这些问题:

问题 原因 解决方法
编译报错:找不到头文件 Include Path 没配置 检查工程选项里的 Include Paths
链接报错:undefined reference 缺少库文件或源文件 检查工程里是否包含了所有 .c 文件
烧录失败:无法连接芯片 驱动没装或接线错误 检查 J-Link 或 USB 驱动,确认接线
手机搜不到设备 天线问题或广播参数不对 检查天线焊接,确认广播间隔和功率

调试技巧:我习惯在代码里加串口打印。Nordic 用 NRF_LOG_INFO,ESP32 用 ESP_LOGI。打印出关键变量的值,比猜问题快得多。

好了,环境搭好了,第一个蓝牙广播程序也跑起来了。下一章咱们会深入蓝牙协议栈,看看广播数据里到底能塞些什么东西。到时候你会发现,广播不只是「我在这儿」,还能传递很多有用的信息。