发布于 

嵌入式开发环境配置实战

一句话结论

只用一套工具就选 PlatformIO:一份 platformio.ini 覆盖 AVR / ESP8266 / ESP32 / STM32 / RP2040,库依赖写进配置就能复现环境,换机器只需 git clone && pio run。要深挖 ESP32 再补一套 ESP-IDF,要搞 STM32 底层再补 STM32CubeIDE。Arduino IDE 只用来跑别人的示例和教学。

零、装工具之前:先把通用地基打好

0.1 工具链选型总表

工具 主力场景 支持平台 优点 缺点 建议
PlatformIO(VS Code 插件 / CLI) 日常主力 AVR、ESP8266/32、STM32、RP2040、nRF、Mbed 等数十种 依赖可复现、库管理强、多环境、CLI 可进 CI 冷门板卡支持滞后、调试配置要手改 首选,本文重点
Arduino IDE 2.x 教学、跑示例、快速验证 Arduino 全系 + ESP8266/32 + RP2040 等 上手最快、示例最多、自带串口绘图仪 库版本不可锁定、无项目概念、大项目难维护 备用,别拿它做正经项目
ESP-IDF ESP32 深度开发 仅乐鑫 ESP32 全系 官方框架、FreeRTOS、组件化、安全特性(Secure Boot / Flash 加密)最全 学习曲线陡、构建慢、文档量大 需要 ESP32 全部能力时
STM32CubeIDE / CubeMX STM32 裸机与 HAL 仅 ST 图形化配引脚时钟、自动生成初始化、内置调试 只管 ST、代码生成器会覆盖手写部分 搞 STM32 必备
Arduino CLI 无 GUI / CI / 批量 同 Arduino 可脚本化 配置繁琐 自动化场景
MicroPython / CircuitPython 快速原型、教学 ESP8266/32、RP2040、部分 STM32 REPL 交互式、改完即跑 性能与实时性差、占 Flash 原型验证
树莓派 / Jetson 官方工具 Linux 单板 对应板卡 官方镜像、开箱即用 与普通嵌入式工具链不通用 单起章节讲

0.2 先认清你的 USB 转串口芯片

板子插上电脑后第一步不是装 IDE,而是确认它用什么 USB 转串口芯片。下面的命令直接复制执行。

# —— Linux ——
lsusb                                     # 列出 USB 设备
dmesg -w                                  # 插拔一次,看内核打印(Ctrl+C 退出)
ls -la /dev/ttyUSB* /dev/ttyACM* 2>/dev/null
udevadm info -q property -n /dev/ttyUSB0 2>/dev/null | grep -E "ID_VENDOR|ID_MODEL"

# —— macOS ——
system_profiler SPUSBDataType | grep -A5 -i "serial\|USB"
ls /dev/cu.*

# —— Windows(PowerShell,需管理员) ——
Get-PnpDevice -PresentOnly | Where-Object { $_.FriendlyName -match "COM|USB Serial|CH34|CP210|FT232" } | Select-Object FriendlyName, InstanceId
# 或在设备管理器里看「端口 (COM 和 LPT)」下的名字

常见芯片对照:

丝印 / 设备名 厂商 驱动 典型出现位置 VID:PID
CH340 / CH341 沁恒 WCH 需装驱动(Win7/10 部分版本自带) Arduino Nano 克隆、ESP8266/ESP32 廉价板 1A86:7523(CH340)、1A86:5523(CH341)
CP210x(CP2102/CP2104) Silicon Labs Win10+ 多自带 NodeMCU、ESP32 DevKitC、部分 STM32 板 10C4:EA60
FT232RL / FT2232 FTDI Win 自带 / 官方 VCP 高端下载器、Arduino 原装(用的是 ATmega16U2 另算) 0403:6001
ATmega16U2 / 8U2 Microchip 免驱(CDC ACM) Arduino Uno R3 原装 2341:0043 等
原生 USB(ESP32-S2/S3/C3、RP2040) — 免驱 CDC ESP32-S3 DevKitC 的 USB 口、Pico 结果为 /dev/ttyACM*,不是 ttyUSB

⚠️ 注意:ESP32-S3 / S3 类板子通常有两个口:标 USB 的是原生 USB(CDC / JTAG 调试),标 UART 的是经 CP210x/CH340 转出来的串口。程序下载走哪个口取决于板子设计,插错口 pio run -t upload 会连不上。两个口都试一遍是最快的判定方法。

0.3 Windows 驱动安装

# 方式一:winget 安装串口驱动(管理员 PowerShell)
winget install --id WCH.CH34xSER       # CH340/CH341
winget install --id SiliconLabs.CP210xVCP  # CP210x(若仓库有收录)
winget install --id FTDI.FTDISerialDriver  # FT232(通常系统自带,非必要)

# 方式二:ST-Link / J-Link 调试器驱动
winget install --id STMicroelectronics.STLinkDriver  # 若提示无此包,去 ST 官网下 STSW-LINK009

# 方式三:zadig 给 libusb 类设备(OpenOCD、逻辑分析仪)换驱动
winget install --id pbatard.Zadig
驱动 官方下载地址(关键词搜索即可) 装完在设备管理器里应该显示
CH341SER WCH 官网 wch.cn → 产品 → 接口芯片 → CH341 → 驱动 USB-SERIAL CH340 (COMx)
CP210x VCP Silicon Labs 官网 silabs.com → CP210x USB to UART Bridge VCP Drivers Silicon Labs CP210x USB to UART Bridge (COMx)
FTDI VCP ftdichip.com → VCP Drivers USB Serial Port (COMx)
ST-Link V2 ST 官网 → STSW-LINK009 STMicroelectronics STLink dongle(通用串行总线设备里)

装完驱动仍不出现 COM 口的排查顺序:

  1. 换 USB 线。充电线只有 VCC/GND 两根,没有数据线,这是新手第一位故障原因。
  2. 换 USB 口,别接在显示器/键盘的 HUB 上。
  3. 设备管理器里看是否有「未知设备」带黄色感叹号 → 右键更新驱动 → 手动指定目录。
  4. Windows 11 上部分 CH340 克隆被驱动签名拦截 → 需禁用驱动强制签名(启动设置 → 疑难解答 → 高级选项 → 启动设置 → 按 7)。
  5. 板子本身坏:换一台电脑试。

0.4 Linux 串口权限(必做)

# 把当前用户加入 dialout 组(串口设备所属组)
sudo usermod -aG dialout $USER

# 若用 OpenOCD / ST-Link / J-Link / 逻辑分析仪,通常还需 plugdev 与 udev 规则
sudo usermod -aG plugdev $USER

# 查看自己已在哪些组(确认 dialout 出现)
groups

# ⚠️ 必须注销并重新登录(或重启)才生效,仅开新终端无效

不想重新登录的临时办法(重启后失效):

sudo chmod 666 /dev/ttyUSB0

更规范的做法是写 udev 规则,让设备固定名字、固定权限:

# 先查设备的厂商/产品 ID
udevadm info -a -n /dev/ttyUSB0 | grep -E "idVendor|idProduct|serial" | head -6

# 新建规则文件
sudo tee /etc/udev/rules.d/99-usb-serial.rules > /dev/null <<'EOF'
# CH340
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0666", SYMLINK+="ttyCH340"
# CP210x
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="0666", SYMLINK+="ttyCP210"
# FT232
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666", SYMLINK+="ttyFTDI"
# ST-Link V2(供 OpenOCD / stlink 使用,无需 root)
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", MODE="0666", GROUP="plugdev"
# ST-Link V2.1(Nucleo 板载)
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="374b", MODE="0666", GROUP="plugdev"
EOF

# 重载规则并触发
sudo udevadm control --reload-rules && sudo udevadm trigger

# 验证:拔插设备后应该出现固定别名的软链接
ls -la /dev/ttyCH340 /dev/ttyCP210 2>/dev/null

⚠️ 注意:MODE="0666" 等于任何用户都能读写串口,方便但降低安全性。多人共享的机器上建议改用 GROUP="dialout", MODE="0660" 并把用户加进 dialout。

Ubuntu 上还有一个高频坑:

# brltty(盲文终端守护进程)会抢占 CH340,导致 /dev/ttyUSB0 出现几秒后消失
systemctl status brltty-udev.service 2>/dev/null
sudo apt remove brltty          # 确认不用盲文设备就直接卸载

0.5 macOS 注意事项

# 查看串口(macOS 用 cu.* 而非 tty.*,cu 是 callout 设备,不会被系统占用)
ls /dev/cu.*

# 连接串口
screen /dev/cu.usbserial-1420 115200
# 退出 screen:Ctrl+A 然后按 k,再按 y 确认

# Homebrew 装常用工具
brew install --cask visual-studio-code
brew install minicom esptool stlink open-ocd sigrok-cli

⚠️ 注意:较新的 Mac(Apple Silicon + macOS 12+)上 CH340 驱动需要允许系统扩展:开机按住电源键进恢复模式 → 安全策略 → 勾选「允许用户管理来自被认可开发者的内核扩展」。CP210x 与 FTDI 情况类似,具体以驱动厂商的安装说明为准。

0.6 网络加速:镜像源的思路

乐鑫、PlatformIO 的索引和工具链都在境外,国内直连经常超时。可选方案:

目标 原始地址 替代思路
Arduino ESP32 索引 https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 用 ghproxy / jsDelivr 等公共加速前缀改写 URL;或离线下载索引与工具包后放到本地 HTTP 服务。具体镜像域名会变动,以当时可用的镜像为准
PlatformIO 平台包 https://dl.registry.platformio.org 设置环境变量 PLATFORMIO_CORE_DIR 换缓存目录;离线时可把已下载的 ~/.platformio 整个目录拷贝到新机器
ESP-IDF 工具链 https://github.com/espressif/...、https://dl.espressif.com 安装时设置 IDF_GITHUB_ASSETS="dl.espressif.com/github_assets" 走乐鑫国内 CDN
pip 包 https://pypi.org/simple pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple(清华源)
GitHub Release / git clone github.com 配置 git 代理,或用 git config --global url."https://ghproxy.com/https://github.com/".insteadOf 形式改写。镜像域名随时可能失效,别写进长期脚本
# pip 换清华源(通用、长期稳定)
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

