项目地址:https://github.com/leoduu/mimiRTOS
专栏地址:mimiOS
搭好环境没有烦恼~
工具一览
| 工具 | 用途 |
|---|---|
| STM32CubeMX | 图形化配置 MCU 外设、时钟,生成 HAL 库初始化代码 |
| Visual Studio Code | YYDS |
| PlatformIO 扩展 | 嵌入式开发工具,管理工具链、编译、烧录、调试 |
| NUCLEO-L452RE 开发板 | MCU:STM32L452RET6,自带了 ST-Link |
| stlink 驱动 | ST-Link 调试器驱动 |
STM32CubeMX | Software - STMicroelectronics
STSW-LINK009 | Software - STMicroelectronics
1. 前置准备
插上开发板
USB 线连电脑,检查设备管理器,能看到 STMicroelectronics STLink Device 之类的设备。如果设备管理器里有个黄色感叹号,说明 ST-Link 驱动没装好。
确认工具链
装好 VS Code 之后,安装 PlatformIO 扩展。装完左边栏会出现一个小蚂蚁图标,打开 PlatformIO CLI 跑一下:
# Windows 下在 VS Code 终端跑
pio --version
如果提示找不到命令,关了 VS Code 重开一次,让环境变量生效。
2. 用 STM32CubeMX 创建工程
选开发板
打开 CubeMX,点 ACCESS TO BOARD SELECTOR ,搜索 NUCLEO-L452RE,双击选中
选开发板比选 MCU 省事,外设引脚都帮你连好了。
确认外设配置
切换到 Pinout & Configuration 面板,能看到 CubeMX 已经根据开发板的布局配好了 GPIO:
- LD2(板载 LED)→ PA5
- USART2(ST-Link 虚拟串口)
改一下标签方便使用:在 Pinout 视图里找到 PA5,右键改 user label 为 LED。
配调试接口
左边标签页切到 System Core > SYS,Debug 选 Serial Wire。不配的话烧一次程序之后芯片可能锁死,下次就烧不进来了,得通过写 FLASH 刷机了。
时钟配置
切到 Clock Configuration 标签页,默认就行,HCLK 跑 80MHz。
工程设置
切到 Project Manager 标签:
-
Project Name:填你的项目名字,后续和 PlatformIO 里面的一样;
-
Toolchain / IDE:选 Makefile(选什么都一样)
-
Code Generator:建议勾选
-
Copy only the necessary library files Add necessary library files
-
Generate peripheral initialization as a pair of’.c/.h’ files per peripheral
点 GENERATE CODE,CubeMX 会把代码生成到你指定的目录。
3. PlatformIO 配置
新建 PlatformIO 项目
VS Code 里点 PlatformIO 图标 > Quick Access > PIO Home > Open > New Project,填写字段后,点 Finish,PlatformIO 会下载工具链和依赖,第一次可能需要等几分钟:
| 字段 | 值 |
|---|---|
| Name | 跟 CubeMX 的项目名字保持一致 |
| Board | 搜 NUCLEO-L452RE(也可以是 MCU 型号) |
| Framework | STM32Cube |
| Location | 取消勾选 “Use default location”,选 CubeMX 生成的那个目录 |
修改 PlatformIO 配置文件
项目根目录下找到 platformio.ini,改成下面这样:
[env:nucleo_l452re]
platform = ststm32
board = nucleo_l452re
framework = stm32cube
board_build.ldscript = ./STM32L452XX_FLASH.ld
upload_protocol = stlink
debug_tool = stlink
monitor_speed = 115200
monitor_port = COM3
[platformio]
src_dir = Core/Src
include_dir = Core/Inc
- board_build.ldscript:指定链接脚本路径;
- upload_protocol:用板载 ST-Link 烧录;
- monitor_xxx:串口监视器的波特率和端口号。COM3 不一定是你实际端口,打开设备管理器看一下 ST-Link 的端口号是多少,改成实际的;
- [platformio]:指定代码源文件夹,不然会使用默认的 src 目录。
4. 编译 & 烧录
编写测试代码
打开 Core/Src/main.c,找到 while (1),加上测试代码,LED 每秒闪烁一次,串口每秒打印一次:
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(1000);
uint8_t data[] = "Hello, world!\r\n";
HAL_UART_Transmit(&huart2, data, sizeof(data) - 1, HAL_MAX_DELAY);
}
/* USER CODE END 3 */
注意:代码要写在 USER CODE BEGIN / END 注释块里面,不然修改 CubeMX 后重新生成代码会被覆盖掉。
编译
VS Code 底部 PlatformIO toolbar 点 ✓ (Build),或者在 PIO 的终端跑 pio run,编译成功之后,输出末尾能看到类似 log:
RAM: [ ] 0.2% (used 376 bytes from 163840 bytes)
Flash: [ ] 1.4% (used 7440 bytes from 524288 bytes)
Building .pio\build\nucleo_l452re\firmware.bin
============ [SUCCESS] Took 8.75 seconds ========
烧录
点击 → (Upload) 按钮,或者终端执行 pio run --target upload,烧录成功后板子上的 LED 应该开始一秒闪一次。
[stm32l4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08001dbc msp: 0x20020000
** Programming Started **
Warn : Adding extra erase range, 0x08001ec0 .. 0x08001fff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
串口输出
PlatformIO 底部栏点 (Serial Monitor),或者终端跑 pio device monitor,可以看到熟悉的 Hello, world!
常见问题
编译报错
出现链接文件相关的报错,原因可能是 GCC 10 及以下不支持相关关键字,PlatformIO 自带的工具链版本比较老,在 platformio.ini 加上指定的 GCC11 版本即可,保存配置文件后就会自动下载:
[env:nucleo_l452re]
platform_packages = platformio/toolchain-gccarmnoneeabi@^1.110301.0
在终端输入 pio pkg search toolchain-gccarmnoneeabi,可以看到找到的 gcc 版本 platformio/toolchain-gccarmnoneeabi Tool • 1.140201.0 • Published on Fri Feb 28 20:40:53 2025 GNU toolchain for Arm Cortex-M and Cortex-R processors platformio/toolchain-gccarmnoneeabi-teensy Tool • 1.110301.0 • Published on Wed Apr 5 15:30:49 2023 GNU toolchain for Teensy boards based on Arm Cortex-M
PlatformIO 找不到头文件
检查 platformio.ini 里的 include_dir 是不是 Core/Inc,路径是相对项目根目录的。
串口输出乱码
通常是波特率对不上,检查 CubeMX 里对应串口的 Baud Rate 是不是 115200,串口工具或者 platformio.ini 里 monitor_speed 是不是一致。