PlatformIO 是什么?
PlatformIO 是一个开源的跨平台物联网(IoT)开发环境,专注于嵌入式系统和微控制器开发。它集成了代码编辑、编译、调试、库管理和固件烧录等功能,支持 650+种开发板 和 40+种框架(如Arduino、ESP-IDF、STM32Cube、Raspberry Pi Pico等)。
核心功能与优势
- 多硬件平台支持
- 主流架构:ARM Cortex-M(STM32、Nordic)、ESP32/ESP8266、AVR、RISC-V等。
- 开发板兼容性:Arduino Uno、Raspberry Pi Pico、STM32 Nucleo、ESP32-C3等。
- 传统芯片支持:通过自定义配置可支持51单片机。
- 集成开发工具链
- 编译器:自动下载GCC、Clang、IAR等工具链。
- 调试器:支持GDB调试(通过J-Link、ST-Link等硬件调试器)。
- 烧录工具:兼容OpenOCD、py、STC-ISP等。
- 依赖管理与库生态
- 库管理器:通过ini声明依赖,自动从PlatformIO Registry或GitHub拉取库。
- 示例工程:内置数千个开源示例(如传感器驱动、通信协议实现)。
- 高效开发体验
- 代码智能提示:基于Clang的代码补全和语法检查。
- 远程开发:支持SSH和容器化开发(Docker集成)。
- 单元测试:集成Unity测试框架,支持自动化测试。
与传统工具(如Keil)的对比
特性 | PlatformIO | Keil μVision |
跨平台支持 | 全平台(Windows/macOS/Linux) | 仅Windows |
开源免费 | 完全免费(MIT协议) | 商业软件,免费版功能受限 |
生态开放性 | 社区驱动,支持自定义硬件和框架 | 封闭生态,依赖厂商支持包 |
多框架支持 | Arduino、ESP-IDF、Zephyr等 | 主要针对Keil自有工具链 |
开发效率 | 自动化依赖管理,集成现代工具链 | 手动配置库和工程选项 |
适用场景 | IoT、多平台项目、开源协作 | 传统嵌入式教学、单一平台开发 |
典型应用场景
- 多硬件平台开发:同一项目适配不同硬件(如ESP32和STM32共用代码)。
- 物联网设备开发:快速集成WiFi/蓝牙(ESP32)、传感器(BME280)和云服务(AWS IoT)。
- 开源协作:通过Git管理代码,依赖声明式配置(ini)确保环境一致性。
- 教育与实验:提供Arduino兼容性,适合新手快速上手嵌入式开发。
局限性
- 对传统芯片支持有限。部分老旧MCU(如STC89C51)需手动配置平台和工具链。
- 学习曲线。CLI和配置文件(ini)需一定学习成本。
- 调试依赖硬件。需额外调试器(如J-Link)实现高级调试功能。
PlatformIO的安装
安装必要工具
SDCC编译器(8051专用开源编译器):
- Windows:从 SDCC官网 下载安装包。
- Linux/macOS:使用包管理器安装。
烧录工具 stcgal(用于STC单片机): pip install stcgal
PlatformIO:在Vscode扩展市场中搜索PlatformIO进行安装
创建自定义STC89C51平台
在PIO Home的Boards中搜索STC89C51,并安装Intel MCS-51(8051) Platform
然后切换到Projects创建自己的项目。
由于我使用的是STC 89C516RD+的芯片,创建项目时会报错,报错内容为:
Could not initialize project PIO Core Call Error: "The following files/directories have been created in C:\\Users\\qw\\Documents\\PlatformIO\\Projects\\STC89C51\r\ninclude - Put project header files here\r\nlib - Put project specific (private) libraries here\r\nsrc - Put project source files here\r\nplatformio.ini - Project Configuration File\r\n\n\nInvalidEnvNameError: Invalid environment name 'STC89C516RD+'. The name can contain alphanumeric, underscore, and hyphen characters (a-z, 0-9, -, _)"
解决方案1:选择Generic STC89C51RC也能创建成功。芯片稍有区别,但能正常使用。
解决方案2:打开C:\Users\{username}\.platformio\platforms\intel_mcs51\boards,找到STC89C516RD+.json文件,复制并重命名为STC89C516RD.json,并去除文件内的+号。修改完毕后重新启动VSCode再次搜索就能找到STC89C516RD的型号。
重新创建项目,创建项目的时候选择STC89C516RD即可。
完成后生成如下项目:
配置 PlatformIO 项目
进入系统后报:
[2025/5/25 10:06:24] 无法使用 compilerPath 解析配置:“C:/Users/qw/.platformio/packages/toolchain-sdcc/bin/sdcc.exe”
解决方案,在platformio.ini中新增compiler_path(路径为一开始安装的sdcc的路径)
; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:STC89C516RD] platform = intel_mcs51 board = STC89C516RD compiler_path = C:/Program Files/SDCC/bin/sdcc.exe
在src目录下新建main.c文件,文件内容为:
#include <8051.h> void delay() { unsigned int i; for (i=0; i<30000; i++); } void main() { while (1) { P2 = 0x00; // LED全亮 delay(); P2 = 0xFF; // LED全灭 delay(); } }
对代码进行编译:
能够顺利完成编译,但当尝试进行Upload时发现卡住了。
经排查这里是stcgal的一个Bug,用户在上传时需要指定stcgal的协议参数-P stc89,否则上传会失败。尝试修改platformio.ini文件,新增upload选项:
; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:STC89C516RD] platform = intel_mcs51 board = STC89C516RD compiler_path = C:/Program Files/SDCC/bin/sdcc.exe upload_protocol = stcgal upload_port = COM5 ; 根据实际串口号修改(Linux/macOS为/dev/ttyUSB0) upload_speed = 2400 ; 必须降低波特率[11,12](@ref) build_flags = -D F_CPU=11059200 ; 与单片机晶振频率一致[6,12](@ref) upload_flags = -P stc89 ; 强制指定协议类型[4,8](@ref)
改完后重新尝试,报如下错误:
* 正在文件夹 STC89C516RD 中执行任务: C:\Users\qw\.platformio\penv\Scripts\platformio.exe run --target upload --environment STC89C516RD Processing STC89C516RD (platform: intel_mcs51; board: STC89C516RD) ----------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option CONFIGURATION: https://docs.platformio.org/page/boards/intel_mcs51/STC89C516RD.html PLATFORM: Intel MCS-51 (8051) (2.2.0) > Generic STC89C516RD HARDWARE: STC89C516RD 11MHz, 1.25KB RAM, 64KB Flash PACKAGES: - tool-stcgal @ 1.110.0 (1.10) - tool-vnproch55x @ 1.0.220407 - toolchain-sdcc @ 1.40400.0 (4.4.0) LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf LDF Modes: Finder ~ chain, Compatibility ~ soft Found 0 compatible libraries Scanning dependencies... No dependencies Building in release mode Checking size .pio\build\STC89C516RD\firmware.hex Advanced Memory Usage is available via "PlatformIO Home > Project Inspect" Flash: [ ] 0.2% (used 130 bytes from 65536 bytes) Configuring upload protocol... AVAILABLE: stcgal CURRENT: upload_protocol = stcgal Looking for upload port... Using manually specified: COM5 Uploading .pio\build\STC89C516RD\firmware.hex usage: stcgal.py [-h] [-e] [-a] [-A {dtr,rts}] [-r RESETCMD] [-P {stc89,stc89a,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}] [-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D] [-V] [code_image] [eeprom_image] stcgal.py: error: argument -P/--protocol: invalid choice: ' stc89' (choose from 'stc89', 'stc89a', 'stc12a', 'stc12b', 'stc12', 'stc15a', 'stc15', 'stc8', 'stc8d', 'stc8g', 'usb15', 'auto') *** [upload] Error 2 ============================================= [FAILED] Took 1.20 seconds ============================================= * 终端进程“C:\Users\qw\.platformio\penv\Scripts\platformio.exe 'run', '--target', 'upload', '--environment', 'STC89C516RD'”已终止,退出代码: 1。 * 终端将被任务重用,按任意键关闭。
发现是stc89前多了空格导致的。删除空格再次尝试:发现还是卡住了,-P参数并没有被正确的解析到。
再次实验,通过命令行手动进行上传:stcgal -P stc89 -p COM5 -b 2400 .pio/build/STC89C516RD/firmware.hex
发现顺利进入流程,当Waiting for MCU, please cycle power: done时,重启开关即可。
针对命令行可顺利上传的表现,再次调整platformio.ini文件为:
; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:STC89C51RC] platform = intel_mcs51 board = STC89C51RC compiler_path = C:/Program Files/SDCC/bin/sdcc.exe # 禁用默认烧录工具,启用自定义命令 upload_protocol = custom # 自定义烧录命令(跨平台兼容) upload_command = stcgal -P stc89 -p COM5 -b 2400 .pio/build/STC89C516RD/firmware.hex
调整单片机引用
在前面的实验代码中,我们使用了#include <8051.h>,为了更高的使用我们的芯片,我们需要从STC-IPS中导出一个型号对应的头文件。
注意这里需要选择SDCC格式头文件。将文件保存为STC89C516RD.h。并抢其复制到项目文件夹下的include目录下。
代码就可以修改为:
#include "STC89C516RD.h" void delay() { unsigned int i; for (i=0; i<30000; i++); } void main() { while (1) { P2 = 0x00; // LED全亮 delay(); P2 = 0xFF; // LED全灭 delay(); } }
解决IntelliSense无法理解SDCC的特殊语法
具体表现为:上面的代码能够正常编译,但是代码中P2下面会出现红色的波浪线提示,非常影响使用体验。原因是VS Code 的 IntelliSense 无法原生理解 SDCC 的特殊寄存器语法(如 __sfr __at),但我们可以通过配置让它正确识别这些定义。
我的解决方案:
在 STC89C516RD.h 中添加 IntelliSense 支持:
// STC89C52RC.h #ifndef __STC89C52RC_H__ #define __STC89C52RC_H__ // 为 IntelliSense 定义伪关键字 #ifdef __INTELLISENSE__ // 定义 SDCC 特殊关键字为 IntelliSense 可理解的格式 #define __sfr volatile unsigned char #define __at(x) #define __bit unsigned char #define __critical #define __code #define __data #define __xdata #define __pdata #endif // 特殊功能寄存器定义 __sfr __at (0xA0) P2; __sfr __at (0x80) P0; __sfr __at (0x90) P1; __sfr __at (0xB0) P3; // 其他寄存器定义... __sfr __at (0x98) SCON; __sfr __at (0x99) SBUF; __sfr __at (0x88) TCON; __sfr __at (0x89) TMOD; #endif
改完后一切就OK了。
特别注意:SDCC与 Keil的不一致
网上的很多示例代码都是keil的,在sdcc环境下并不能直接使用,所以需要进行一轮转化,比较简单的方式是使用deepseek这样的工具让他帮忙给你转化。
示例原始代码:
#include <REGX51.H> #include <INTRINS.H> void delay(unsigned int t) { while(t--); } void main() { int i; // Declare 'i' outside the loops P2 = 0xFE; while(1) { for(i = 0; i < 7; i++) { // Use pre-declared 'i' P2 = _crol_(P2, 1); delay(50000); } for(i = 0; i < 7; i++) { // Same here P2 = _cror_(P2, 1); delay(50000); } } }
转换后的代码:
#include "STC89C516RD.h" /* * SDCC兼容的8051流水灯程序 - 不使用intrins.h * 使用标准位操作实现循环移位功能 * * 连接说明:P2口连接8个LED(共阳接法或串联限流电阻) * 初始状态:P2.0亮(0xFE: 11111110) * 效果:先左移7次(LED灯依次向左流动),然后右移7次(LED灯依次向右流动) */ /** * 自定义循环左移函数 * @param c 输入的字节 * @return 循环左移一位后的结果 */ unsigned char custom_crol(unsigned char c) { // 1. 检查最高位(MSB)是否为1 unsigned char msb = c & 0x80; // 2. 左移一位(最低位自动补0) unsigned char result = c << 1; // 3. 如果最高位为1,设置最低位为1 if (msb) { result |= 0x01; } return result; } /** * 自定义循环右移函数 * @param c 输入的字节 * @return 循环右移一位后的结果 */ unsigned char custom_cror(unsigned char c) { // 1. 检查最低位(LSB)是否为1 unsigned char lsb = c & 0x01; // 2. 右移一位(最高位自动补0) unsigned char result = c >> 1; // 3. 如果最低位为1,设置最高位为1 if (lsb) { result |= 0x80; } return result; } /** * 简单的软件延时函数 * @param t 延时参数(值越大延时越长) */ void delay(unsigned int t) { while(t--); // 空循环实现延时 } void main() { unsigned char led = 0xFE; // 初始值:11111110 (P2.0亮) int i; P2 = led; // 初始化P2口 while(1) { // 向左循环移动7次 for(i = 0; i < 7; i++) { led = custom_crol(led); // 自定义循环左移 P2 = led; // 更新P2口 delay(50000); // 延时 } // 向右循环移动7次 for(i = 0; i < 7; i++) { led = custom_cror(led); // 自定义循环右移 P2 = led; // 更新P2口 delay(50000); // 延时 } } }
Happy Hacking!