# ESP-IDF 走乐鑫国内 CDN(安装前设置)
export IDF_GITHUB_ASSETS="dl.espressif.com/github_assets"

# git 走代理(按你自己的代理端口改)
git config --global http.proxy  http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
# 用完取消
git config --global --unset http.proxy
git config --global --unset https.proxy

一、Arduino IDE 2.x

1.1 安装

# —— Windows(管理员 PowerShell) ——
winget install ArduinoSA.IDE.stable        # 2.x 稳定版
# 或 winget install ArduinoSA.IDE.nightly  # 抢先版

# —— Ubuntu / Debian ——
# 官方 deb 与 AppImage 版本更新更快,优先官网下载;仓库版通常较旧
sudo apt install arduino

# —— 通用:官网下载 AppImage(Linux,无需 root)——
# https://www.arduino.cc/en/software → Linux AppImage 64 bits
chmod +x arduino-ide_2.x.x_Linux_64bit.AppImage
./arduino-ide_2.x.x_Linux_64bit.AppImage --no-sandbox

# —— macOS ——
brew install --cask arduino-ide

# —— 命令行版(服务器/CI 用,无 GUI)——
# https://arduino.github.io/arduino-cli/latest/installation/
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
arduino-cli config init
arduino-cli core update-index
arduino-cli core install arduino:avr

1.2 添加 ESP32 / ESP8266 板卡支持

菜单路径:File → Preferences(首选项)→ Additional boards manager URLs(附加开发板管理器网址),填入(多个地址用英文逗号分隔或每行一个):

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
https://arduino.esp8266.com/stable/package_esp8266com_index.json
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

然后:Tools → Board → Boards Manager → 搜索 esp32 → 安装 "esp32 by Espressif Systems"。

ESP32 索引访问不畅时的处理思路(镜像域名会变,以下为方法而非固定地址):

# 思路 A:手动下载索引文件,起本地 HTTP 服务再把 URL 指向 127.0.0.1
curl -L -o package_esp32_index.json \
  https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
python3 -m http.server 8111 --directory .
# 然后在 Arduino 首选项里填 http://127.0.0.1:8111/package_esp32_index.json
# 索引里各工具包的 URL 仍指向 github,需一并替换或配合代理使用

# 思路 B:用公共加速前缀改写原始 URL(前缀域名以当时可用的为准)
# 例:https://<加速前缀>/https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

# 思路 C:直接用 Arduino CLI 走系统代理
export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890
arduino-cli core update-index --additional-urls \
  https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

1.3 板卡关键参数(ESP32 为例)

菜单项 常用值 说明
Board ESP32S3 Dev Module / ESP32 Dev Module / ESP32C3 Dev Module 按你的芯片选,选错会下载失败或运行异常
USB CDC On Boot Enabled(S3/C3 用原生 USB 串口时) 关掉的话 Serial 走外部 UART 芯片
CPU Frequency 240MHz (WiFi) 想省电选 80/160 MHz
Flash Mode QIO 80MHz 一般不动
Flash Size 4MB (32Mb) / 16MB (128Mb) 与实际颗粒一致,超出部分写不进去
Partition Scheme Default 4MB with spiffs / 16M Flash (3MB APP) 程序放不下就换更大 APP 分区的方案
PSRAM OPI PSRAM(S3 带 PSRAM 的板) 不打开就用不了那 8 MB PSRAM
Upload Speed 921600 下载不稳定就降到 115200
Port 实际 COM 口 / /dev/ttyUSB0 为空说明驱动没装好

1.4 验证:点灯 + 打印芯片信息

// Arduino:Blink + 芯片信息打印(ESP32 / ESP8266 / AVR 通用写法)
#ifndef LED_BUILTIN
  #define LED_BUILTIN 2   // 多数 ESP32 开发板的板载 LED 在 GPIO2
#endif

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  delay(1000);

  Serial.println("\n==== board info ====");
  Serial.printf("CPU Freq      : %u MHz\n", getCpuFrequencyMhz());   // AVR 无此函数,需删掉
  Serial.printf("Flash Size    : %u bytes\n", ESP.getFlashChipSize());
  Serial.printf("Free Heap     : %u bytes\n", ESP.getFreeHeap());
  Serial.printf("Chip Model    : %s rev %u\n", ESP.getChipModel(), ESP.getChipRevision());
  Serial.printf("SDK Version   : %s\n", ESP.getSdkVersion());
  Serial.println("====================");
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  Serial.println("tick");   // 串口监视器应每 1 秒打印一次
}

⚠️ 注意:getCpuFrequencyMhz()、ESP.getChipModel() 是 ESP32 专有 API,Arduino Uno(AVR)上编译会报错,用 Uno 时把这些行删掉,只保留 pinMode / digitalWrite / Serial.println。ESP.getFlashChipSize() 在 ESP8266 上也可用于验证 Flash 是否虚标。

打开 Tools → Serial Monitor,右下角波特率选 115200(与代码一致),看到每秒一行 tick 即成功。

1.5 Arduino IDE 常见报错排查

现象 原因 解法
Tools → Port 灰色不可选 驱动未装 / 数据线只有电源线 / 权限不足 见 0.3、0.4 节;Linux 确认 groups 里有 dialout 并已重登录
Failed to connect to ESP32: Timed out waiting for packet header 芯片没进下载模式 按住 BOOT 键 → 点上传 → 出现 Connecting... 后松开 BOOT;或给 EN 对地接 10 µF 电容
A fatal error occurred: Wrong boot mode detected (0x13) GPIO0 未拉低 / strapping 引脚被外设占用 手动进下载模式;检查 GPIO0/2/12 上是否接了会改变电平的外设
Sketch too big(区溢出) 分区方案 APP 空间不足 换 APP 更大的 Partition Scheme;关掉 Tools → USB CDC On Boot 之外的冗余功能;精简库
Compilation error: xxx.h: No such file or directory 库没装或装错版本 Sketch → Include Library → Manage Libraries 搜索安装;注意库与板卡架构是否匹配
下载成功但串口无输出 波特率不一致 / TX-RX 没交叉 / 用了外部串口口 监视器波特率改为代码里的值;换另一个 USB 口;S3/C3 打开 USB CDC On Boot
编译时卡在 Downloading tools 十几分钟 网络访问索引/工具链超时 挂代理或按 1.2 的镜像思路处理;Arduino IDE 2.x 的下载目录在 ~/.arduino15/staging(Windows: %LOCALAPPDATA%\Arduino15\staging)
exit status 1 且日志里出现 python 相关 系统 Python 与工具链冲突 Linux 上确认 python3 存在;Windows 上删掉 PATH 里多余的 Python 软链接(Microsoft Store 版最容易冲突)
上传完板子反复重启 供电不足 / 代码里访问了非法地址触发 panic 换 USB 口或外接 5 V 电源;打开串口日志看 panic 行,用 ESP32 Exception Decoder 或 addr2line 定位

二、PlatformIO(推荐主力)

2.1 安装

# 方式一(推荐):VS Code 扩展
# 扩展市场搜索 "PlatformIO IDE"(作者 PlatformIO),安装后重启 VS Code,左侧出现外星人图标

# 方式二:仅装 CLI(服务器 / CI / 不爱用 VS Code)
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade platformio
pio --version

# 把常用命令做成短别名,写进 ~/.bashrc 或 ~/.zshrc
cat >> ~/.bashrc <<'EOF'
alias pio='platformio'
alias piob='pio run -t upload'
alias piom='pio device monitor'
EOF
source ~/.bashrc

⚠️ 注意:PlatformIO 首次启动会下载平台包与工具链,体积可达数 GB,务必在稳定网络下等待完成。Windows 上若卡在 Installing PlatformIO Core,多半是杀软拦截或 Python 冲突,尝试以管理员运行 VS Code 一次。

2.2 项目目录结构

my_project/
├── platformio.ini        # 唯一需要手写的配置文件,一切依赖写在这里
├── src/                  # 源码(.c / .cpp / .ino 都可以)
│   └── main.cpp
├── include/              # 头文件
├── lib/                  # 本地私有库(每个库一个子目录)
│   └── my_driver/
│       ├── my_driver.h
│       └── my_driver.cpp
├── test/                 # 单元测试(pio test)
└── .pio/                 # 构建产物(务必加进 .gitignore)
# .gitignore 必须包含
printf '.pio/\n.vscode/\n' >> .gitignore

# 从零初始化一个项目(交互式选板卡)
pio project init --board esp32-s3-devkitc-1 --project-option="framework=arduino"

2.3 platformio.ini 完整注释示例

; ===== 通用区:所有环境共享 =====
[env]
platform = espressif32
framework = arduino

; 串口监视器波特率,必须和代码里 Serial.begin() 一致
monitor_speed = 115200
; 监视器端口,不写则自动探测;多设备时强烈建议写死
; monitor_port = /dev/ttyUSB0
; 监视器过滤器:esp32_exception_decoder 可直接把 panic 地址翻译成代码行
monitor_filters = esp32_exception_decoder, time, colorize
; 打开后串口收到 DTR/RTS 变化不复位板子(某些场景需要)
; monitor_rts = 0
; monitor_dtr = 0

