第二章 开发环境搭建:交叉编译工具链安装、调试器配置、串口终端工具使用

说实话,很多初学者一上来就急着写代码,结果卡在环境搭建上三天三夜。我当年也干过这种蠢事——工具链没配好就编译,报错信息看得一头雾水。后来学乖了:先把环境收拾利索,后面才能跑得顺畅。

这一章,咱们就把开发环境彻底搞定。包括三样东西:交叉编译工具链、调试器(JTAG/SWD)、串口终端。这三板斧拿下了,你就能在PC上编译出能在ARM芯片上跑的程序,还能烧进去、调起来、看输出。

核心思路: 你的PC是x86架构,目标板是ARM架构。PC上编译的程序不能在ARM上直接跑,必须用交叉编译工具链。调试器负责把程序烧进去并控制执行,串口则让你看到板子“说了什么”。

2.1 交叉编译工具链安装

什么叫交叉编译?说白了,就是在你的电脑上编译出能在另一个CPU架构上运行的程序。比如你在x86的笔记本上编译ARM的可执行文件。

我个人习惯用 gcc-arm-none-eabi 这套工具链。它是开源的,专门针对ARM Cortex-M系列芯片。安装方式很简单,我直接说最常用的两种。

2.1.1 在Ubuntu上安装

sudo apt update
sudo apt install gcc-arm-none-eabi

装完以后,验证一下:

arm-none-eabi-gcc --version

如果看到版本号,说明装好了。嗯,这里要注意:有些老版本的Ubuntu源里工具链版本太旧,我建议去ARM官网下载最新版。

2.1.2 在Windows上安装

Windows下我推荐用 GNU Arm Embedded Toolchain 的Windows安装包。去ARM官网下载,一路Next就行。装完后记得把bin目录加到系统PATH里。

小技巧: 我个人习惯在用户目录下建一个 ~/tools/ 文件夹,把所有工具链都放里面。这样换电脑时直接拷贝这个文件夹,省得重新配。

2.1.3 验证工具链是否可用

写个最简单的程序试试:

// test.c
int main(void) {
    return 0;
}

编译:

arm-none-eabi-gcc -c test.c -o test.o
arm-none-eabi-objdump -d test.o

如果能看到ARM汇编指令,说明工具链工作正常。

我曾经踩过的坑: 有一次我装完工具链,编译时总报“找不到头文件”。查了半天,发现是环境变量没配好。记住:工具链的bin目录必须加到PATH里,否则系统找不到可执行文件。

2.2 调试器配置(JTAG/SWD)

调试器是嵌入式开发的“眼睛”。没有它,你只能靠猜。JTAG和SWD是两种常见的调试接口。JTAG需要4-5根线,SWD只需要2根(SWDIO和SWCLK)。现在大多数Cortex-M芯片都支持SWD,我个人也更喜欢用SWD,因为省引脚。

2.2.1 常用调试器硬件

调试器型号 接口类型 特点
J-Link JTAG/SWD 速度快,稳定,价格稍贵
ST-Link SWD STM32板载调试器,性价比高
DAP-Link SWD 开源,支持CMSIS-DAP协议
OpenOCD + FT2232 JTAG/SWD 灵活,但配置稍复杂

我在项目中用得最多的是J-Link。虽然贵了点,但稳定性和速度确实好。有一次调试一个USB协议栈,用ST-Link死活连不上,换J-Link一次成功。从那以后,我手边常备一个J-Link。

2.2.2 安装调试器驱动

以J-Link为例:

  1. 去SEGGER官网下载J-Link软件包
  2. 安装后,驱动会自动装好
  3. 用USB线连接调试器和电脑
  4. 打开设备管理器,确认能看到J-Link设备

小技巧: 如果你用的是Linux,可能需要给J-Link添加udev规则。否则普通用户权限下无法访问USB设备。规则文件一般在安装包里就有,拷贝到 /etc/udev/rules.d/ 目录下就行。

2.2.3 连接调试器到目标板

SWD接口只需要4根线:

  • SWDIO:数据线
  • SWCLK:时钟线
  • GND:地线
  • VCC:参考电压(可选,有些调试器需要)

连接时注意:SWDIO和SWCLK上最好加10kΩ上拉电阻到VCC。我曾经因为没加上拉电阻,导致调试器偶尔连不上,排查了整整一天。

2.2.4 验证调试器连接

用J-Link自带的命令行工具测试:

JLinkExe
device STM32F103C8
connect

如果能看到芯片ID,说明连接成功。如果报错,先检查接线,再检查驱动。

注意: 调试器连接时,目标板必须上电。有些调试器可以从USB取电给目标板,但电流有限。如果你的板子功耗大,建议单独供电。

2.3 串口终端工具使用

