1. 项目概述与核心思路最近在折腾一个物联网项目手头正好有块合宙的ESP32-C3开发板想用它来采集传感器数据。我的主力开发机是一台树莓派4B平时就放在桌角当个小服务器用。直接在树莓派上给ESP32-C3写代码听起来是个很顺理成章的选择毕竟环境统一部署也方便。但实际操作起来我发现常用的Arduino IDE在树莓派上运行起来有点“肉”界面响应慢而且对于习惯了命令行操作的我来说图形界面反而成了累赘。于是我把目光投向了arduino-cli——Arduino官方的命令行工具。它轻量、高效完全通过命令来管理库、编译和上传代码特别适合在树莓派这种资源受限或者纯命令行环境下使用。这个连载的第一篇我就来详细拆解一下如何在树莓派系统上从零开始搭建arduino-cli环境并成功用它给ESP32-C3开发板编写和上传第一个程序。简单来说这个过程可以分解为几个核心步骤首先是在树莓派上安装arduino-cli本身然后是配置arduino-cli让它认识我们的ESP32-C3开发板这需要添加额外的硬件支持包接着创建一个新项目编写代码最后完成编译和上传。整个流程走通后你会发现用命令行玩转Arduino开发是如此清爽和高效尤其适合自动化脚本和持续集成场景。2. 环境准备与arduino-cli安装2.1 树莓派系统选择与基础配置我的树莓派4B安装的是64位的Raspberry Pi OS基于Debian。选择这个系统主要是因为其软件生态完善社区支持好。如果你用的是Ubuntu Server for Raspberry Pi或者其他Debian系发行版操作也大同小异。首先确保系统是最新的打开终端执行更新命令sudo apt update sudo apt upgrade -y这个操作会更新软件包列表并升级所有可升级的软件。虽然arduino-cli我们通常用官方脚本安装但更新系统能避免一些潜在的依赖库冲突。接下来需要安装一些基础编译工具和依赖这对于后续arduino-cli正常工作以及编译ESP32的代码至关重要sudo apt install -y git curl python3-pip cmake ninja-build ccache libusb-1.0-0-dev这里解释一下几个关键包的作用git用于克隆代码仓库curl用来下载安装脚本python3-pip是Python包管理器某些ESP32工具链可能会用到cmake和ninja-build是现代化的构建系统ESP32的Arduino核心在编译时会用到ccache可以显著加速重复编译的速度libusb库则是与USB设备比如我们的开发板通信所必需的。注意如果你的树莓派是全新的或者之前没有进行过开发环境配置这一步的依赖安装非常重要。缺少libusb或cmake可能会导致后续识别板子或编译失败错误信息往往比较隐晦提前装好能省去很多排查时间。2.2 安装与配置arduino-cliArduino官方提供了非常方便的安装脚本。我们不推荐通过apt安装可能存在的旧版本直接使用官方脚本能确保获得最新且功能完整的arduino-cli。下载并安装 在终端中执行以下命令。这条命令会从Arduino官网下载安装脚本并直接运行它将arduino-cli安装到当前用户的/home/pi/bin目录下如果该目录不存在会自动创建。curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh配置环境变量 安装脚本通常会自动将可执行文件路径添加到当前shell的会话中。但为了永久生效我们需要将其添加到用户的配置文件里。编辑~/.bashrc文件nano ~/.bashrc在文件末尾添加一行export PATH$PATH:/home/pi/bin然后按CtrlX再按Y最后回车保存退出。让配置立即生效source ~/.bashrc验证安装与初始化配置 现在输入以下命令应该能看到arduino-cli的版本信息arduino-cli version接下来需要进行初始化生成默认的配置文件(arduino-cli.yaml)和创建必要的目录结构arduino-cli config init你可以查看一下默认的配置其中会显示Sketchbook项目草图的存放路径等arduino-cli config dump至此arduino-cli本体就安装配置完成了。它的设计非常简洁所有功能都通过子命令调用比如board list查看板子compile编译upload上传等。接下来我们要解决最关键的问题如何让arduino-cli支持ESP32-C3这块板子。3. 添加ESP32-C3硬件支持包3.1 理解硬件支持包与板卡管理器Arduino生态之所以能支持成千上万种开发板核心机制在于“硬件支持包”。对于官方板子如Uno, Mega支持是内置的。但对于像ESP32、STM32这类第三方板子就需要手动添加对应的“硬件支持包”。这个包里面包含了该系列芯片的编译工具链、烧录工具、核心库函数定义以及板子的配置信息如引脚定义、闪存大小等。arduino-cli通过“板卡管理器”来维护和安装这些包。我们需要告诉它一个“附加开发板管理器网址”这个网址指向存放ESP32支持包的索引文件。3.2 添加ESP32硬件支持包源ESP32的Arduino核心主要由乐鑫官方社区维护。我们需要添加它的包源。执行以下命令arduino-cli config add board_manager.additional_urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json这个命令会修改之前生成的arduino-cli.yaml配置文件添加一个新的源地址。你可以用arduino-cli config dump再次查看确认additional_urls下面已经包含了这个网址。3.3 更新索引并安装ESP32核心添加源之后需要更新本地的包索引这样才能知道有哪些可安装的包及其版本。arduino-cli core update-index更新完成后就可以搜索并安装ESP32的核心了。搜索命令如下arduino-cli core search esp32在输出列表中你应该能看到一个名为esp32:esp32的核心。接下来安装它。请注意ESP32的工具链和框架体积比较大大约1GB在树莓派上安装需要一些时间请保持网络连接稳定。arduino-cli core install esp32:esp32这个命令会下载并安装ESP32系列芯片包括ESP32-C3所需的所有工具编译器xtensa-esp32-elf 和 riscv32-esp-elf、烧录工具esptool.py、OpenOCD调试服务器以及Arduino核心库本身。安装成功后会显示“Installed esp32:esp32”。实操心得安装过程可能会因为网络问题中断。如果遇到下载失败可以尝试重新运行安装命令。arduino-cli支持断点续传。另外安装路径默认在~/.arduino15/packages下如果后续磁盘空间紧张可以清理旧版本的核心包。3.4 确认ESP32-C3板卡支持安装完核心后我们可以列出所有现在可用的开发板看看ESP32-C3在不在里面arduino-cli board listall | grep -i c3或者更精确地搜索合宙的板子如果你用的是合宙ESP32-C3arduino-cli board listall | grep -i lilygo通常合宙的ESP32-C3板子在Arduino核心中对应的FQBN完全合格的板子名称是esp32:esp32:esp32c3。你可以看到类似这样的输出esp32:esp32:esp32c3 (ESP32C3 Dev Module)。这证明硬件支持包已经成功添加并且系统已经识别到了这款板子。4. 创建项目与编写第一个程序4.1 初始化一个Arduino项目Sketch在Arduino语境下一个项目被称为一个“Sketch”。我们首先创建一个新的Sketch目录和主文件。创建项目目录你可以任意选择位置。我在家目录下创建一个esp32c3_projects的文件夹来管理所有相关项目。mkdir -p ~/esp32c3_projects/first_blink cd ~/esp32c3_projects/first_blink创建Sketch文件Sketch的主文件必须是一个.ino文件且文件名与所在目录名一致这是Arduino IDE的传统arduino-cli也遵循。这里我们的目录叫first_blink所以创建first_blink.ino。touch first_blink.ino4.2 编写经典的Blink程序我们用经典的“闪烁LED”程序来测试。ESP32-C3开发板上通常有一颗连接到GPIO8不同板子可能不同请以你的板子原理图为准的板载LED。对于常见的合宙ESP32-C3板载LED是接在GPIO8上的且低电平点亮。用你喜欢的文本编辑器如nano或vim打开first_blink.ino文件nano first_blink.ino输入以下代码// 定义LED连接的引脚。合宙ESP32-C3板载LED通常接GPIO8 const int ledPin 8; // 初始化函数只在启动时运行一次 void setup() { // 将LED引脚设置为输出模式 pinMode(ledPin, OUTPUT); } // 循环函数会一遍又一遍地重复运行 void loop() { digitalWrite(ledPin, LOW); // 输出低电平点亮LED对于此板 delay(1000); // 等待1000毫秒1秒 digitalWrite(ledPin, HIGH); // 输出高电平熄灭LED delay(1000); // 再等待1秒 }代码解析setup(): 单片机启动后的初始化例程这里只做一件事把ledPinGPIO8配置为数字输出引脚。loop(): 主循环。先给引脚低电平LOW点亮LED延时1秒再给高电平HIGH熄灭LED再延时1秒。如此循环就实现了LED的闪烁。重要提示引脚电平与LED亮灭的关系取决于硬件电路。大部分ESP32-C3开发板的板载LED是“低电平有效”即引脚输出LOW时LED导通发光。如果你的板子不同可能需要将LOW和HIGH对调。保存并退出编辑器在nano中是CtrlX然后Y回车。5. 编译与上传代码到ESP32-C35.1 连接开发板与确认端口在编译上传之前需要先用USB线将ESP32-C3开发板连接到树莓派的USB口上。连接开发板使用一条可靠的Micro-USB或Type-C数据线最好是数据线而非仅充电线连接。查看串口设备连接后树莓派会自动识别到一个新的串口设备。通常设备名是/dev/ttyACM0或/dev/ttyUSB0。可以通过以下命令查看ls /dev/ttyACM* /dev/ttyUSB* 2/dev/null在连接板子前后分别执行一次新出现的那个设备就是你的ESP32-C3。记下这个设备路径例如/dev/ttyACM0。使用arduino-cli列出板子arduino-cli也能帮你发现已连接的板子arduino-cli board list这个命令会列出所有通过USB连接的Arduino兼容板并显示其FQBN和对应的串口地址。输出应该类似Port Protocol Type Board Name FQBN /dev/ttyACM0 serial Serial Port (USB) ESP32C3 Dev Module esp32:esp32:esp32c3这个信息非常关键它确认了三点板子被正确识别、其FQBN是esp32:esp32:esp32c3、使用的串口是/dev/ttyACM0。5.2 编译Sketch编译是将我们写的.ino代码和引用的库翻译成ESP32-C3芯片能执行的机器码的过程。使用以下命令进行编译arduino-cli compile --fqbn esp32:esp32:esp32c3 first_blink.ino参数解释--fqbn esp32:esp32:esp32c3指定目标板子的完全限定名。这告诉编译器使用我们之前安装的ESP32核心中针对esp32c3这个变体的配置包括CPU类型、闪存布局、引脚定义等进行编译。first_blink.ino要编译的Sketch主文件。如果一切顺利编译过程会在终端输出大量信息最后以“项目使用了 X 字节占用了 Y% 的程序存储空间。最大为 Z 字节。”结束这表示编译成功并在当前目录下生成了二进制文件。注意事项第一次为某个FQBN编译时arduino-cli可能需要下载一些额外的工具或缓存索引可能会稍慢。编译过程中如果报错最常见的原因是FQBN写错了。仔细检查板子名称区分大小写。缺少某个库。如果代码中包含了#include SomeLibrary.h你需要先用arduino-cli lib install SomeLibrary来安装。开发板支持包没有正确安装。可以尝试arduino-cli core update-index和arduino-cli core install esp32:esp32重装。5.3 上传程序到开发板编译成功后就可以将二进制文件烧录到ESP32-C3的闪存中了。上传前ESP32-C3需要处于“下载模式”。对于大部分开发板通常有两种方式进入下载模式按住板子上的“BOOT”或“DOWNLOAD”按钮不放再按一下“RESET”按钮然后松开“RESET”最后松开“BOOT”。有些板子包括合宙的部分型号在上电或复位时会自动检测串口DTR/RTS信号无需手动操作。我们先尝试自动上传arduino-cli和esptool.py会尝试通过控制DTR和RTS线来自动触发板子进入下载模式。使用以下命令arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32c3 first_blink.ino参数解释-p /dev/ttyACM0指定上传使用的串口端口替换成你arduino-cli board list看到的实际端口。--fqbn esp32:esp32:esp32c3同样需要指定板子类型。first_blink.inoSketch文件。如果上传成功你会看到输出信息显示“烧录成功”并且板子会自动复位运行。此时你应该能看到ESP32-C3板载的LED开始以1秒的间隔规律闪烁。5.4 手动进入下载模式的上传方法如果自动上传失败终端卡住或报错“连接超时”就需要我们手动让板子进入下载模式。断开USB线或者按一下板子的复位键RST。按住板子上的“BOOT”按钮有些板子标为“IO0”或“DOWNLOAD”不要松开。在按住“BOOT”按钮的同时将USB线插入树莓派或者按一下“RST”按钮。等待大约1秒然后松开“BOOT”按钮。此时板子应处于下载模式。立即在终端中运行上面的上传命令。这次应该能成功上传。上传完成后板子会自动复位并运行新程序。6. 项目进阶串口打印与库管理6.1 添加串口调试输出闪烁LED只能验证最基本的GPIO功能。在实际开发中串口打印是调试和输出信息的生命线。我们修改一下first_blink.ino加入串口功能。const int ledPin 8; void setup() { // 初始化串口通信波特率设置为115200 Serial.begin(115200); // 等待串口连接对于USB-CDC这行不是必须的但保留是好习惯 while (!Serial) { delay(10); } Serial.println(ESP32-C3 Blink with Serial Started!); pinMode(ledPin, OUTPUT); } void loop() { digitalWrite(ledPin, LOW); Serial.println(LED ON); delay(1000); digitalWrite(ledPin, HIGH); Serial.println(LED OFF); delay(1000); }重新编译上传后我们还需要一个工具来查看串口输出。在树莓派上可以使用screen命令简单但功能少或者更强大的minicom。安装minicomsudo apt install minicom -y使用minicom监听串口 首先确保你的程序已经上传并在运行。然后在另一个终端窗口中运行minicom -D /dev/ttyACM0 -b 115200参数-D指定设备-b指定波特率必须和代码中Serial.begin(115200)设置的保持一致。如果连接成功你将看到“ESP32-C3 Blink with Serial Started!”以及交替出现的“LED ON”和“LED OFF”信息。按CtrlA然后按X再按回车可以退出minicom。6.2 使用arduino-cli管理第三方库很多项目需要用到传感器、显示屏等外部模块这些通常由社区以库的形式提供。arduino-cli可以方便地搜索、安装和管理库。例如假设我们需要一个用于驱动DHT11温湿度传感器的库。搜索库arduino-cli lib search DHT11这会列出所有名称或描述中包含“DHT11”的库。通常我们会选择DHT sensor library。安装库arduino-cli lib install DHT sensor library注意库名要用引号括起来特别是当名称中有空格时。查看已安装库arduino-cli lib list在项目中使用库 安装后就可以在代码中使用#include DHT.h了。arduino-cli在编译时会自动在库路径中查找。实操心得库的版本管理很重要。如果你发现某个库的新版本导致项目不兼容可以安装特定版本。例如arduino-cli lib install DHT sensor library1.4.4。使用arduino-cli lib list可以查看已安装库的版本。7. 常见问题排查与优化技巧7.1 上传失败问题排查表问题现象可能原因解决方案上传错误串口 /dev/ttyACM0 不存在或没有权限1. 板子未连接或连接松动。2. 当前用户没有串口设备的读写权限。1. 检查USB线重新插拔。2. 将用户加入dialout组sudo usermod -a -G dialout $USER注销并重新登录生效。或临时使用sudo运行上传命令不推荐长期使用。连接超时 / 等待上传端口超时1. 板子未进入下载模式。2. 串口端口号错误。3. 有其它程序占用了串口如minicom未关闭。1. 参考上文“手动进入下载模式”操作。2. 用arduino-cli board list或ls /dev/tty*确认端口。3. 关闭所有可能占用该端口的终端或程序。A fatal error occurred: Failed to connect to ESP32-C31. 驱动程序问题在Linux上较少见。2. 板子型号选择错误FQBN。3. USB线质量差或仅能充电。1. 确保已安装libusb我们之前已装。2. 仔细核对arduino-cli board list显示的FQBN。3. 更换一条已知良好的数据线。编译错误对‘xxx’未定义的引用1. 缺少必要的库。2. 库已安装但未正确包含#include。3. 库版本与代码不兼容。1. 根据错误信息安装对应库。2. 检查代码中的#include语句。3. 尝试安装库的其它版本。7.2 编译速度优化ESP32的代码编译比较耗时在树莓派上更是如此。我们可以通过两个方法显著提升编译体验启用ccache编译器缓存我们在第一步已经安装了ccache。arduino-cli需要配置才能使用它。编辑Arduino的全局配置文件~/.arduino15/arduino-cli.yaml如果不存在用arduino-cli config init生成添加或修改以下行builder: compiler: cache: enabled: true path: /home/pi/.arduino15/cache保存后下次编译就会利用缓存对于重复编译仅修改少量代码的情况速度提升非常明显。在RAM磁盘上编译树莓派的SD卡读写速度是瓶颈。我们可以将临时编译目录指向内存中的/tmp这是一个tmpfs文件系统速度极快。这需要修改arduino-cli的编译命令指定构建路径arduino-cli compile --fqbn esp32:esp32:esp32c3 --build-path /tmp/arduino_build first_blink.ino这样编译的中间文件都会放在/tmp/arduino_build下。注意/tmp下的内容在重启后会消失但这不影响最终的二进制输出和上传。7.3 项目结构与多文件管理当项目变大时把所有代码都写在.ino文件里会很难维护。arduino-cli支持多文件项目结构。你可以在Sketch目录下创建额外的.cpp和.h文件。例如创建一个LED.cpp和LED.h来封装LED操作LED.h#ifndef LED_H #define LED_H #include Arduino.h class LED { private: int pin; bool state; public: LED(int pinNumber); void begin(); void on(); void off(); void toggle(); }; #endifLED.cpp#include LED.h LED::LED(int pinNumber) : pin(pinNumber), state(false) {} void LED::begin() { pinMode(pin, OUTPUT); off(); } void LED::on() { digitalWrite(pin, LOW); // 假设低电平点亮 state true; } void LED::off() { digitalWrite(pin, HIGH); state false; } void LED::toggle() { state ? off() : on(); }然后在主first_blink.ino中#include LED.h LED myLed(8); void setup() { Serial.begin(115200); myLed.begin(); Serial.println(Project with Class Started.); } void loop() { myLed.on(); Serial.println(ON); delay(1000); myLed.off(); Serial.println(OFF); delay(1000); }直接使用之前的编译命令arduino-cli会自动将同目录下的.cpp文件一起编译链接。这种结构让代码更清晰也便于复用。7.4 固件烧录失败后的恢复偶尔操作不当如断电可能导致ESP32-C3的引导程序损坏无法再通过串口下载。这时需要用到“串口强制下载模式”。这需要将GPIO9有些板子是IO0在芯片上电时保持为低电平。具体操作因板子硬件设计而异通常需要将GPIO9或标记为“IO0”的引脚用杜邦线接地GND。给板子上电或按复位键。此时芯片会进入固件烧录模式再执行arduino-cli upload命令。上传成功后断开GPIO9与GND的连接重新上电即可正常启动。这个操作有点“硬核”但它是救活一块“变砖”的开发板最后的手段。具体引脚请务必查阅你所使用的ESP32-C3开发板的原理图或手册。