; 依赖库,支持三种写法:
;   1) 库名                → 从 PIO 注册表拉最新稳定版
;   2) 库名@^版本号        → 语义化版本锁定
;   3) https://git 地址    → 直接用仓库
lib_deps =
    adafruit/Adafruit SSD1306@^2.5.7
    paulstoffregen/OneWire@^2.3.8
    knolleary/PubSubClient@^2.8
    https://github.com/bblanchon/ArduinoJson.git#v7.0.4

; 编译期宏,等同于代码里的 #define
build_flags =
    -D CORE_DEBUG_LEVEL=3          ; ESP32 日志级别 0=None 1=Error 2=Warn 3=Info 4=Debug 5=Verbose
    -D MY_WIFI_SSID=\"myap\"        ; 字符串宏要转义引号
    -D BAUD=115200
    -Wall -Wextra                  ; 打开更多编译警告

; ===== ESP32-S3 开发环境 =====
[env:esp32-s3-devkitc-1]
board = esp32-s3-devkitc-1
; board 已隐含 platform/framework,这里重复声明只为演示,不写也行
framework = arduino
monitor_speed = 115200
upload_speed = 921600
; upload_port 多设备时写死端口,Windows 写 COM3,Linux 写 /dev/ttyUSB0
upload_port = /dev/ttyACM0
lib_deps =
    ${env.lib_deps}                 ; 继承通用区的依赖
    adafruit/Adafruit NeoPixel@^1.12.0
build_flags =
    ${env.build_flags}
    -D ARDUINO_USB_CDC_ON_BOOT=1    ; S3 用原生 USB 串口
    -D BOARD_HAS_PSRAM=1            ; 启用 PSRAM
board_build.arduino.memory_type = qio_opi   ; Flash + PSRAM 均为 OPI 模式(S3 常见)
board_build.partitions = default_16MB.csv   ; 16MB Flash 的分区表
board_upload.flash_size = 16MB

; ===== ESP32-C3 量产小板 =====
[env:esp32-c3-devkitm-1]
board = esp32-c3-devkitm-1
framework = arduino
monitor_speed = 115200
upload_speed = 460800
; 使用 esptool 之外的下载协议(C3/S3 支持 esp-builtin 走 USB-OTG)
upload_protocol = esptool
build_flags =
    ${env.build_flags}
    -D ARDUINO_USB_CDC_ON_BOOT=1