串口是嵌入式开发中最常用的调试手段。printf打印、日志输出、交互命令,全靠它。你想想看,没有串口,你怎么知道程序跑到哪一步了?

2.3.1 常用串口终端工具

工具名称 平台 特点
PuTTY Windows 轻量,支持SSH和串口
MobaXterm Windows 功能丰富,支持多标签
screen Linux 命令行工具,轻量
minicom Linux 经典串口工具,配置稍复杂
Serial Monitor (VS Code插件) 跨平台 集成在IDE中,方便

我个人在Windows下用MobaXterm,在Linux下用screen。MobaXterm的会话管理功能很强大,可以保存多个串口配置。screen则胜在轻量,一条命令就能用。

2.3.2 串口参数设置

串口通信需要双方约定好参数。常见的设置是:

  • 波特率:115200(最常用)
  • 数据位:8
  • 停止位:1
  • 校验位:无
  • 流控制:无

为什么是115200?因为它是标准波特率中比较快的一个,而且大多数芯片的UART都能稳定支持。我见过有人用921600,结果线稍微长一点就丢数据。

2.3.3 在Linux下使用screen

# 查看串口设备
ls /dev/ttyUSB*

# 连接串口,波特率115200
screen /dev/ttyUSB0 115200

# 退出screen:Ctrl+A,然后按K

如果提示权限不足,把用户加到dialout组:

sudo usermod -a -G dialout $USER

然后注销重新登录。

2.3.4 在Windows下使用MobaXterm

  1. 打开MobaXterm,点击“Session”
  2. 选择“Serial”
  3. 选择串口号(在设备管理器中查看)
  4. 设置波特率115200,数据位8,停止位1,校验位无
  5. 点击“OK”

连接成功后,如果目标板有打印输出,你就能在终端里看到了。

小技巧: 我习惯在串口终端里开启“本地回显”。这样你输入的命令也能显示出来,方便调试交互式程序。MobaXterm里在“Terminal settings”中勾选“Local echo”就行。

2.3.5 验证串口通信

写一个简单的程序,让板子每隔1秒打印一次“Hello World”:

#include "stm32f1xx_hal.h"

UART_HandleTypeDef huart1;

int main(void) {
    HAL_Init();
    __HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置串口引脚
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 配置串口
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&huart1);

    char msg[] = "Hello World!\r\n";
    while (1) {
        HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);
        HAL_Delay(1000);
    }
}

编译烧录后,打开串口终端,你应该能看到每隔1秒打印一次“Hello World”。

我曾经踩过的坑: 有一次我串口终端什么也收不到,检查了接线、波特率、程序,都没问题。最后发现是USB转串口模块的TX和RX接反了。记住:TX接RX,RX接TX,交叉连接!

2.4 本章知识体系

为了让你更直观地理解这三样工具的关系,我画了一张图:

开发环境搭建:三大核心工具 PC(x86架构) 交叉编译工具链 gcc-arm-none-eabi 调试器软件 J-Link / OpenOCD 串口终端工具 PuTTY / screen / MobaXterm 目标板(ARM架构) ARM Cortex-M 芯片 运行编译后的程序 通过SWD/JTAG调试 UART串口 打印日志 / 交互命令 编译生成.elf/.bin SWD/JTAG 烧录+调试 串口通信(TX/RX) 流程:编写代码 → 交叉编译 → 烧录到目标板 → 调试 → 串口查看输出

这张图展示了PC和目标板之间的数据流。你在PC上写代码,用交叉编译工具链编译成ARM可执行文件,通过调试器烧录到芯片里,然后用串口终端看输出。这三样工具缺一不可。

2.5 常见问题与避坑指南

  • 工具链装好了但编译报错:检查环境变量,确认arm-none-eabi-gcc在PATH里。我曾经因为装了多个版本的Python,导致PATH混乱,工具链找不到。
  • 调试器连不上芯片:先检查接线,再检查芯片供电。有些芯片需要先复位才能连接。我遇到过芯片被锁死的情况,需要用调试器的“unlock”功能。
  • 串口收不到数据:检查TX/RX是否接反,波特率是否匹配。还有一个常见问题:串口工具的流控制(RTS/CTS)没关,导致数据发不出去。
  • 串口收到乱码:波特率不匹配,或者芯片的时钟配置不对。我遇到过芯片内部时钟不准,导致实际波特率偏离设定值的情况。

总结一下: 开发环境搭建是嵌入式开发的第一步,也是最容易出问题的一步。工具链、调试器、串口终端,这三样东西配好了,后面的开发就会顺畅很多。别急着写代码,先把环境搞利索。

嗯,这一章的内容就到这里。环境搭好了,下一章咱们就可以开始写真正的板级代码了。