3. 开发环境搭建:Keil、IAR、GCC工具链配置与第一个点灯程序

好,咱们直接进入正题。做蓝牙低功耗开发,第一步就是把家伙事儿备齐。你想想看,代码写得再漂亮,编译不过去也是白搭。这一章,我就带你把这三种主流工具链——Keil、IAR、GCC——给捋顺了,最后再跑个点灯程序,算是给咱们的课程来个「开机仪式」。

3.1 为什么需要三种工具链?

说实话,不是每个项目都能让你随便挑工具。我在项目中遇到过客户指定必须用IAR,也遇到过团队统一用Keil。GCC呢,更多是Linux派或者喜欢开源的朋友在用。说白了,这三种工具链各有各的脾气,但都能干活。

我个人习惯是:原型验证用Keil,产品量产用IAR,调试底层用GCC。为什么?Keil的调试器好用,上手快;IAR的代码优化确实狠,能省不少Flash;GCC嘛,完全免费,适合折腾。

小提示: 如果你是初学者,我建议先从Keil开始。它的IDE最友好,遇到问题网上资料也多。别一上来就搞GCC命令行,容易劝退。

3.2 Keil MDK 环境搭建

Keil MDK(Microcontroller Development Kit)是ARM内核MCU开发的老牌工具。咱们做蓝牙低功耗,芯片基本都是ARM Cortex-M系列,所以Keil很合适。

3.2.1 安装步骤

  1. 下载安装包:去Keil官网下载MDK-ARM最新版。注意,需要注册账号,免费的。
  2. 安装:一路Next就行。但有个坑——安装路径不要有中文。我曾经有个同事,装在了「D:\开发工具\Keil_v5」,结果编译总是报路径错误,折腾了半天才发现是中文惹的祸。
  3. 安装芯片包:打开Keil,点击 Pack Installer,找到你的芯片型号(比如nRF52832、CC2640),点击Install。这一步很多人会忘,结果新建工程时找不到芯片。
  4. 破解:嗯,这个你懂的。Keil不破解只能用2KB代码,点灯都费劲。网上有注册机,但请支持正版。

3.2.2 新建工程与配置

新建工程时,我习惯先建一个文件夹,比如 ble_led_demo,然后把工程文件放进去。这样项目迁移方便。

// 工程结构示例
ble_led_demo/
├── User/          // 用户代码
├── Driver/        // 外设驱动
├── Startup/       // 启动文件
├── RTE/           // 运行时环境
└── Output/        // 编译输出

配置工程时,有几个关键点:

  • Target:选对你的芯片型号,别选错了。我见过有人用nRF52832选了nRF52840,结果外设地址都不对。
  • Output:勾选 Create HEX File,这样编译后会生成hex文件,方便烧录。
  • C/C++:优化等级建议先选 -O0,调试方便。等代码稳定了再开 -O2-O3
注意: Keil的编译器版本和芯片包版本要匹配。我曾经遇到过,用V5.06编译器配新版的nRF5 SDK,编译直接报几百个错误。后来换成V5.06 update 6才搞定。

3.3 IAR Embedded Workbench 环境搭建

IAR,圈内人称「优化之王」。它的编译器确实牛,同样的代码,IAR编译出来的体积能比Keil小10%-20%。对于Flash紧张的蓝牙芯片来说,这很关键。

3.3.1 安装与配置

IAR的安装比Keil稍微复杂一点。它需要安装主程序,然后还要装对应的芯片支持包。

  1. 下载IAR for ARM:最新版是8.x或9.x。同样需要注册。
  2. 安装:注意,IAR的License管理比较严格。如果你用的是破解版,记得把License文件放到指定目录。
  3. 配置芯片支持:IAR自带了很多芯片的支持,但有些小众芯片需要额外安装。比如TI的CC26xx系列,需要单独下载IAR的补丁包。

3.3.2 工程配置要点

IAR的工程配置界面和Keil不太一样。我个人觉得IAR的配置更「程序员友好」,但新手可能会觉得有点乱。

  • General Options:选芯片型号,配置浮点单元(FPU)。蓝牙芯片一般没有FPU,选None就行。
  • Compiler:优化等级我一般选 High,但调试时选 None
  • Linker:配置链接脚本(.icf文件)。这个文件定义了Flash和RAM的布局,千万别乱改。我见过有人为了省空间,把堆栈改小了,结果程序跑着跑着就HardFault了。