; ===== STM32 蓝丸:用 ST-Link 下载并调试 =====
[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = arduino            ; 也可改为 stm32cube / cmsis / libopencm3
upload_protocol = stlink
debug_tool = stlink
monitor_speed = 115200
build_flags =
    -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC      ; 启用 USB 虚拟串口
    -D PIO_FRAMEWORK_ARDUINO_STANDARD_LIB
    -D HSE_VALUE=8000000U                    ; 蓝丸外部晶振 8 MHz,填错则时钟全错

; ===== Arduino Uno(AVR)=====
[env:uno]
platform = atmelavr
board = uno
framework = arduino
monitor_speed = 9600
upload_port = /dev/ttyACM0

; ===== Raspberry Pi Pico(RP2040)=====
[env:pico]
platform = raspberrypi
board = pico
framework = arduino
upload_protocol = picotool     ; 或 mbed / cmsis-dap(用另一块 Pico 当调试器)
monitor_speed = 115200

2.4 常用命令速查

# —— 构建 ——
pio run                          # 编译当前默认环境(或全部环境)
pio run -e esp32-s3-devkitc-1    # 只编译指定环境
pio run -t clean                 # 清理构建产物
pio run -v                       # 显示完整编译命令(查宏定义问题时很有用)

# —— 下载 ——
pio run -t upload                # 编译并烧录
pio run -t upload -e uno         # 指定环境
pio run -t nobuild_upload        # 跳过编译直接烧录
pio run -t upload --upload-port /dev/ttyUSB0    # 临时指定端口
pio run -t uploadfs              # 烧录文件系统(LittleFS/SPIFFS)镜像
pio run -t erase                 # 全片擦除 Flash

# —— 串口 ——
pio device monitor               # 打开串口监视器(Ctrl+C 退出)
pio device list                  # 列出所有串口设备及 VID/PID(找端口用这个最快)
pio device monitor -b 115200 -p /dev/ttyUSB0 --eol LF

# —— 库管理 ——
pio pkg search "ssd1306"         # 搜索库
pio pkg search "mqtt" --platform "espressif32"     # 限定平台搜索
pio pkg install --library "knolleary/PubSubClient@^2.8"   # 安装并写进 platformio.ini
pio pkg list                     # 列出当前项目依赖
pio pkg outdated                 # 检查可升级的依赖
pio pkg update                   # 更新依赖
pio pkg uninstall "OneWire"

# —— 平台与板卡 ——
pio platform install espressif32
pio platform list
pio boards esp32-s3              # 按关键词查板卡 ID
pio settings get                 # 查看全局配置

# —— 调试(需 debug_tool,ST-Link / J-Link / esp-builtin)——
pio debug                        # 启动调试会话(VS Code 里按 F5 更好用)
pio test -e native               # 在 PC 上跑单元测试(环境 platform = native)

# —— 项目信息 ——
pio project config               # 打印解析后的完整配置(排查继承问题神器)
pio run -t sizedata              # 查看固件体积

2.5 库依赖管理要点

写法 含义 何时用
Adafruit SSD1306 按名字模糊匹配 快速试,但可能装到同名不同库
adafruit/Adafruit SSD1306 指定作者,精确 推荐
adafruit/Adafruit SSD1306@^2.5.7 语义化版本锁定 做项目必用,避免半年后编译不过
adafruit/Adafruit SSD1306@2.5.7 精确版本 需要完全可复现时
https://github.com/xxx/yyy.git#v1.2.3 Git 仓库 + tag/分支/commit 库未发布到注册表时用,务必钉 commit
file:///abs/path/to/lib / symlink://../lib 本地路径 同时开发库和项目时

依赖锁定的正确姿势:

# 生成的 .pio/libdeps/<env>/ 里有实际安装的版本
# 把版本写回 platformio.ini 就是"锁定";更彻底的做法:
pio pkg list --json-output > pio-deps-$(date +%F).json    # 留档

⚠️ 注意:lib_deps 只写库名不写版本是最常见的团队协作地雷。一年后新同事拉代码,库 API 已不兼容,编译报错且难以定位。所有依赖都带 @^版本号 或钉死 commit。

2.6 验证:helloworld + 读芯片 ID

# 1) 确认板子被识别
pio device list
# 期望输出包含 /dev/ttyUSB0(或 COM3),并带 VID/PID 与描述

# 2) 建工程并跑通
mkdir -p ~/pio_hello/src && cd ~/pio_hello
cat > platformio.ini <<'EOF'
[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
monitor_speed = 115200
upload_speed = 921600
EOF

cat > src/main.cpp <<'EOF'
#include <Arduino.h>

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.printf("Chip   : %s rev %u\n", ESP.getChipModel(), ESP.getChipRevision());
  Serial.printf("Cores  : %u  Freq: %u MHz\n", ESP.getChipCores(), getCpuFrequencyMhz());
  Serial.printf("Flash  : %u MB\n", ESP.getFlashChipSize() / 1024 / 1024);
  Serial.printf("PSRAM  : %u bytes\n", ESP.getPsramSize());
  Serial.printf("Heap   : %u bytes free\n", ESP.getFreeHeap());
  Serial.printf("MAC    : %s\n", WiFi_mac_to_string().c_str());
}

void loop() { delay(1000); }
EOF

上面最后一行需要额外实现,用下面这版更省事(直接打印 MAC 字节):

#include <Arduino.h>
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.printf("Chip   : %s rev %u\n", ESP.getChipModel(), ESP.getChipRevision());
  Serial.printf("Cores  : %u  Freq : %u MHz\n", ESP.getChipCores(), getCpuFrequencyMhz());
  Serial.printf("Flash  : %u MB\n", ESP.getFlashChipSize() / 1024 / 1024);
  Serial.printf("PSRAM  : %u bytes\n", ESP.getPsramSize());
  Serial.printf("Heap   : %u bytes free\n", ESP.getFreeHeap());
  uint8_t mac[6];
  esp_read_mac(mac, ESP_MAC_WIFI_STA);
  Serial.printf("MAC    : %02X:%02X:%02X:%02X:%02X:%02X\n",
                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void loop() { delay(1000); }
pio run -t upload && pio device monitor
# 期望看到芯片型号、频率、Flash 大小、MAC 地址,说明工具链/驱动/下载链路全通

2.7 PlatformIO 常见报错排查

现象 原因 解法
Error: Please specify upload_port`` 没探测到串口 pio device list 确认;板子驱动见 0.3/0.4;多设备时在 ini 里写死 upload_port
Error: Unknown board ID 'xxx' 板卡名写错 pio boards esp32 查正确 ID
fatal error: xxx.h: No such file or directory 库未装 / 库与平台不兼容 pio pkg search 后加进 lib_deps;检查库是否支持该 framework
undefined reference to ... 只装了头文件没装实现,或 C/C++ 混编没加 extern "C" 确认库完整;C 头在 C++ 里用 extern "C" { } 包住
PlatformIO Core is not responding Core 进程崩溃,多因杀软/权限 VS Code 里 PlatformIO: Rebuild IntelliSense Index;或 pio --version 确认 CLI 正常
编译通过但板子无反应 程序没跑起来 / 分区表不对 看串口日志;确认 board_build.partitions 与 Flash 实际大小匹配
libdeps 下载失败 网络 挂代理;或手动下载库放到 lib/ 目录(本地目录不需要下载)
中文路径导致编译报奇怪错误 路径含中文/空格 项目路径改成纯英文无空格
pio run 报 Permission denied Linux 串口权限 见 0.4 节
构建很慢(每次全量) 正常;或 .pio 被误删 可开启 build_cache_dir = ~/.platformio/.cache 复用编译缓存

三、ESP-IDF(乐鑫官方框架)

3.1 安装

# ===== Windows:最简单,用官方离线/在线安装包 =====
# https://dl.espressif.com/dl/esp-idf/  下载 ESP-IDF Tools Offline / Online Installer
# 装完桌面会有 "ESP-IDF 5.x PowerShell" / "CMD" 快捷方式,用它启动即自动配好环境变量

# ===== Linux / macOS:git 克隆 + install.sh =====
sudo apt update
sudo apt install git wget flex bison gperf python3 python3-pip python3-venv \
                 cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0

mkdir -p ~/esp && cd ~/esp
git clone -b v5.4 --recursive https://github.com/espressif/esp-idf.git
# 子模块拉取失败时重复执行(很常见,网络问题)
cd ~/esp/esp-idf && git submodule update --init --recursive

# 走乐鑫国内 CDN 加速工具链下载
export IDF_GITHUB_ASSETS="dl.espressif.com/github_assets"
cd ~/esp/esp-idf
./install.sh esp32 esp32s2 esp32s3 esp32c3 esp32c6     # 只装你需要的目标,能省几 GB

# ===== 备用:pip 装的 esp-idf 只提供工具管理,源码仍需上面的 git 仓库 =====

# ===== VS Code 插件(推荐配合)=====
# 扩展市场搜 "Espressif IDF",安装后 Ctrl+Shift+P → "ESP-IDF: Configure ESP-IDF extension"

每次开新终端都要导入环境:

# 一次性把别名写进 shell 配置
echo "alias get_idf='. \$HOME/esp/esp-idf/export.sh'" >> ~/.bashrc
source ~/.bashrc

# 之后每次开发前执行
get_idf
idf.py --version        # 验证

3.2 完整开发流程

# 1) 从示例建工程(比 mkdir 省事,examples 里有几百个可直接抄的模板)
cd ~/esp
cp -r $IDF_PATH/examples/get-started/hello_world ./my_app
cd my_app

# 2) 设定目标芯片(只影响编译目标,可随时改;改后建议 fullclean)
idf.py set-target esp32s3
# 常见值:esp32 / esp32s2 / esp32s3 / esp32c3 / esp32c6 / esp32h2 / esp32p4

# 3) 图形化配置(会生成/更新 sdkconfig)
idf.py menuconfig

# 4) 编译
idf.py build
# 只看大小:idf.py size / idf.py size-components / idf.py size-files

# 5) 烧录(全片 + 所有分区),-p 指定端口,-b 指定波特率
idf.py -p /dev/ttyUSB0 -b 921600 flash
# 只烧 app 分区(迭代调试快很多)
idf.py -p /dev/ttyUSB0 app-flash

# 6) 打开串口监视器
idf.py -p /dev/ttyUSB0 monitor
# 退出:Ctrl+]

# 7) 一条龙:烧录 + 监视
idf.py -p /dev/ttyUSB0 flash monitor

# 8) 其他常用子命令
idf.py fullclean          # 删除整个 build 目录(换 target 或改了大配置后必做)
idf.py reconfigure        # 强制重跑 CMake 配置
idf.py erase-flash        # 全片擦除
idf.py partition-table    # 打印当前分区表
idf.py efuse-summary      # 查看 eFuse 状态(安全特性)
idf.py monitor --print-filter "wifi:*,esp_netif:*"   # 只打印指定 tag 的日志

3.3 menuconfig 关键配置项

idf.py menuconfig 里的路径按 / 搜索关键词最快(按 / 后输入关键词回车即可跳转)。

配置路径 作用 典型值 / 建议
Serial flasher config → Flash size Flash 容量 与颗粒一致(4 MB / 8 MB / 16 MB)。设大于实际会导致写入越界失败
Serial flasher config → Flash SPI mode QIO / DIO / OPI 默认 QIO;S3 带 OPI PSRAM 时用对应模式
Serial flasher config → Flash SPI speed 40 / 80 / 120 MHz 默认 80 MHz,稳定性差就降 40 MHz
Serial flasher config → Default baud rate 下载波特率 921600 快但不稳;失败降 115200
Component config → ESP PSRAM → Support for external PSRAM PSRAM 使能 带 PSRAM 的板必须开,否则 heap_caps_malloc(MALLOC_CAP_SPIRAM) 失败
Component config → ESP PSRAM → SPI RAM config → Mode QUAD / OCT S3 用 OCT(OPI);ESP32 用 QUAD(QSPI)
Component config → ESP System Settings → CPU frequency CPU 频率 80 / 160 / 240 MHz;功耗敏感选 160
Component config → ESP System Settings → Task Watchdog 看门狗 调试阶段可关(不推荐长期关)
Component config → Partition Table → Partition Table 分区表 Single factory app, no OTA / Factory app, two OTA definitions / Custom partition table CSV
Component config → Log output → Default log verbosity 日志级别 开发 Debug/Verbose,量产 Warning/Error(日志本身拖慢速度且占 Flash)
Component config → Log output → Color 日志颜色 Always(好看)或 Never(重定向到文件时)
Component config → FreeRTOS → Kernel tick rate 系统 tick 默认 100 Hz;需要更精细延时可改 1000 Hz(增加开销)
Component config → Wi-Fi → WiFi Task Core WiFi 任务跑在哪个核 双核场景可固定到 core 0,把应用留给 core 1
Component config → ESP-TLS / mbedTLS TLS 相关 做 HTTPS/MQTT-TLS 时按需开启证书包
Component config → Hardware Settings → Sleep Config 功耗 电池项目要配
Security features(需目标支持) Secure Boot / Flash Encryption 开发阶段切勿开启,eFuse 不可逆

自定义分区表示例(partitions.csv,然后在 menuconfig 里选 Custom partition table CSV 并填文件名):

# Name,   Type, SubType, Offset,   Size,     Flags
nvs,      data, nvs,     0x9000,   0x5000,
otadata,  data, ota,     0xe000,   0x2000,
app0,     app,  ota_0,   0x10000,  0x200000,
app1,     app,  ota_1,   0x210000, 0x200000,
spiffs,   data, spiffs,  0x410000, 0x3F0000,

⚠️ 注意:app 分区的 Offset 必须 0x10000(64 KB)对齐。改分区表后 OTA 数据可能失效,务必 idf.py erase-flash 再 flash。

3.4 验证:hello_world + 崩溃定位

/* main/hello_world_main.c —— 官方示例改一行,加芯片信息打印 */
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"

void app_main(void)
{
    printf("Hello world!\n");

    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), WiFi%s%s, silicon revision %d, ",
           CONFIG_IDF_TARGET, chip_info.cores,
           (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
           chip_info.revision);

    unsigned major_rev = 0;
    esp_flash_init(NULL);
    printf("%uMB %s flash\n", 0u, "external");
    printf("Minimum free heap size: %u bytes\n", esp_get_minimum_free_heap_size());

    fflush(stdout);
    vTaskDelay(pdMS_TO_TICKS(2000));
    printf("Restarting now.\n");
    fflush(stdout);
    esp_restart();
}

崩溃时(Guru Meditation Error / abort())用地址翻译工具定位代码行:

# IDF 自带:把 monitor 里的 backtrace 地址喂给它
idf.py monitor | tee crash.log
# 复制 backtrace 里的 0x4xxxxxxx 地址后:
xtensa-esp32s3-elf-addr2line -pfiaC -e build/hello_world.elf 0x4200abcd 0x4037cdef

# 或者直接让 monitor 自动解码(ESP-IDF 5.x 默认已开启 panic 地址解码)

3.5 ESP-IDF 常见报错排查

现象 原因 解法
idf.py: command not found 没导入环境 执行 . $HOME/esp/esp-idf/export.sh(或 get_idf)
CMake Error: The following variables are used in this project... 换过 target 没清 build idf.py fullclean && idf.py set-target <chip> && idf.py build
A fatal error occurred: Failed to connect to ESP32 下载模式/串口问题 按住 BOOT 再执行;降波特率 -b 115200;检查端口
idf.py menuconfig 打不开(乱码 / 报错) 终端太小或缺少 ncurses 终端窗口拉大;Linux sudo apt install libncurses-dev 后重装工具链
编译报 esp_psram.h: No such file PSRAM 未使能 menuconfig 打开 PSRAM 支持
region 'flash' overflowed 固件超出 app 分区 换更大 app 分区的分区表;关日志;-Os 优化:CONFIG_COMPILER_OPTIMIZATION_SIZE=y
E (xxx) spi_flash: Detected size(4096k) smaller than the size in the binary image header menuconfig 的 Flash size 大于实际 改回实际值;必要时 esptool.py flash_id 确认真实容量
Brownout detector was triggered 供电不足 换电源/USB 口;或在 menuconfig 里调低 Brownout 阈值(治标不治本)
下载后串口乱码 波特率不对 / 晶振配置错 监视器 115200;检查 CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ 与实际晶振
install.sh 卡在下载 xtensa-esp32-elf 网络 export IDF_GITHUB_ASSETS="dl.espressif.com/github_assets" 后重跑

四、STM32:CubeIDE / CubeMX / OpenOCD

4.1 STM32CubeIDE 与 CubeMX

# ===== 安装 =====
# STM32CubeIDE(含 CubeMX + GCC + GDB + 调试):ST 官网搜索 STM32CubeIDE,需注册 ST 账号下载
# Linux 解压安装:
chmod +x st-stm32cubeide_*.sh
sudo ./st-stm32cubeide_*.sh

# Ubuntu 上常缺的依赖
sudo apt install libncurses5 libusb-1.0-0-dev

# 独立 CubeMX(只想生成代码不想装 Eclipse)
# ST 官网 → STM32CubeMX → 下载 → java -jar SetupSTM32CubeMX-*.exe

CubeMX 生成项目的关键步骤(顺序很重要):

  1. File → New Project → 选芯片型号(如 STM32F103C8Tx),别选错封装。
  2. Pinout 视图:配置 RCC → HSE = Crystal/Ceramic Resonator;SYS → Debug = Serial Wire(这一步忘了,下次就下不进程序)。
  3. Clock Configuration:HSE 8 MHz → PLL → HCLK = 72 MHz(F103 上限),回车让工具自动解算。
  4. Connectivity / Timers / ADC 里按需开外设。
  5. Project Manager → 设置工程名与路径(英文无空格)→ Toolchain/IDE 选 STM32CubeIDE(或 Makefile 想用 CLI)。
  6. Code Generator 里勾选 Generate peripheral initialization as a pair of .c/.h files(外设代码分文件,好维护)。
  7. Generate Code。

⚠️ 注意:CubeMX 生成的代码只在 /* USER CODE BEGIN */ 与 /* USER CODE END */ 之间保留手写内容。Regenerate 会覆盖其他地方,写代码务必放进 USER CODE 块里。

验证:在 main.c 的 while(1) 里加翻转,观察板载 LED(多数蓝丸是 PC13,低电平点亮):

/* main.c —— 放在 while(1) 的 USER CODE BEGIN WHILE 里 */
while (1)
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    HAL_UART_Transmit(&huart1, (uint8_t*)"hello stm32\r\n", 13, HAL_MAX_DELAY);
    HAL_Delay(500);
    /* USER CODE END WHILE */
}
# ===== 安装 =====
# Linux
sudo apt install openocd gdb-multiarch stlink-tools
# macOS
brew install open-ocd stlink arm-none-eabi-gdb
# Windows:用 ST 的 STM32CubeProgrammer,或用 MSYS2 / xpack 提供的 OpenOCD
#   xpack 版(推荐):https://github.com/xpack-dev-tools/openocd-xpack/releases

