VSCode + GCC 环境下 STM32 移植 RT-Thread Nano 的实战指南

张开发
2026/4/13 6:52:54 15 分钟阅读

分享文章

VSCode + GCC 环境下 STM32 移植 RT-Thread Nano 的实战指南
1. 为什么选择VSCodeGCC开发STM32作为一个常年混迹嵌入式开发的老鸟我强烈推荐VSCodeGCC这个组合来开发STM32项目。很多人可能习惯了Keil或IAR这类传统IDE但我要告诉你用VSCode开发STM32真香首先说说VSCode的优势。这个编辑器轻量级、插件丰富代码提示和跳转功能完全不输专业IDE。我实测下来在同样配置的电脑上VSCode启动速度比Keil快3倍不止。而且它跨平台Windows、Linux、MacOS通吃再也不用为了不同系统装不同的开发环境。再说GCC工具链。arm-none-eabi-gcc是免费的不像Keil有代码大小限制。我用GCC编译同样的项目生成的代码体积比Keil小了约15%。而且GCC支持C17等现代特性写起来更顺手。最爽的是这个组合完全免费不用到处找破解版也不用担心版权问题。对于个人开发者和小团队来说能省下不少授权费用。2. 环境搭建全攻略2.1 必备软件安装工欲善其事必先利其器。在开始移植RT-Thread之前我们需要准备好开发环境。以下是必须安装的软件VSCode从官网下载最新版安装时记得勾选添加到PATHGCC工具链推荐使用arm-none-eabi-gcc 10.3版本STM32CubeMX用于生成基础工程Cortex-Debug插件VSCode的调试神器Make工具建议使用MinGW-w64提供的make安装GCC时有个坑要注意Windows用户建议把工具链路径添加到系统环境变量我一般放在C:\gcc-arm这种没有空格的路径下避免后续编译出问题。2.2 工程初始化用STM32CubeMX新建工程时关键配置如下工具链选择Makefile在Code Generator选项卡勾选为每个外设生成单独的.c/.h文件堆栈大小建议设置大一些我通常设为0x1000生成工程后用VSCode打开项目文件夹。这时候我们需要配置三个关键文件// tasks.json { version: 2.0.0, tasks: [ { label: Build, type: shell, command: make, args: [-j8], group: { kind: build, isDefault: true } } ] }// launch.json { version: 0.2.0, configurations: [ { name: Cortex Debug, cwd: ${workspaceRoot}, executable: ${workspaceRoot}/build/${workspaceFolderBasename}.elf, request: launch, type: cortex-debug, servertype: jlink, device: STM32F103C8 } ] }# Makefile修改点 CFLAGS -mcpucortex-m3 -mthumb -Wall -O0 -g LDFLAGS -specsnano.specs -lc -lm -lnosys3. RT-Thread Nano源码准备3.1 选择合适的版本RT-Thread有完整版和Nano版两种。对于资源受限的STM32F1系列我强烈建议用Nano版。它的内存占用极小最小配置下仅占用3KB ROM和1KB RAM。从GitHub下载最新Nano版源码git clone https://github.com/RT-Thread/rtthread-nano.git下载后我习惯把源码放在项目根目录的rt-thread文件夹下。目录结构应该是这样的你的项目/ ├── Core/ ├── Drivers/ ├── rt-thread/ │ ├── include/ │ ├── libcpu/ │ ├── src/ │ └── bsp/ └── Makefile3.2 源码裁剪技巧Nano版虽然已经很小了但我们还可以进一步裁剪删除libcpu中非ARM架构的代码删除bsp下所有非当前平台的代码删除documentation等文档文件夹我实测下来经过裁剪后的RT-Thread仅占用约2.5KB ROM空间非常适合STM32F103这种只有64KB Flash的芯片。4. Makefile配置详解4.1 添加RT-Thread源文件修改Makefile是关键步骤这里我给出一个通用模板# RT-Thread源码路径 RT_THREAD_DIR rt-thread # 添加RT-Thread源文件 C_SOURCES \ $(wildcard $(RT_THREAD_DIR)/src/*.c) \ $(wildcard $(RT_THREAD_DIR)/libcpu/arm/cortex-m3/*.c) \ $(RT_THREAD_DIR)/bsp/board.c # 添加汇编文件 ASM_SOURCES \ $(RT_THREAD_DIR)/libcpu/arm/cortex-m3/context_gcc.s # 添加头文件路径 C_INCLUDES \ -I$(RT_THREAD_DIR)/include \ -I$(RT_THREAD_DIR)/bsp # 关键编译选项 CFLAGS -DUSE_HAL_DRIVER -DSTM32F103xB CFLAGS -Wa,-mimplicit-itthumb # 解决汇编指令问题4.2 常见编译错误解决第一次编译很可能会遇到这些问题隐式IT指令错误 解决方法添加-Wa,-mimplicit-itthumb编译选项重复定义中断函数 需要删除或注释掉stm32f1xx_it.c中的以下函数HardFault_HandlerPendSV_HandlerSysTick_Handler内存不足错误 修改链接脚本(.ld文件)适当增大堆栈大小_Min_Heap_Size 0x800; /* 2KB */ _Min_Stack_Size 0x800; /* 2KB */5. 关键代码修改点5.1 启动文件修改这是最容易出错的地方。找到startup_stm32f103xe.s文件做两处修改将bl main改为bl entry确保堆栈大小设置合理; 修改前 ; bl main ; 修改后 bl entry5.2 系统时钟配置RT-Thread需要正确的时钟配置。在board.c的rt_hw_board_init()函数中添加void rt_hw_board_init() { HAL_Init(); SystemClock_Config(); // 这是CubeMX生成的函数 /* 初始化硬件定时器 */ rt_hw_usart_init(); // 如果使用串口控制台 /* 初始化系统时钟 */ SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); /* 调用组件初始化 */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif }5.3 串口控制台配置如果要用串口作为控制台需要实现rt_hw_console_output()函数void rt_hw_console_output(const char *str) { rt_size_t i 0, size 0; char a \r; size rt_strlen(str); for (i 0; i size; i) { if (*(str i) \n) { HAL_UART_Transmit(huart1, (uint8_t *)a, 1, 10); } HAL_UART_Transmit(huart1, (uint8_t *)(str i), 1, 10); } }6. 调试技巧与实战经验6.1 常见问题排查系统启动失败检查启动文件是否修改正确确认堆栈大小设置足够使用JLink Commander查看PC指针位置线程无法调度检查SysTick_Handler是否被RT-Thread接管确认系统时钟配置正确查看rtconfig.h中的RT_TICK_PER_SECOND值内存不足使用list_mem()命令查看内存使用情况调整rtconfig.h中的RT_MAIN_THREAD_STACK_SIZE6.2 性能优化建议Tick频率设置 对于STM32F103我建议设置为1000Hz#define RT_TICK_PER_SECOND 1000线程栈大小 主线程栈至少256字节简单任务线程可以设为128字节#define RT_MAIN_THREAD_STACK_SIZE 256使用硬件定时器 如果对定时精度要求高可以用硬件定时器替代SysTickvoid rt_hw_timer_init() { /* 硬件定时器初始化代码 */ }7. 进阶功能扩展7.1 添加FinSH组件FinSH是RT-Thread的交互式shell添加步骤如下从完整版RT-Thread中复制components/finsh目录在rtconfig.h中开启宏#define RT_USING_FINSH修改链接脚本添加FinSH需要的段实现rt_hw_console_getchar()函数7.2 内存管理配置默认情况下Nano版使用静态内存管理要启用动态内存在rtconfig.h中取消注释#define RT_USING_HEAP修改链接脚本指定堆区域.heap : { __heap_start__ .; . . _Min_Heap_Size; __heap_end__ .; } RAM7.3 添加设备驱动框架要使用RT-Thread的设备驱动框架在rtconfig.h中开启#define RT_USING_DEVICE #define RT_USING_DEVICE_IPC实现rt_hw_usart_init()等硬件初始化函数注册设备到系统rt_device_t device; device rt_device_find(uart1); rt_device_open(device, RT_DEVICE_FLAG_RDWR);移植完成后你可以创建一个简单的线程测试系统是否正常工作static void thread_entry(void *parameter) { while (1) { rt_kprintf(Hello RT-Thread!\n); rt_thread_mdelay(1000); } } int main(void) { rt_thread_t tid; tid rt_thread_create(test, thread_entry, RT_NULL, 256, 10, 10); if (tid ! RT_NULL) { rt_thread_startup(tid); } return 0; }在实际项目中我遇到过因为栈大小设置不足导致系统跑飞的情况。后来养成了习惯每个线程创建时都会仔细计算所需的栈空间并留出至少20%的余量。

更多文章