核心经验: IAR的调试器非常好用。它的Live Watch功能可以在程序运行时实时查看变量值,对于调试蓝牙协议栈这种复杂系统,简直是神器。

3.4 GCC + Makefile 环境搭建

GCC,开源界的骄傲。如果你用的是Linux或者喜欢命令行,那GCC就是你的菜。很多蓝牙芯片厂商(比如Nordic)的SDK都提供了GCC支持。

3.4.1 工具链安装

GCC工具链通常叫 arm-none-eabi-gcc。安装方式:

  • Windows:下载ARM官方的GCC工具链,或者用MSYS2 + pacman安装。
  • Linuxsudo apt-get install gcc-arm-none-eabi,一行命令搞定。
  • macOS:用Homebrew,brew install gcc-arm-embedded

3.4.2 Makefile 编写

GCC没有IDE,所以需要自己写Makefile。别怕,其实很简单。我给你一个最小化的模板:

# 工具链前缀
CROSS_COMPILE = arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy

# 编译选项
CFLAGS = -mcpu=cortex-m4 -mthumb -O2 -Wall
LDFLAGS = -T linker_script.ld

# 源文件
SRCS = main.c startup.c
OBJS = $(SRCS:.c=.o)

# 目标
TARGET = ble_led_demo.elf

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $^

%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $<

clean:
	rm -f $(OBJS) $(TARGET)

嗯,这里要注意:链接脚本(.ld文件)一定要和芯片匹配。Nordic的SDK里自带链接脚本,直接拿来用就行。别自己写,容易翻车。

避坑指南: 我曾经在GCC环境下编译蓝牙协议栈,结果链接时报了一堆未定义引用。查了半天,发现是库文件的链接顺序不对。GCC对链接顺序很敏感,-lble 这种库要放在源文件后面。

3.5 第一个点灯程序

好了,环境搭好了,咱们来点个灯。这是嵌入式开发的「Hello World」,也是验证工具链是否正常的最好方法。

3.5.1 硬件准备

随便一块蓝牙开发板就行。我以Nordic nRF52832 DK为例。板子上一般都有LED,接在某个GPIO上。nRF52832 DK的LED1接在P0.17上。

3.5.2 代码实现

代码很简单,就是配置GPIO为输出,然后拉高拉低。但要注意,蓝牙芯片的GPIO配置和普通MCU不太一样,需要先使能时钟。

#include "nrf.h"

// 延时函数,简单粗暴
void delay(uint32_t ms) {
    for (uint32_t i = 0; i < ms * 1000; i++) {
        __NOP();
    }
}

int main(void) {
    // 使能GPIO时钟
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;

    // 配置P0.17为输出
    NRF_P0->DIRSET = (1 << 17);
    NRF_P0->OUTCLR = (1 << 17);  // 初始低电平

    while (1) {
        NRF_P0->OUTSET = (1 << 17);  // 拉高,LED亮
        delay(500);
        NRF_P0->OUTCLR = (1 << 17);  // 拉低,LED灭
        delay(500);
    }
}

3.5.3 编译与烧录

三种工具链的烧录方式不同:

工具链 烧录方式 常用工具
Keil IDE内一键下载 J-Link, ST-Link
IAR IDE内一键下载 J-Link, I-jet
GCC 命令行烧录 JLinkExe, OpenOCD

GCC命令行烧录示例:

# 先编译
make

# 用J-Link烧录
JLinkExe -device nRF52832_xxAA -if SWD -speed 4000 -autoconnect 1 -CommanderScript flash.jlink

其中 flash.jlink 文件内容:

loadfile ble_led_demo.hex
r
g
exit

3.6 常见问题与避坑

最后,我总结几个新手最容易踩的坑:

  • 烧录失败:检查SWD接线,特别是GND和VCC。我遇到过好几次,板子没上电,J-Link也能识别,但烧录就是失败。
  • LED不亮:先确认GPIO号对不对。很多开发板的LED是低电平点亮,代码里要拉低而不是拉高。
  • 编译报错:检查芯片型号和启动文件是否匹配。nRF52832和nRF52840的启动文件不一样。
一句话总结: 环境搭建是磨刀不误砍柴工。花点时间把Keil、IAR、GCC都配好,后面写蓝牙协议栈的时候,你会发现省了很多事。

好,这一章就到这儿。下一章咱们开始真正接触蓝牙协议栈,从GAP层讲起。到时候你会看到,点灯只是开胃菜,蓝牙才是主菜。