# ===== 确认调试器被识别 =====
lsusb | grep -i "st-link\|0483"
st-info --probe            # stlink-tools 提供,能读出芯片信息即成功
# 期望输出类似:Found 1 stlink programmers ... chip id: 0x410 (STM32F1xx medium-density)

用 OpenOCD 烧录:

# F103 蓝丸(stlink + target 脚本名按芯片换)
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg \
        -c "program build/my_app.elf verify reset exit"

# F4 系列
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \
        -c "program build/my_app.bin 0x08000000 verify reset exit"

# 查看所有可用脚本
ls /usr/share/openocd/scripts/target/ | grep stm32
ls /usr/share/openocd/scripts/interface/ | grep stlink

起 GDB server 做源码级调试:

# 终端 1:启动 OpenOCD(保持运行)
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg

# 终端 2:GDB 连接(默认端口 3333)
arm-none-eabi-gdb build/my_app.elf
(gdb) target extended-remote localhost:3333
(gdb) monitor reset halt
(gdb) load
(gdb) break main
(gdb) continue
(gdb) info registers
(gdb) x/16xw 0x20000000        # 查看 SRAM 起始处
(gdb) monitor flash info 0     # 查看 Flash 信息

PlatformIO 里则只需在 platformio.ini 写 debug_tool = stlink 然后按 F5。

4.3 st-flash 命令行(最轻量的烧录方式)

# 查芯片
st-info --probe
st-info --flash --size         # Flash 大小(单位字节)
st-info --chipid
st-info --serial

# 烧录(.bin 需带地址 0x08000000,.elf 自动解析)
st-flash write firmware.bin 0x08000000
st-flash write firmware.elf 0x08000000
st-flash --reset write firmware.bin 0x08000000

# 读取 Flash(备份/固件提取)
st-flash read dump.bin 0x08000000 0x10000     # 读 64 KB

# 擦除
st-flash erase

# 起 GDB server(端口 4242)
st-util

⚠️ 注意:st-flash 对设置了 RDP Level 1 读保护的芯片会失败(Failed to read memory / unknown chip id)。解除需全片擦除(st-flash erase 可能也要先改 option bytes),且解除会清空 Flash,数据不可恢复。

4.4 串口 ISP 下载(无调试器时)

原理:把 BOOT0 拉高(接 3.3 V)、BOOT1 拉低,复位后芯片进系统 Bootloader,通过 USART1(PA9/PA10)下载。

板卡 BOOT0 跳线位置 操作顺序
蓝丸 STM32F103C8T6 板边两个黄色跳线,标 BOOT0 / BOOT1 BOOT0 跳到 1 → 按 RESET → 下载 → BOOT0 跳回 0 → 再按 RESET 运行
正点原子/野火板 BOOT0 排针 + B0 接 3.3 V 同上
Nucleo / Discovery 一般不用(板载 ST-Link) —
# stm32flash(Linux / macOS,F1/F4 支持较好)
sudo apt install stm32flash
# Windows 图形工具:FlyMCU(mcuisp 的老牌国产工具,仅 Windows,选"编程后执行")

# 查看设备
stm32flash /dev/ttyUSB0
# 期望输出芯片型号与 Flash 大小;若报 "Failed to init device",说明没进 Bootloader 模式

# 烧录
stm32flash -w firmware.bin -v -g 0x08000000 /dev/ttyUSB0
#   -w 写入  -v 校验  -g 从指定地址开始执行  -b 波特率(默认 57600)

# 读取
stm32flash -r dump.bin -S 0x08000000 -s 65536 /dev/ttyUSB0

# 解除读保护(会清空 Flash!)
stm32flash -k /dev/ttyUSB0

# ESP32 / Raspberry Pi 也能当 ISP 下载器(stm32flash 的 GPIO 变体)

FlyMCU 的关键设置(Windows 图形界面):

选项 值
串口 实际 COM 口
波特率 76800(FlyMCU 默认,可试 115200)
选项字节区 一般不要勾"编程到配置",容易锁死芯片
编程后执行 勾选
校验 / 写入 都勾

4.5 STM32 常见报错排查

现象 原因 解法
Error: No Device Found / st-info --probe 无输出 ST-Link 驱动没装 / 接线松 / 目标板没供电 装 STSW-LINK009;检查 SWDIO/SWCLK/GND/VCC 四根线;目标板单独供电
Error: init mode failed (unable to connect to the target) SYS → Debug 没配成 Serial Wire,或 SWD 引脚被复用为 GPIO CubeMX 里 SYS → Debug = Serial Wire 重新生成;或用串口 ISP 擦掉重烧
WARN: UNEXPECTED idcode 芯片型号选错 / 是国产替代(GD32/CH32) 换 target 脚本;GD32 需用适配版 OpenOCD
st-flash: unknown chip id 芯片被读保护 / 处于低功耗模式 / 接线错 按住 RESET 再执行;st-flash erase(会清 Flash);串口 ISP 解除保护
下载成功但程序不跑 BOOT0 还在 1;或复位电路问题 BOOT0 跳回 0 并复位
时钟不对(串口乱码、延时不准) HSE_VALUE 与实际晶振不符 CubeMX 里按板上实际晶振填(蓝丸常见 8 MHz,部分克隆是 12 MHz,以丝印为准)
HAL_UART_Transmit 卡死 外设时钟未使能 / 引脚配置错 检查 CubeMX 里 USART 引脚与 GPIO Alternate Function
程序跑一会就死 栈溢出 / 中断优先级配置错 增大 stack_size;检查 FreeRTOS 的 configTOTAL_HEAP_SIZE
CubeIDE 编译报 make: *** No rule to make target 路径含中文/空格 工程路径改纯英文

五、树莓派

5.1 烧录系统

# ===== 官方工具 Raspberry Pi Imager(跨平台,最省事)=====
# Windows: winget install RaspberryPiFoundation.RaspberryPiImager
# Linux:   sudo apt install rpi-imager
# macOS:   brew install --cask raspberry-pi-imager

# Imager 里的关键设置(点右下角齿轮进"高级设置",或按 Ctrl+Shift+X):
#   ✔ 设置主机名         → raspberrypi.local
#   ✔ 开启 SSH           → 选"使用密码认证"或"只允许公钥认证"
#   ✔ 设置用户名与密码   → 注意:新版系统不再有默认 pi/raspberry
#   ✔ 配置无线局域网     → 填 SSID / 密码 / 国家 CN
#   ✔ 设置区域设置       → 时区 Asia/Shanghai、键盘布局 us
#   ✔ 持久化保存设置     → 下次烧录复用

# ===== 命令行烧录(Linux / macOS)=====
# 先确认设备名,别写错盘符
lsblk          # Linux
diskutil list  # macOS

# 方法 A:dd(简单粗暴,写错盘符会毁数据)
sudo dd if=2024-11-19-raspios-bookworm-armhf.img of=/dev/sdX bs=4M conv=fsync status=progress
sync

# 方法 B:rpi-imager --cli(支持高级选项,推荐)
sudo rpi-imager --cli --os-list                        # 列出可选系统
sudo rpi-imager --cli \
  --os "Raspberry Pi OS (64-bit)" \
  --sd-card /dev/sdX \
  --options ssh.enabled=1,ssh.passwordAuthentication=1,ssh.username=pi,ssh.password=xxx,\
wifi.ssid=MyAP,wifi.password=xxx,wifi.country=CN,\
hostname=raspberrypi.local,locale.timezone=Asia/Shanghai,locale.keymap=us

⚠️ 注意:dd 的 of=/dev/sdX 写错会直接抹掉你电脑的硬盘。执行前务必用 lsblk 反复确认容量与分区,sdX 不带数字(写整盘而非分区)。

5.2 无头(headless)配置

Imager 已能预配一切;若用 dd 烧录,则在 boot 分区(Windows 下可见的那个 FAT32 分区)手动放文件:

# 挂载 boot 分区后(Linux 自动挂载到 /media/$USER/bootfs 或 /run/media/...)
cd /media/$USER/bootfs

