PlatformIO 多环境管理:ESP32 + Arduino Uno 双目标构建
目标
一个 PlatformIO 项目同时支持 ESP32 和 Arduino Uno,通过环境配置和条件编译实现跨平台代码复用。
项目结构
multi-target/
├── platformio.ini
├── src/
│ └── main.cpp
├── include/
│ └── board_config.h
└── lib/
└── (自定义库)
一、platformio.ini — 多环境配置
[platformio]
default_envs = uno
[common]
monitor_speed = 115200
lib_deps =
adafruit/Adafruit Unified Sensor @ ^1.1.14
[env:uno]
platform = atmelavr
board = uno
framework = arduino
build_flags =
-D BOARD_UNO
-D LED_PIN=LED_BUILTIN
lib_deps =
${common.lib_deps}
adafruit/DHT sensor library @ ^1.4.4
monitor_speed = 9600
[env:esp32]
platform = espressif32
board = esp32dev
framework = arduino
build_flags =
-D BOARD_ESP32
-D LED_PIN=2
lib_deps =
${common.lib_deps}
adafruit/DHT sensor library @ ^1.4.4
adafruit/Adafruit SSD1306 @ ^2.5.7
adafruit/Adafruit GFX Library @ ^1.11.9
monitor_filters = esp32_exception_decoder
[env:esp32-c3]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
build_flags =
-D BOARD_ESP32_C3
-D LED_PIN=8
lib_deps =
${common.lib_deps}
adafruit/DHT sensor library @ ^1.4.4
二、board_config.h — 条件编译板级配置
#pragma once
#include <Arduino.h>
#if defined(BOARD_UNO)
#define BOARD_NAME "Arduino Uno"
#define CPU_SPEED_MHZ 16
#define HAS_WIFI 0
#define HAS_BLUETOOTH 0
#define RAM_KB 2
#define FLASH_KB 32
#elif defined(BOARD_ESP32)
#define BOARD_NAME "ESP32 DevKit"
#define CPU_SPEED_MHZ 240
#define HAS_WIFI 1
#define HAS_BLUETOOTH 1
#define RAM_KB 520
#define FLASH_KB 4096
#elif defined(BOARD_ESP32_C3)
#define BOARD_NAME "ESP32-C3"
#define CPU_SPEED_MHZ 160
#define HAS_WIFI 1
#define HAS_BLUETOOTH 1
#define RAM_KB 400
#define FLASH_KB 4096
#else
#error "未定义目标板!请使用 -D BOARD_xxx 编译宏"
#endif
#if defined(BOARD_UNO)
#define PIN_I2C_SDA A4
#define PIN_I2C_SCL A5
#define PIN_DHT 2
#define PIN_BUTTON 3
#elif defined(BOARD_ESP32)
#define PIN_I2C_SDA 21
#define PIN_I2C_SCL 22
#define PIN_DHT 4
#define PIN_BUTTON 0 // BOOT 按键
#elif defined(BOARD_ESP32_C3)
#define PIN_I2C_SDA 6
#define PIN_I2C_SCL 7
#define PIN_DHT 3
#define PIN_BUTTON 9
#endif
三、main.cpp — 跨平台业务逻辑
#include <Arduino.h>
#include "board_config.h"
#if HAS_WIFI
#include <WiFi.h>
#endif
void printBoardInfo() {
Serial.println(F("========================"));
Serial.print(F("板卡: "));
Serial.println(BOARD_NAME);
Serial.print(F("CPU: "));
Serial.print(CPU_SPEED_MHZ);
Serial.println(F(" MHz"));
Serial.print(F("RAM: "));
Serial.print(RAM_KB);
Serial.print(F(" KB | Flash: "));
Serial.print(FLASH_KB);
Serial.println(F(" KB"));
Serial.print(F("WiFi: "));
Serial.println(HAS_WIFI ? F("✓") : F("✗"));
Serial.print(F("BLE: "));
Serial.println(HAS_BLUETOOTH ? F("✓") : F("✗"));
Serial.print(F("LED: D"));
Serial.print(LED_PIN);
Serial.print(F(" | DHT: D"));
Serial.print(PIN_DHT);
Serial.println(F("\n========================"));
}
void smartDelay(unsigned long ms) {
unsigned long start = millis();
while (millis() - start < ms) {
#if HAS_WIFI
#endif
delay(1); // 让步给系统
}
}
void setup() {
Serial.begin(115200);
#if defined(BOARD_ESP32_C3)
delay(1000);
#endif
while (!Serial && millis() < 3000) {
delay(10);
}
printBoardInfo();
pinMode(LED_PIN, OUTPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP);
#if HAS_WIFI
WiFi.mode(WIFI_OFF); // 省电
Serial.println(F("WiFi 已关闭(省电模式)"));
#endif
Serial.println(F("\n系统就绪!"));
Serial.print(F("LED 开始闪烁 | 按键引脚 D"));
Serial.println(PIN_BUTTON);
}
void loop() {
static unsigned long lastBlink = 0;
static unsigned long lastReport = 0;
static uint32_t loopCount = 0;
loopCount++;
if (millis() - lastBlink >= 500) {
lastBlink = millis();
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
}
if (millis() - lastReport >= 5000) {
lastReport = millis();
Serial.print(F("["));
Serial.print(BOARD_NAME);
Serial.print(F("] 运行中 | 循环 #"));
Serial.print(loopCount);
Serial.print(F(" | 运行时间: "));
Serial.print(millis() / 1000);
Serial.println(F("s"));
#if (FLASH_KB > 100)
Serial.print(F(" 可用堆: "));
Serial.print(ESP.getFreeHeap());
Serial.println(F(" bytes"));
#endif
}
if (digitalRead(PIN_BUTTON) == LOW) {
delay(20);
if (digitalRead(PIN_BUTTON) == LOW) {
Serial.println(F("按键按下!"));
while (digitalRead(PIN_BUTTON) == LOW) { delay(10); }
}
}
}
四、构建与烧录
pio project config
pio run -e uno
pio run -e esp32
pio run -e esp32-c3
pio run
pio run -e esp32 -t upload
pio device monitor -e esp32
关键点
${common.xxx} 语法实现配置继承,避免重复
-D MACRO 编译标志注入板级宏,驱动 #if 条件编译
board_config.h 集中管理引脚映射,业务逻辑代码零 #ifdef
#if HAS_WIFI 这种语义化条件比 #ifdef ESP32 更易读易维护
PlatformIO 快速上手:Arduino Uno 项目搭建与构建
目标
使用 PlatformIO CLI 创建 Arduino Uno 项目,完成编译、上传、串口监控的全流程。
前提
已安装 PlatformIO Core(pio --version 验证)。
完整步骤
1. 创建项目
mkdir pio-hello &
pio project init --board uno --ide vscode
生成的 platformio.ini 如下:
[env:uno]
platform = atmelavr
board = uno
framework = arduino
monitor_speed = 9600
2. 编写代码
src/main.cpp:
#include <Arduino.h>
const int LED_PIN = LED_BUILTIN;
unsigned long lastToggle = 0;
bool ledState = LOW;
unsigned long loopCount = 0;
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
while (!Serial) { delay(10); }
Serial.println("\n=== PlatformIO Hello ===");
Serial.print("Board: ");
Serial.println(ARDUINO_BOARD);
Serial.print("CPU Freq: ");
Serial.print(F_CPU / 1000000);
Serial.println(" MHz");
}
void loop() {
loopCount++;
if (millis() - lastToggle >= 500) {
lastToggle = millis();
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
Serial.print("[");
Serial.print(loopCount);
Serial.print("] LED: ");
Serial.println(ledState ? "ON" : "OFF");
}
}
3. 编译
pio run
pio run -e uno
成功输出:
Processing uno (platform: atmelavr; board: uno; framework: arduino)
...
RAM: [=== ] 25.4% (used 521 bytes from 2048 bytes)
Flash: [= ] 8.7% (used 2814 bytes from 32256 bytes)
========================= [SUCCESS] Took 3.45 seconds =========================
4. 上传
pio run --target upload
pio run --target upload --upload-port /dev/ttyUSB0
5. 串口监控
pio device monitor
预期输出:
=== PlatformIO Hello ===
Board: Arduino Uno
CPU Freq: 16 MHz
[1] LED: ON
[2] LED: OFF
[3] LED: ON
...
6. 一键编译+上传+监控
pio run -t upload &
关键点
platformio.ini 是声明式配置核心,无需手写 Makefile
- 自动管理 Arduino 框架和 AVR 工具链,首次
pio run 会自动下载
pio device list 可查看所有连接的串口设备
- 配合 VSCode 使用:项目目录下
code . 即可获得完整 IDE 体验