第三章 开发环境搭建:交叉编译工具链安装、系统烧录、SSH远程连接与文件传输、基础SDK验证

说实话,嵌入式开发的第一步往往是最劝退的。我记得刚入行那会儿,光配环境就折腾了整整两天。后来带新人时发现,十个人里有八个卡在这一步。所以这一章,咱们就把这些「脏活累活」一次讲透。

3.1 交叉编译工具链:为什么非得「交叉」?

你想想看,你的电脑是 x86 架构,而嵌入式板子通常是 ARM 架构。x86 编译出来的程序,ARM 根本跑不了。所以我们需要在 PC 上装一个「能生成 ARM 机器码的编译器」——这就是交叉编译工具链。

我个人习惯用 Linaro 提供的 GCC 工具链,稳定且社区活跃。以 ARM Cortex-A 系列为例,下载地址一般是:

https://releases.linaro.org/components/toolchain/binaries/

选择对应版本,比如 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz。解压后配置环境变量:

tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
sudo mv gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf /opt/
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin

验证是否安装成功:

arm-linux-gnueabihf-gcc --version

如果看到版本号输出,恭喜你,第一步走通了。

注意: 我曾经遇到过一位同事,下载了 aarch64 版本的工具链,但板子是 32 位的 ARMv7。结果编译出来的程序一运行就报 Illegal instruction。所以一定要确认板子的架构是 armv7 还是 armv8,是硬浮点还是软浮点。

3.2 系统烧录:把系统「灌」进板子

拿到一块空板子,第一件事就是烧录系统。市面上常见的烧录方式有几种:SD 卡烧录、USB OTG 烧录、以及通过网络烧录。我个人最常用的是 SD 卡烧录,因为简单粗暴。

以 Raspberry Pi 或类似的 ARM 板为例,步骤大致如下:

  1. 准备一张 16GB 以上的 SD 卡(建议 Class 10 以上)
  2. 下载板子对应的系统镜像,比如 Ubuntu 或 Buildroot 生成的 .img 文件
  3. 使用 dd 命令或 balenaEtcher 工具写入 SD 卡

dd 命令时一定要小心:

sudo dd if=ubuntu-20.04.3-preinstalled-server-armhf.img of=/dev/sdb bs=4M status=progress
关键点: of= 后面是设备名,不是分区名。比如 /dev/sdb 而不是 /dev/sdb1。写错了可能会把你的硬盘数据清空,别问我怎么知道的。

烧录完成后,把 SD 卡插入板子,上电。如果板子有 HDMI 接口,接上显示器看看启动日志。没有显示器也没关系,我们接下来用串口或 SSH 连接。

3.3 SSH 远程连接:告别显示器和键盘

嵌入式开发中,板子通常没有显示器。你总不能每次都搬个显示器过去吧?所以 SSH 是必备技能。

首先,确保板子和 PC 在同一个局域网内。可以通过路由器,或者直接用网线直连。我个人习惯用路由器,因为 DHCP 会自动分配 IP。

查看板子的 IP 地址:

ifconfig
# 或者
ip addr show

然后在 PC 上执行:

ssh username@192.168.1.100

默认密码一般是 rootadmin,具体看你的系统镜像。

小技巧: 我建议你配置 SSH 密钥登录,省去每次输密码的麻烦。用 ssh-keygen 生成密钥对,然后把公钥传到板子上:ssh-copy-id username@192.168.1.100。这样以后连接就一键直达了。

3.4 文件传输:把代码「扔」到板子上

代码在 PC 上写好,怎么传到板子上?常用的方法有三种:

方法 命令 适用场景
SCP scp file username@ip:/path/ 单个文件或少量文件
SFTP sftp username@ip 交互式传输,支持目录
NFS 挂载远程目录 开发阶段频繁修改代码

我个人的工作流是这样的:开发阶段用 NFS 挂载,代码在 PC 上修改后,板子上直接运行。调试稳定后,再用 SCP 把最终版本传到板子上。

配置 NFS 稍微麻烦一点,但值得。在 PC 上安装 NFS 服务器:

sudo apt install nfs-kernel-server
sudo mkdir /home/user/nfs_share
sudo chmod 777 /home/user/nfs_share
echo "/home/user/nfs_share *(rw,sync,no_subtree_check)" | sudo tee -a /etc/exports
sudo exportfs -a
sudo systemctl restart nfs-kernel-server

在板子上挂载:

sudo mount -t nfs 192.168.1.2:/home/user/nfs_share /mnt
注意: 我曾经在 NFS 上吃过亏。板子挂载后,我直接修改了 PC 上的源码,结果板子上的程序还在跑旧版本。后来养成了习惯:每次修改后,在板子上 sync 一下,或者重新挂载。

3.5 基础 SDK 验证:跑通第一个程序

环境搭好了,总得验证一下能不能用。写一个最简单的 Hello World:

// hello.c
#include <stdio.h>

int main() {
    printf("Hello from ARM board!\n");
    return 0;
}

用交叉编译器编译:

arm-linux-gnueabihf-gcc hello.c -o hello

把编译好的文件传到板子上:

scp hello username@192.168.1.100:/home/username/

在板子上运行:

./hello

如果看到 Hello from ARM board!,说明整个开发环境已经打通了。

到这里,你已经完成了嵌入式开发中最基础也最关键的一步。 很多初学者觉得配环境浪费时间,但我想说:环境配好了,后面的事情就是水到渠成。我见过太多人卡在环境上,最后放弃了。所以,耐心一点,把这一步走扎实。

3.6 避坑指南:我踩过的那些坑

  • 工具链版本不匹配: 我曾经用 GCC 8.3 编译的程序,在只支持 GCC 7.5 的板子上跑,结果段错误。后来我养成了习惯:板子用什么版本的 GCC,我就用什么版本的工具链。
  • 烧录时写错设备: 有一次我急着下班,把 of=/dev/sda 写成了 of=/dev/sda1,结果系统直接挂了。从那以后,我每次烧录前都会用 lsblk 确认三遍。
  • SSH 连接超时: 板子启动后,SSH 连不上。排查了半天,发现是板子的防火墙没关。用 sudo ufw disable 解决。
  • NFS 权限问题: 挂载后无法写入,检查发现是 /etc/exports 里忘了加 rw 选项。

嗯,这些坑我都踩过。你遇到了也别慌,一步步排查,总能解决。

下一章,我们会开始搭建嵌入式 Linux 系统,从 Bootloader 到内核,再到根文件系统。到时候你会发现,今天配的环境,就是后面所有工作的基石。