# 1) 开 SSH:放一个名为 ssh 的空文件(无扩展名)
touch ssh

# 2) 配 WiFi(Bookworm 及之后推荐用 NetworkManager 的 keyfile 方式)
#    传统 wpa_supplicant.conf 在新版系统可能不再被读取,优先用 Imager
cat > wpa_supplicant.conf <<'EOF'
country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="你的SSID"
    psk="你的密码"
    key_mgmt=WPA-PSK
}
EOF

# 3) 新版 Bookworm 的替代方案:NetworkManager 连接文件(放在 boot 分区根目录)
#    文件名会被系统自动拷贝为 /etc/NetworkManager/system-connections/*.nmconnection
cat > mywifi.nmconnection <<'EOF'
[connection]
id=mywifi
type=wifi
autoconnect=true

[wifi]
mode=infrastructure
ssid=你的SSID

[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=你的密码

[ipv4]
method=auto

[ipv6]
method=auto
EOF

# 4) 用户配置(Bookworm 起,userconf.txt 取代了默认 pi 用户)
#    生成密码哈希(在任意 Linux 上执行,树莓派自带的 openssl 也行)
echo 'mypassword' | openssl passwd -6 -stdin
#    把输出写进 userconf.txt,格式 用户名:哈希
echo 'pi:$6$xxxxxxxxxxxxxxxx$yyyyyyyy...' > userconf.txt

sync && umount /media/$USER/bootfs

首次登录:

# 方式一:mDNS(同局域网,无需知道 IP)
ssh pi@raspberrypi.local         # Windows 需装 Bonjour 或用 -o 直连 IP
#   默认密码由你自己在 Imager 里设定;老版本镜像默认是 pi / raspberry

# 方式二:找 IP
#   路由器后台看 DHCP 列表;或
ping -c1 raspberrypi.local
nmap -sn 192.168.1.0/24          # 扫描整个网段找树莓派(MAC 前缀通常是 B8:27:EB 或 DC:A6:32 或 E4:5F:01)

# 首次登录后必做
sudo apt update && sudo apt full-upgrade -y
sudo raspi-config

5.3 raspi-config 常用项

sudo raspi-config
# 命令行非交互模式(写进自动化脚本)
sudo raspi-config nonint do_ssh 0              # 0=开 1=关
sudo raspi-config nonint do_camera 0           # 启用摄像头(旧版;新版用 do_camera 0 或 libcamera 自动)
sudo raspi-config nonint do_i2c 0              # 启用 I2C
sudo raspi-config nonint do_spi 0              # 启用 SPI
sudo raspi-config nonint do_serial 2           # 0=登录shell 1=关闭 2=启用串口但不开登录shell
sudo raspi-config nonint do_onewire 0          # 启用 1-Wire
sudo raspi-config nonint do_expand_rootfs      # 扩容文件系统到整张卡
sudo raspi-config nonint do_hostname mypi
sudo raspi-config nonint do_wifi_country CN
sudo raspi-config nonint get_config do_ssh     # 查询当前值
sudo raspi-config nonint do_boot_behaviour B2  # B1=进桌面需登录 B2=进桌面自动登录 B3=CLI需登录 B4=CLI自动登录

启用 I2C/SPI 后必须确认设备节点存在:

ls /dev/i2c-* /dev/spidev*.* 2>/dev/null
lsmod | grep -E "i2c_dev|spi_bcm2835"
sudo apt install -y i2c-tools
i2cdetect -y 1            # 扫描 I2C 总线 1(老板是 0),看到设备地址即成功

5.4 GPIO 库选型

库 实现方式 支持板卡 性能 现状 / 推荐度
RPi.GPIO 直接操作 /dev/gpiomem 寄存器 仅树莓派(BCM283x/271x) 中(软件 PWM,翻转约 100 kHz 量级) 已停止维护,Pi 5 不支持,新项目别用
gpiozero 基于 lgpio(新)或 RPi.GPIO(旧)的高层封装 树莓派为主 低(面向教学,抽象多) 适合教学与简单场景,API 最友好
libgpiod / gpiod 内核 GPIO character device(/dev/gpiochipN) 通用 Linux(树莓派、Jetson、RK、全志) 中高 新项目首选,官方推荐,跨板通用,有 C/Python 绑定
lgpio 直接寄存器访问,用户态 树莓派(含 Pi 5) 高 需要精确时序时用;是 gpiozero 在新系统上的后端
pigpio 守护进程 + 寄存器,支持远距离网络控制 树莓派 高(硬件定时 PWM、波形生成) 强大但 Pi 5 支持需额外处理
sysfs GPIO(/sys/class/gpio) 老接口 通用 低 已废弃,新内核不再推荐
# 装库
sudo apt install -y python3-gpiozero python3-rpi.gpio python3-libgpiod gpiod python3-pigpio

# gpiod 命令行工具(排错神技)
gpioinfo                 # 列出所有 gpiochip 与引脚状态
gpiodetect               # 列出 gpiochip
gpioget gpiochip0 17     # 读 GPIO17
gpioset gpiochip0 17=1   # 写 GPIO17 高电平(默认写完立即释放!)
gpioset --mode=wait gpiochip0 17=1    # 保持直到 Ctrl+C
gpiomon gpiochip0 17     # 监视引脚电平变化(查按键/中断很方便)

# 把用户加进 gpio 组,避免每次 sudo
sudo usermod -aG gpio $USER

三种库的最小点灯代码:

# ===== libgpiod(推荐,跨板通用)=====
# pip install gpiod   (注意:v2.x 与 v1.x API 差异巨大,以下代码为 v2.x)
import gpiod, time
from gpiod.line import Direction, Value

chip = gpiod.Chip('/dev/gpiochip0')
req = chip.request_lines(
    consumer="blink",
    config={17: gpiod.LineSettings(direction=Direction.OUTPUT)}
)
for _ in range(10):
    req.set_values({17: Value.ACTIVE})
    time.sleep(0.5)
    req.set_values({17: Value.INACTIVE})
    time.sleep(0.5)
req.release()
# ===== gpiozero(最简单,教学首选)=====
from gpiozero import LED, Button
from signal import pause

led = LED(17)
btn = Button(2)
btn.when_pressed  = led.on
btn.when_released = led.off
pause()          # 阻塞等待事件
# ===== RPi.GPIO(老项目维护用,Pi 5 不支持)=====
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
p = GPIO.PWM(17, 50)          # 50 Hz 软件 PWM
p.start(7.5)                  # 占空比 7.5%(SG90 舵机中位)
try:
    while True: time.sleep(1)
finally:
    p.stop(); GPIO.cleanup()

5.5 远程与摄像头快速验证

# 摄像头(Bookworm 起统一用 libcamera,raspistill 已废弃)
libcamera-hello --list-cameras        # 列出摄像头(这一步能识别就成功一半)
libcamera-still -o test.jpg           # 拍一张
libcamera-vid -t 10000 -o test.h264   # 录 10 秒
sudo apt install -y python3-picamera2  # Python 接口(仅 64 位系统)

# 远程桌面
sudo apt install -y xrdp              # Windows 远程桌面直连
sudo raspi-config nonint do_vnc 0     # 或 RealVNC

# 系统健康检查
vcgencmd measure_temp                 # CPU 温度
vcgencmd get_throttled                # 0x0 才正常;非 0 说明曾欠压/过温降频
vcgencmd measure_volts core
dmesg | grep -i "under-voltage"
df -h && free -h

⚠️ 注意:vcgencmd get_throttled 返回值含义(常见位):0x0 正常;0x50000 曾欠压;0x50005 当前正在欠压并降频。出现欠压说明电源不行,换 5 V/3 A(Pi 4)或 5 V/5 A(Pi 5)官方电源。

5.6 树莓派常见报错排查

现象 原因 解法
绿灯不闪 / 彩虹屏不动 镜像烧录失败 / SD 卡坏 / 电源不足 重烧镜像;换 SD 卡(Class 10 A1 以上);换电源
反复重启 电源电流不足(最常见) 换 3 A(4B)/ 5 A(5)电源,别用电脑 USB 口
ssh: Could not resolve hostname raspberrypi.local 没开 mDNS / 跨网段 用 IP 直连;Linux 装 avahi-daemon;Windows 装 Bonjour
Permission denied (publickey) Imager 里选了"只允许公钥"但没导公钥 重烧并在 Imager 里填公钥,或选密码认证
Connection refused(SSH) SSH 未启用 boot 分区放 ssh 空文件;或 Imager 高级设置里开
WiFi 连不上 国家码/频段/密码错;5 GHz 兼容性 设 country=CN;先用 2.4 GHz;确认不是 WPA3-only 的 AP
i2cdetect 全 -- I2C 未启用或接线错 raspi-config 开 I2C;确认 SDA/SCL 与 GND 共地
RuntimeError: No access to /dev/mem 权限 sudo 运行;或 sudo usermod -aG gpio $USER 后重登录
This module can only be run on a Raspberry Pi 用了 RPi.GPIO 但在 Pi 5 / 非树莓派上 换 gpiozero / libgpiod
系统卡死 SD 卡寿命/散热 dmesg 看 I/O 错误;Pi 4/5 加散热片

六、NVIDIA Jetson

6.1 SDK Manager 刷机流程

# ===== 准备工作 =====
# 宿主机要求:Ubuntu 20.04 或 22.04 的 x86_64 物理机/虚拟机(虚拟机刷机成功率低,建议物理机)
# SDK Manager 下载:developer.nvidia.com/sdk-manager(.deb 包)

sudo apt install ./sdkmanager_*.deb
sdkmanager &

# 命令行模式(适合自动化与断网重来)
sdkmanager --cli install \
  --logintype devzone \
  --product Jetson \
  --version 6.1 \
  --targetos Linux \
  --target PACK_NAME \
  --flash all \
  --select 'Jetson Orin Nano Super 8GB' \
  --additionaloptions '{"targetImageFolder":"~/nvidia/nvidia_sdk"}'

刷机步骤要点:

步骤 操作 说明
1 进入 Recovery 模式 断电 → 用跳线/杜邦线短接 FC REC 与 GND 引脚 → 上电(或用 Type-C 线连好后按住 REC 键再按 RST 键,松开 RST 再松开 REC)
2 用 Type-C 线连宿主机 宿主机执行 lsusb,应看到 NVIDIA Corp. APX(0955:7323 等)
3 SDK Manager 检测 选目标板(Orin Nano Super / NX / AGX)与 JetPack 版本
4 下载并烧写 约 20–60 分钟,含 OS 镜像、CUDA、cuDNN、TensorRT、VPI、DeepStream
5 板端完成初始化 首次启动会进 Ubuntu 设置界面,建用户、连 WiFi
6 装 jetson-stats sudo pip3 install -U jetson-stats 后重启
# 确认进 Recovery(宿主机上执行)
lsusb | grep -i nvidia
# 期望:Bus 001 Device 0xx: ID 0955:7323 NVIDIA Corp. APX

⚠️ 注意:Jetson Orin Nano 系列官方推荐用 NVMe SSD 启动,SD 卡版本性能和寿命都受限。刷机时 SDK Manager 里要选对存储设备(NVMe / eMMC / SD Card),选错会烧到错误的介质上。

6.2 环境确认

# ===== 版本总览(jetson-stats 提供,最直观)=====
jetson_release
# 输出包含:JetPack 版本、L4T 版本、内核、CUDA、cuDNN、TensorRT、VPI、OpenCV 版本

# 若命令不存在
sudo pip3 install -U jetson-stats
sudo systemctl restart jtop.service
sudo reboot

关键版本核验命令:

# L4T / JetPack 版本
cat /etc/nv_tegra_release
# 或
dpkg-query --show nvidia-l4t-core

# CUDA
nvcc --version                      # 编译器版本
nvidia-smi                          # Jetson 上是精简版输出(tegra 平台)
cat /usr/local/cuda/version.json 2>/dev/null

# cuDNN
dpkg -l | grep -i cudnn
# 或查头文件
grep -E "CUDNN_MAJOR|CUDNN_MINOR|CUDNN_PATCHLEVEL" /usr/include/cudnn_version.h 2>/dev/null
# 老版本在 /usr/include/cudnn.h

# TensorRT
dpkg -l | grep -i tensorrt
python3 -c "import tensorrt as trt; print(trt.__version__); print(trt.Builder(trt.Logger()))"

# OpenCV(是否带 CUDA 加速)
python3 -c "import cv2; print(cv2.__version__); print(cv2.getBuildInformation())" | head -30

# 系统资源与温度(实时)
jtop                                # 交互式,按 1-6 切页面,q 退出
tegrastats                          # 命令行实时:CPU/GPU/内存/温度/功耗
sudo nvpmodel -q                    # 当前功耗模式
sudo nvpmodel -m 0                  # 切到最高性能模式(不同板编号含义不同,用 -q --verbose 看)
sudo jetson_clocks                  # 锁定最高频率(跑 benchmark 时用)
sudo jetson_clocks --restore        # 恢复

# CUDA 示例编译验证
cd /usr/local/cuda/samples/1_Utilities/deviceQuery 2>/dev/null && sudo make && ./deviceQuery

6.3 常用环境配置

# Python 深度学习栈(Jetson 上务必用 NVIDIA 提供的 wheel,别直接 pip install torch)
# PyTorch for Jetson:forums.developer.nvidia.com 的官方安装贴给出对应 JetPack 版本的 whl
sudo apt install -y python3-pip python3-dev
python3 -m pip install -U pip
# 例(版本以官方贴为准,JetPack 6.x + Python 3.10):
# wget https://developer.download.nvidia.com/compute/redist/jp/v61/pytorch/torch-*.whl
# python3 -m pip install torch-*.whl

# 容器化(推荐,避免污染系统环境)
sudo apt install -y nvidia-container docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
# 运行带 GPU 的容器
docker run --runtime nvidia --gpus all -it --rm nvcr.io/nvidia/l4t-base:r36.4.0
# jetson-containers 项目提供一键构建各种 AI 容器(Ultralytics/ROS/LLM 等)
git clone https://github.com/dusty-nv/jetson-containers
cd jetson-containers && ./install.sh

# 验证 GPU 能在容器里用
docker run --runtime nvidia --rm nvcr.io/nvidia/l4t-base:r36.4.0 nvidia-smi

6.4 Jetson 常见报错排查

现象 原因 解法
宿主机 lsusb 看不到 NVIDIA APX 没进 Recovery / Type-C 线是充电线 重做 Recovery 短接步骤;换数据线
SDK Manager 卡在 Flash Jetson OS 虚拟机 USB 掉线 / 权限 用物理机;sudo apt install libgconf-2-4;给 /dev/bus/usb 权限
刷完不开机,无 HDMI 输出 显示器 EDID 问题 / 镜像没烧对 换显示器或先接串口调试;重刷并确认目标存储设备
jetson_release: command not found 没装 jetson-stats sudo pip3 install -U jetson-stats 后重启
nvcc --version 无输出 CUDA 未加入 PATH export PATH=/usr/local/cuda/bin:$PATH 并写进 ~/.bashrc
import tensorrt 报 libnvinfer.so 找不到 环境变量/版本不匹配 确认安装的 TensorRT 版本与 JetPack 对应;ldconfig
磁盘空间不足 JetPack 全套约 20 GB+ 用 NVMe;sudo apt clean;删 /usr/src/ 下用不到的内核源码与 samples
频繁过热降频 散热不足 装风扇;jtop 看温度;sudo jetson_clocks 反而会更热,慎用
pip install torch 装完 import 报错 装了 x86 的 wheel 必须用 NVIDIA 为 Jetson(aarch64) 编译的 whl
系统启动但 USB/CSI 不工作 设备树/载板不匹配 刷机时选正确的载板配置(carrier board)

七、通用调试工具

7.1 逻辑分析仪(查时序问题的唯一利器)

# ===== 软件:sigrok / PulseView(开源免费,支持 Saleae 克隆)=====
# Linux
sudo apt install -y pulseview sigrok-cli libsigrok libsigrokdecode
# macOS
brew install --cask pulseview sigrok-cli
# Windows:sigrok.org 下载 PulseView 安装包

# 命令行抓 I2C(快速验证,不用开 GUI)
sigrok-cli --driver fx2lafw --config samplerate=1M --time 5s -o capture.sr
# 直接解码并打印
sigrok-cli --driver fx2lafw --config samplerate=1M \
           --time 5s --protocol-decoders i2c:scl=0:sda=1 -A i2c

# 解码 UART(自动测波特率)
sigrok-cli --driver fx2lafw --config samplerate=1M --time 10s \
           --protocol-decoders uart:rx=0:baudrate=115200 -A uart

# 列出设备与可用驱动
sigrok-cli --scan
sigrok-cli --show

PulseView 图形界面使用要点:

  1. 采样率设为信号最高频率的 10 倍以上(100 kHz I2C 用 1 MHz 以上,1 MHz SPI 用 8 MHz 以上)。
  2. 抓前先设触发条件(如 SDA 下降沿),避免抓到一段空闲。
  3. 加协议解码器:Decoders → I2C / SPI / UART,填对应通道(CH0/CH1…)。
  4. 解码器可以叠加:I2C 上再叠 SSD1306、SPI 上再叠 MDIO 等。

⚠️ 注意:廉价 24 MHz 8 通道逻辑分析仪(Cypress FX2LP 方案,约 ¥30–50)只能看不能产,且输入电平一般只支持 5 V tolerant 的 TTL,不要直接接 RS232 的 ±12 V 或 CAN 的差分信号,会烧。看 CAN/RS485 需要在收发器之后的 TTL 侧测。

设备 参考价格 采样率 通道 适合
FX2LP 克隆("24MHz 8CH") ¥30–50 24 MHz 8 I2C/SPI/UART 够用,入门首选
树莓派 Pico 自制(pico-logic-analyzer) ¥25 最高可达 100 MHz 级(取决于实现) 8–24 想玩开源固件
DSLogic / Kingst LA 系列 ¥300–1500 100–800 MHz 16–32 高速 SPI、并行总线、时序余量分析
Saleae Logic 8 / Pro ¥2000+ 100–500 MS/s 8–16 专业,模拟+数字混合、协议触发强大

7.2 串口工具

# ===== Linux =====
sudo apt install -y minicom screen picocom tio

# minicom(功能全,需先配置)
sudo minicom -s                    # 进设置:Serial port setup → A 改设备 → E 改波特率/流控
minicom -D /dev/ttyUSB0 -b 115200  # 直接指定
# 退出:Ctrl+A 然后 X

# screen(最省事,但退出键位容易忘)
screen /dev/ttyUSB0 115200
# 退出:Ctrl+A 然后 k → y

# picocom(推荐,退出最直观)
picocom -b 115200 /dev/ttyUSB0 --echo
# 退出:Ctrl+A 然后 Ctrl+X

# tio(现代替代品,自动重连)
tio /dev/ttyUSB0 -b 115200 --log
# 退出:Ctrl+T 然后 q

# 只看输出不交互(抓日志到文件)
cat /dev/ttyUSB0                  # 需先 stty 设波特率
stty -F /dev/ttyUSB0 115200 raw -echo && cat /dev/ttyUSB0 | tee boot.log

Windows:PuTTY(Serial 模式,填 COM 口与波特率)、MobaXterm、SSCOM/串口助手(国产,带十六进制收发与自动应答,适合调试 Modbus 之类二进制协议)。

Windows 首推:ATK-XCOM(正点原子串口调试助手)

上面 PuTTY 那类"终端"工具看日志够用,但调试单片机的双向通信(发指令、看回包、调试协议)时,图形化的串口调试助手效率高一个量级。Windows 上首推正点原子的 ATK-XCOM(免费,v3.0),理由不是它功能最多,而是每一项功能都对准了嵌入式调试的真实痛点:

痛点 XCOM 对应功能 实战用法
设备吐的是二进制不是文本 16 进制收发(发送区字节自动拆分,不用手动加空格) 调 Modbus/自定义帧协议时勾上 HEX,直接看原始字节
一条条敲 AT 指令太慢 多条发送(4 页 × 多条,支持导入导出) 调蓝牙/GSM/WiFi 模块时把整套 AT 指令预先编排好,点击发送
要按键实时控车/飞行器 关联数字键盘(条目 0-9 绑数字键) 智能车方向控制按数字键即发,小键盘当方向键用
帧对不上不知道哪次发的 时间戳显示(按 \r\n 断帧) 注意:数据里没有换行符时时间戳无效——这是它断帧的机制决定的
传输丢包没感知 协议模式(Modbus RTU 变种 + 自动重发 + CRC8/16 校验) IAP 串口升级/可靠传输场景用,可配重发次数与帧周期
高波特率芯片 自定义波特率(需关串口后改) 硬件支持时突破 1382400bps 上限

两个上手就能踩的点提前说:一是16 进制多条发送不做校验——条目里混进非 HEX 字符会静默发送失败,排查"为什么这条没反应"先检查有没有输错;二是时间戳依赖换行回车断帧,如果你的设备固件 printf 不带 \r\n,时间戳和自动换行都会失效,先修固件输出格式。

类似的还有 SSCOM、友善串口调试助手,功能大同小异;选哪个看顺手,关键是十六进制收发、多条发送、定时发送这三个能力必须有——它们覆盖了 90% 的串口调试场景。

macOS:screen /dev/cu.usbserial-xxx 115200、minicom、CoolTerm(GUI)。

波特率自动探测(拿到一块未知板子时):

# 思路:依次尝试常见波特率,看哪个能出可读文本
for b in 9600 19200 38400 57600 74880 115200 230400 460800 921600; do
  echo "--- trying $b ---"
  timeout 3 picocom -b $b /dev/ttyUSB0 --imap lfcrlf -q 2>/dev/null | head -5
done

# 或者用逻辑分析仪/示波器量一位的时长:波特率 ≈ 1 / 位宽
# 更系统的做法见《硬件模块与通信协议基础》的 UART 一节

7.3 万用表实用技巧

档位 典型用途 注意事项
蜂鸣档(通断) 查杜邦线是否断、焊点是否虚焊、GND 是否共地 必须在断电下测;阻值 < 几十欧才响,长线也可能误判
直流电压 确认 3.3 V / 5 V 是否存在、电池电量、分压中点 表笔别同时碰两个相邻引脚,容易短路
直流电流 测整机功耗、睡眠电流 必须串联进回路,且先插 mA 孔(大电流孔保险丝不同);测完立刻换回电压孔,否则下次测电压会短路
电阻 确认上拉电阻值(如 I2C 的 4.7 kΩ)、判断 LED 好坏 断电测,且电容要放电
电容 判断去耦电容是否虚标、滤波电容容量 需从电路上焊下一端再测,否则受并联电路影响
二极管档 判断二极管/LED 极性、三极管管型 LED 正向压降约 1.8–3.3 V(不同颜色不同),表会显示压降

几个高频实用场景:

1) 判断杜邦线好坏:蜂鸣档测两端,不通就换。面包板项目一半的玄学故障源于此。
2) 判断板子是否真上电:黑表笔接 GND,红表笔量 VCC 引脚(不是电源输入端)。
3) 找短路:断电,蜂鸣档测 VCC 与 GND。导通说明有短路,逐段断开外围模块定位。
4) 测功耗:电源 → 万用表(电流档串联)→ 板子 VCC。注意 ESP32 峰值 300 mA+,
   万用表 mA 档保险丝可能扛不住,用带 10 A 孔的档位或专用 USB 电流表。
