【保姆级】WSL 2 中使用 PlatformIO 开发 ESP32 完整教程

WSL 2 中使用 PlatformIO 开发 ESP32 完整教程

  • [WSL 2 + PlatformIO + ESP32:一站式开发环境搭建指南](#WSL 2 + PlatformIO + ESP32:一站式开发环境搭建指南)
    • 适用场景与前置要求
    • 阶段一:环境准备
      • [Windows 主机端配置](#Windows 主机端配置)
        • [安装 WSL 2 和 Linux 发行版](#安装 WSL 2 和 Linux 发行版)
        • [安装 VS Code 及必要扩展](#安装 VS Code 及必要扩展)
        • [安装 USB 转发工具 usbipd-win](#安装 USB 转发工具 usbipd-win)
      • WSL(Linux)端配置
        • [验证 PlatformIO 是否就绪](#验证 PlatformIO 是否就绪)
        • [(可选)安装 UDEV 规则消除警告](#(可选)安装 UDEV 规则消除警告)
    • [阶段二:USB 串口设备转发(核心步骤)](#阶段二:USB 串口设备转发(核心步骤))
      • [使用脚本自动化 USB 转发](#使用脚本自动化 USB 转发)
      • [在 WSL 中确认串口设备](#在 WSL 中确认串口设备)
    • [阶段三:PlatformIO 项目配置与烧录](#阶段三:PlatformIO 项目配置与烧录)
    • 常见问题排查
      • [问题 1:烧录卡在 Connecting... 或报错 Failed to connect to Espressif device](#问题 1:烧录卡在 Connecting... 或报错 Failed to connect to Espressif device)
      • [问题 2:Permission denied 访问 /dev/ttyUSB0](#问题 2:Permission denied 访问 /dev/ttyUSB0)
      • [问题 3:usbipd attach 报错 "WSL instance not found"](#问题 3:usbipd attach 报错 “WSL instance not found”)
    • 附加工具建议
    • 总结

WSL 2 + PlatformIO + ESP32:一站式开发环境搭建指南

在 Windows 上进行嵌入式开发,尤其是使用 ESP32 这类主流微控制器时,开发者常常面临工具链配置复杂、串口驱动兼容性差等问题。而 WSL 2(Windows Subsystem for Linux)提供了一个近乎原生的 Linux 开发体验,配合 PlatformIO 强大的跨平台构建与烧录能力,可以构建一个高效、稳定、可复现的开发环境。

本文将手把手带你完成从零开始搭建 WSL 2 + PlatformIO + ESP32 的完整开发流程,并提供一个自动化脚本,简化 USB 串口设备在 WSL 中的识别与转发操作------这是成功烧录的关键。


适用场景与前置要求

  • 操作系统:Windows 10/11(需支持 WSL 2)
  • 目标硬件:任意基于 ESP32 的开发板(如 ESP32-DevKitC、ESP32-CAM、NodeMCU-32S 等)
  • 开发工具
    • Visual Studio Code(简称 VS Code)
    • WSL 2(推荐 Ubuntu 22.04 或 24.04)
    • PlatformIO IDE 扩展
    • usbipd-win(微软官方 USB 转发工具)

为什么选择 WSL 2?

相比传统虚拟机或双系统,WSL 2 启动快、资源占用低、与 Windows 文件系统无缝互通,同时提供完整的 Linux 内核支持,非常适合嵌入式开发中的编译、调试和脚本自动化。


阶段一:环境准备

Windows 主机端配置

安装 WSL 2 和 Linux 发行版

打开 PowerShell(管理员),执行:

powershell 复制代码
wsl --install

该命令会自动启用 WSL 功能、安装 WSL 2 内核,并默认安装 Ubuntu。你也可以手动指定版本:

powershell 复制代码
wsl --install -d Ubuntu-22.04

首次启动时会提示创建 Linux 用户名和密码,请牢记。

安装 VS Code 及必要扩展
  1. 下载并安装 Visual Studio Code
  2. 安装以下扩展:
    • WSL:允许 VS Code 在 WSL 中运行
    • PlatformIO IDE:ESP32 开发核心插件

安装后,在 VS Code 中按 Ctrl+Shift+P,输入 Remote-WSL: New Window,即可在 WSL 环境中打开项目。

安装 USB 转发工具 usbipd-win

这是 WSL 2 能够访问物理 USB 设备(如 ESP32 串口芯片)的关键!

在管理员 PowerShell 中运行:

powershell 复制代码
winget install usbipd

安装完成后,重启 WSL 以确保服务正常加载:

powershell 复制代码
wsl --shutdown

WSL(Linux)端配置

验证 PlatformIO 是否就绪

首次在 WSL 中打开 VS Code 并安装 PlatformIO IDE 扩展后,扩展会自动下载并安装 PlatformIO Core(包括 Python、toolchain、esptool 等)。

你可以在 WSL 终端中验证:

bash 复制代码
pio --version
# 应输出类似:PlatformIO Core, version 6.x.x
(可选)安装 UDEV 规则消除警告

虽然 usbipd 转发不依赖 UDEV,但 PlatformIO 可能提示权限警告。运行以下命令可消除:

bash 复制代码
pio system udevrules install
sudo udevadm control --reload-rules

此步骤非必需,不影响实际烧录功能。


阶段二:USB 串口设备转发(核心步骤)

重要提示:每次插拔 ESP32 板子或重启 WSL 后,都需重新执行此阶段操作!

为简化操作,我们提供一个 PowerShell 脚本 BindAttachSelectWsl_Final_Exit.ps1,它将自动完成以下任务:

  1. 列出所有 USB 设备供选择;
  2. 列出所有已安装的 WSL 发行版供选择;
  3. 自动绑定并挂载所选设备到指定 WSL 实例;
  4. 显示最终状态并等待用户确认退出。

使用脚本自动化 USB 转发

将以下内容保存为文件 BindAttachSelectWsl_Final_Exit.ps1

powershell 复制代码
# BindAttachSelectWsl_Final_Exit.ps1
# 功能:绑定 USB -> 选 WSL -> 挂载 -> 按 Enter 彻底关闭窗口
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# --- 1. 管理员权限检查 ---
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
    Write-Host "[警告] 此脚本需要管理员权限。正在重新启动为管理员..." -ForegroundColor Yellow
    
    Start-Process powershell.exe "-File `"$PSCommandPath`"" -Verb RunAs
    exit
}

# ==========================================
# 第一步:选择 USB 设备
# ==========================================
Write-Host "[INFO] [1/3] 获取 USB 设备列表..." -ForegroundColor Cyan
$rawList = usbipd list 2>&1

# 检查是否需要强制绑定
$needsForce = $rawList -match 'incompatible with this software' -or $rawList -match 'UsbDk' -or $rawList -match 'nxusbf'

# 解析设备列表
$devices = @()
$lines = $rawList -split '\r?\n'
foreach ($line in $lines) {
    if ($line -match '^(\d+-\d+)\s+([0-9a-fA-F]{4}:[0-9a-fA-F]{4})\s+(.+?)\s{2,}(.+)$') {
        $busid = $matches[1]
        $vidpid = $matches[2]
        $deviceName = $matches[3].Trim()
        $state = $matches[4].Trim()
        if ($busid -match '^\d+-\d+$') {
            $devices += [PSCustomObject]@{ BusId = $busid; VidPid = $vidpid; DeviceName = $deviceName; State = $state }
        }
    }
}

if ($devices.Count -eq 0) { 
    Write-Host "[错误] 未找到设备。" -ForegroundColor Red
    Read-Host "按 Enter 退出程序"
    exit
}

# 显示 USB 设备
Write-Host "`n[列表] 可用 USB 设备:" -ForegroundColor Green
for ($i = 0; $i -lt $devices.Count; $i++) {
    Write-Host "  $($i+1). [$($devices[$i].BusId)] $($devices[$i].DeviceName) ($($devices[$i].State))"
}

$usbSelection = Read-Host "`n-> 请输入 USB 设备序号 (例如 1)"
if (-not ([int]::TryParse($usbSelection, [ref]$null) -and [int]$usbSelection -ge 1 -and [int]$usbSelection -le $devices.Count)) {
    Write-Host "[错误] 无效输入。" -ForegroundColor Red
    Read-Host "按 Enter 退出程序"
    exit
}
$targetUsb = $devices[[int]$usbSelection - 1]

# ==========================================
# 第二步:选择 WSL 发行版
# ==========================================
Write-Host "`n[INFO] [2/3] 获取 WSL 发行版列表..." -ForegroundColor Cyan

# 获取 WSL 列表
$wslRaw = (wsl --list --quiet) 
$wslDistros = $wslRaw -split '\r?\n' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }

if ($wslDistros.Count -eq 0) {
    Write-Host "[错误] 未检测到任何 WSL 发行版,请先安装 WSL。" -ForegroundColor Red
    Read-Host "按 Enter 退出程序"
    exit
}

# 显示 WSL 列表
Write-Host "`n[列表] 可用 WSL 发行版:" -ForegroundColor Green
for ($i = 0; $i -lt $wslDistros.Count; $i++) {
    Write-Host "  $($i+1). $($wslDistros[$i])"
}

$wslSelection = Read-Host "`n-> 请输入 WSL 系统序号 (直接按 Enter 默认使用第1个)"

# 处理 WSL 选择逻辑
if ([string]::IsNullOrWhiteSpace($wslSelection)) {
    $targetWsl = $wslDistros[0]
    Write-Host "已选择默认: $targetWsl" -ForegroundColor Gray
}
elseif ([int]::TryParse($wslSelection, [ref]$null) -and [int]$wslSelection -ge 1 -and [int]$wslSelection -le $wslDistros.Count) {
    $targetWsl = $wslDistros[[int]$wslSelection - 1]
}
else {
    Write-Host "[错误] 无效输入。" -ForegroundColor Red
    Read-Host "按 Enter 退出程序"
    exit
}

# ==========================================
# 第三步:执行绑定与连接
# ==========================================
Write-Host "`n[INFO] [3/3] 开始处理..." -ForegroundColor Cyan
Write-Host "   目标设备: $($targetUsb.DeviceName)"
Write-Host "   目标系统: $targetWsl"
Write-Host "--------------------------------"

# 1. Bind (绑定)
Write-Host "[步骤 1] 正在绑定 (Bind)..." -ForegroundColor Gray
$bindArgs = @("bind", "--busid", $targetUsb.BusId)
if ($needsForce) { 
    $bindArgs += "--force" 
    Write-Host "   (检测到驱动冲突,已启用 --force)" -ForegroundColor Yellow
}
Start-Process usbipd -ArgumentList $bindArgs -Wait -NoNewWindow

# 2. Attach (连接)
Write-Host "[步骤 2] 正在连接 (Attach)..." -ForegroundColor Gray
$attachArgs = @("attach", "--wsl", $targetWsl, "--busid", $targetUsb.BusId)

# 执行并输出
& usbipd $attachArgs

# 3. 验证
Write-Host "`n[INFO] 状态验证:" -ForegroundColor Cyan
Start-Sleep -Seconds 1
$finalList = usbipd list 2>&1
$resultLine = ($finalList -split '\r?\n') | Where-Object { $_ -match "^$($targetUsb.BusId)\s" }

if ($resultLine -match "Attached") {
    Write-Host $resultLine -ForegroundColor Green
    Write-Host "`n[成功] 设备已挂载到 [$targetWsl]。" -ForegroundColor Green
} else {
    Write-Host $resultLine -ForegroundColor Yellow
    Write-Host "`n[注意] 设备未显示 Attached,请进入 $targetWsl 输入 'lsusb' 检查。" -ForegroundColor Yellow
}

Write-Host "`n---"
Read-Host "按 Enter 退出程序"

exit
使用方法:
  1. 将 ESP32 开发板通过 USB 连接到电脑;
  2. 右键以管理员身份运行 BindAttachSelectWsl_Final_Exit.ps1
  3. 按提示依次选择 USB 设备和 WSL 发行版;
  4. 脚本执行完毕后,设备即已挂载到 WSL。

建议将此脚本放在桌面或固定位置,每次开发前运行一次即可。


在 WSL 中确认串口设备

脚本执行成功后,切换到 WSL 终端,执行:

bash 复制代码
ls /dev/tty*

你应该能看到新增的设备节点,通常是:

复制代码
/dev/ttyUSB0

这就是你在 PlatformIO 中要使用的烧录端口。


阶段三:PlatformIO 项目配置与烧录

创建或打开 ESP32 项目

在 VS Code 中:

  1. Ctrl+Shift+P
  2. 输入 PlatformIO: New Project
  3. 选择:
    • Board: Espressif ESP32 Dev Module(或其他你的板型)
    • Framework: Arduino(或 ESP-IDF)
  4. 项目路径建议放在 WSL 文件系统内(如 /home/yourname/esp32_test

不要将项目放在 /mnt/c/...(Windows 挂载目录),否则可能导致权限或性能问题。


配置 platformio.ini

编辑项目根目录下的 platformio.ini 文件,显式指定上传端口:

ini 复制代码
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_port = /dev/ttyUSB0     ; ← 关键!必须匹配 WSL 中的设备名
upload_speed = 921600          ; 推荐高速烧录(部分板子需降速至 115200)

如果看到 /dev/ttyACM0,说明可能是 CDC 类设备(如某些 ESP32-S2/S3),请相应调整。


编译 & 烧录

方法一:图形界面操作
  • 点击左侧 PlatformIO 图标
  • 展开 Project Tasks
  • 点击 Upload
方法二:终端命令
bash 复制代码
pio run --target upload

成功日志示例:

复制代码
Uploading .pio/build/esp32dev/firmware.bin
Serial port /dev/ttyUSB0
Connecting........___
...
Writing at 0x00010000... (100%)
Hard resetting via RTS pin...

常见问题排查

问题 1:烧录卡在 Connecting... 或报错 Failed to connect to Espressif device

原因:ESP32 未进入下载模式(Download Mode)。

解决方案:

  • 对于 ESP32-DevKitC 等带自动复位电路的板子:通常无需操作。
  • 对于 ESP32-CAM、某些廉价模块:需手动进入下载模式:
    1. 按住 BOOT(或 GPIO0)按钮不放
    2. 点击 Upload
    3. 看到 Connecting... 后立即松开 BOOT 按钮

问题 2:Permission denied 访问 /dev/ttyUSB0

原因:当前用户不在 dialout 组。

解决方案(在 WSL 中执行):

bash 复制代码
sudo usermod -aG dialout $USER

然后退出 WSL 并重新登录(或重启 WSL)。


问题 3:usbipd attach 报错 "WSL instance not found"

原因:WSL 实例名称错误或未运行。

检查方法:

powershell 复制代码
wsl -l -v

确保状态为 Running,并使用正确的名称(区分大小写)。


附加工具建议

  • 串口监视器:PlatformIO 自带,支持实时查看 Serial.print() 输出

  • 自动重连 :在 platformio.ini 中添加:

    ini 复制代码
    monitor_flags =
      --raw
  • 多设备管理 :若同时连接多个串口设备,可通过 ls -l /dev/serial/by-id/ 查看唯一标识符,避免 /dev/ttyUSB0 变化导致配置失效。


总结

通过 WSL 2 + PlatformIO,你可以在 Windows 上获得接近 Linux 原生的 ESP32 开发体验,同时享受 VS Code 的强大编辑能力。USB 串口转发是核心难点,但借助本文提供的自动化脚本,你可以一键完成设备绑定与挂载,大幅提升开发效率。

现在,你的 WSL 已经成为一个功能完备的嵌入式开发工作站。Happy Coding with ESP32!


参考链接:

相关推荐
1379号监听员_1 小时前
hc05蓝牙模块
stm32·单片机·物联网
就是蠢啊1 小时前
51单片机——DS18B02(二)
单片机·嵌入式硬件·51单片机
沧海一条狗1 小时前
Ecat从站SSC代码与GD32H75E接口的适配注意事项
单片机·嵌入式硬件
minglie11 小时前
clion+RP2040-Zero的ws2812
单片机
2401_853448232 小时前
QT控制----单片机控制外设项目
stm32·qt·uart
点灯小铭2 小时前
基于单片机的加油站加油机显示控制系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
m0_690780522 小时前
串口通信,嵌入式系统
单片机·嵌入式硬件
沧海一条狗2 小时前
SOEM与ESC无法通讯问题解决方案
单片机
雾削木2 小时前
STM32 HAL 软件SPI任意GPIO控制st7735
stm32·单片机·嵌入式硬件