5) 判断 IO 是否真在翻转:电压档测引脚,若一直在 0 V 或 3.3 V 说明代码没跑;
   若在 1.6 V 左右波动说明在翻转(PWM/通信中)。

7.4 电源:3.3 V 与 5 V、电流不足的排查

参数 5 V 系统(Arduino Uno、舵机、多数传感器模块) 3.3 V 系统(ESP32、STM32、RP2040、树莓派 GPIO)
逻辑高电平阈值 约 > 3.0 V(TTL) / > 0.7×VCC(CMOS) 约 > 2.0 V(具体看芯片数据手册)
常见供电方式 USB 5 V、DC 圆口 7–12 V 经板载 LDO USB 5 V 经板载 AMS1117 转 3.3 V
直接接 5 V 的后果 — ESP32/STM32/RP2040/树莓派 GPIO 大概率永久损坏
3.3 V 信号给 5 V 输入 通常能识别为高电平(临界,不可靠) 需电平转换(见第 3 篇)

电流不足导致反复重启的排查流程:

现象:程序下载正常,但一启动 WiFi / 一转舵机 / 一亮灯就重启;
      串口日志里出现 "Brownout detector was triggered"(ESP32)
      或树莓派右上角出现闪电图标 / dmesg 报 under-voltage

排查顺序:
1) 换 USB 口:台式机后置口 > 前置口 > 笔记本口 > USB HUB(HUB 最差)
2) 换线:细长线压降大;数据线要 28AWG/24AWG 以上(越粗越好)
3) 换电源:ESP32 项目按 5 V/1 A 起步,WiFi 发射峰值留 300 mA 余量
4) 外接供电:电机/舵机/继电器/大屏**必须独立供电**,只把 GND 与 MCU 共地
5) 加电容:在 MCU 的 VCC-GND 间并联 100 µF 电解 + 0.1 µF 陶瓷,吸收瞬时跌落
6) 测:万用表电压档量 MCU 的 VCC 引脚(不是电源输出端),
      触发负载的瞬间若跌到 3.0 V 以下,就是电源问题
7) 软件侧确认:ESP32 可在 menuconfig 里看 Brownout 阈值;
   树莓派用 vcgencmd get_throttled 确认是否欠压过

推荐电源配置:

场景 推荐 说明
ESP32 开发(无大负载) USB 5 V/1 A 充电头 够用且便宜
ESP32 + 摄像头/大屏 5 V/2 A 以上 峰值电流大
树莓派 4B 5 V/3 A 官方电源 低于 3 A 会随机重启、SD 卡损坏
树莓派 5 5 V/5 A USB-PD 官方 PD 电源,普通充电头会限流警告
多舵机(4 个 SG90 以上) 单独 5 V/2–3 A 开关电源 绝不能从 MCU 的 3.3 V 取电
步进电机 + A4988 12 V/2 A(按电机额定) 电机电源与逻辑电源分开,只共地
桌面调试通用 可调稳压电源(0–30 V、0–3 A) 带限流保护,烧片子前能救命

7.5 通用故障排查表

现象 可能原因(按概率排序) 快速判定方法
电脑完全认不到设备 数据线没数据功能 → 驱动 → 板子坏 换线 → 换口 → 换电脑
能识别但下载失败 波特率过高 → 没进下载模式 → strapping 引脚被占用 降波特率 → 按键进模式 → 拔掉外设再试
下载成功不运行 BOOT 跳线 → 复位电路 → 程序本身崩 看串口日志 → 手动复位
串口全乱码 波特率不对 → 晶振配置错 → 电平不匹配 换常见波特率 → 逻辑分析仪量位宽
运行几分钟后死机 电源跌落 → 过热 → 内存泄漏 / 栈溢出 摸芯片温度 → 量 VCC → 看日志
通信类外设无响应 接线错(TX/RX 未交叉)→ 未共地 → 地址错 → 上拉缺失 逻辑分析仪看波形 → I2C 地址扫描
时好时坏 杜邦线接触不良 / 面包板氧化 / 虚焊 重新插拔 → 换线 → 补焊
烧了芯片 电压接错 / VCC 与 GND 反接 / IO 直驱大电流 断电闻味摸温;下次接线前先量一遍

八、环境可复现:把"能跑"固化下来

# ===== 环境版本留档(排查"我这能跑你那不能跑"的关键)=====
pio --version && pio pkg list
idf.py --version
arm-none-eabi-gcc --version
xtensa-esp32s3-elf-gcc --version
openocd --version
python3 --version
cat /etc/os-release | head -3

# 写进项目 README 或 env-info.txt,比记忆可靠
{
  echo "date: $(date -I)"
  echo "os:   $(uname -a)"
  echo "pio:  $(pio --version 2>/dev/null)"
  echo "idf:  $(idf.py --version 2>/dev/null)"
  echo "gcc:  $(arm-none-eabi-gcc --version 2>/dev/null | head -1)"
} | tee env-info.txt

# Docker 化(团队协作 / CI 最彻底的方案)
docker run --rm -it -v "$PWD":/project -w /project \
  python:3.11-slim bash -c "pip install platformio && pio run"

九、本系列导航

  • 本系列第 1 篇:《常见开发板选型与信息速查》——买什么板、各板规格与坑
  • 本系列第 3 篇:《硬件模块与通信协议基础》——GPIO/UART/I2C/SPI/PWM/ADC/CAN 精讲 + 模块速查 + 电源与焊接

一个通用原则:环境配好后,立刻做一个"最小可验证闭环"(点灯 / 打印 Hello World / 读芯片 ID),把它跑通再往下走。90% 的"环境问题"都能在这一步暴露,而不是等到写了几百行代码才发现串口根本连不上。