手把手:RT-Thread Studio 生成串口工程(STM32F407ZGT6),附完整源码

📅 2026/7/24 19:39:03
手把手:RT-Thread Studio 生成串口工程(STM32F407ZGT6),附完整源码
前言之前写过一篇利用 STM32CubeMX 裸机工程手动移植 RT-Thread 的文章。今天换一种更省事的方式——直接用 RT-Thread Studio 生成工程全程可视化操作不需要手动复制文件。本文面向第一次用 RT-Thread Studio 做 STM32 开发的同学目标新建工程 → 配置外设 → 写代码 → 在板子上跑通三个线程。目录前言一、开发环境二、下载 RT-Thread Studio三、新建 RT-Thread 工程四、STM32CubeMX配置4.1 打开 CubeMX Settings4.2 配置 RCC时钟源4.3 配置 SYS调试接口4.4 配置 GPIOLED4.5 配置 USART1串口4.6 配置时钟树4.7 工程管理配置4.8 生成代码五、编译六、编写应用代码6.1 将外设初始化搬到应用 main6.2 创建三个线程6.3 编译报错七、实验验证7.1 调试终端验证7.2 硬件验证八、总结一、开发环境主控芯片STM32F407ZGT6编译工具RT-Thread Studio2.3.0配置工具STM32CubeMX 6.17.0操作系统RT-Thread 4.0.3串口助手SSCOM V5.13.1二、下载 RT-Thread Studio进入RT-Thread Studio官网rt-thread.org/studio.html点击下载。推荐使用版本2.3.0对新手更友好网盘下载或官网下载均可。下载后默认安装即可。三、新建 RT-Thread 工程打开 RT-Thread Studio菜单栏选择文件--新建-- RT-Thread 项目。在弹出的对话框中填写工程信息如果首次使用没有安装 STM32F4 系列芯片支持包在SDK 管理器里搜索安装即可。安装完成后点击完成。一个基础的 RT-Thread 工程就创建成功了。注意目前工程使用的是芯片内部HSI 时钟8MHz精度一般。建议后续通过 CubeMX 切换到外部 HSE 晶振以获得准确的主频。四、STM32CubeMX配置RT-Thread Studio 内置了CubeMX Settings入口可以直接启动 CubeMX 并同步配置。4.1 打开 CubeMX Settings在工程根目录双击CubeMX Settings选择你安装的 STM32CubeMX.exe 路径。4.2 配置 RCC时钟源进入RCCHSE→ 选择Crystal/Ceramic Resonator4.3 配置 SYS调试接口进入SYSDebug→ 选择Serial Wire (SWD)占用 PA13/PA14与调试器通信警告调试接口一定要配成 SWD否则 PA13/PA14 被当成 GPIO 后 SWD 会连不上板子只能通过 BOOT 模式救砖。4.4 配置 GPIOLED在芯片引脚图上点击 PF9 和 PF10选择GPIO_Output用于控制板载 LED。4.5 配置 USART1串口选择USART1配置为异步串口通信参数保持默认115200-8-N-1。4.6 配置时钟树切换到Clock Configuration标签页输入 HSE 频率24 MHzPLLM 分频12PLLN 倍频168PLLP 分频2最终系统时钟168 MHz注意HSE要根据板子实际的外部晶振频率来。4.7 工程管理配置4.8 生成代码点击GENERATE CODE等待 CubeMX 生成完成。回到 RT-Thread Studio会提示检测到代码变更。验证时钟配置是否生效打开board/drv_clk.c可以看到它自动调用了 CubeMX 生成的SystemClock_Config()配置参数为24MHz 外部晶振锁相到 168MHz。void clk_init(char *clk_source, int source_freq, int target_freq) { /* * Use SystemClock_Config generated from STM32CubeMX for clock init * system_clock_config(target_freq); */ extern void SystemClock_Config(void); SystemClock_Config(); }void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM 12; RCC_OscInitStruct.PLL.PLLN 168; RCC_OscInitStruct.PLL.PLLP RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ 4; if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(RCC_ClkInitStruct, FLASH_LATENCY_5) ! HAL_OK) { Error_Handler(); } }五、编译在写程序代码之前我们先构建项目。点击项目 → 全部构建CtrlB会看到几十个类似stm32f4xx_hal_conf.h: No such file or directory的错误。原因是CubeMX 生成代码时用完整版 HAL 库覆盖了 RT-Thread 的精简版但头文件路径不一致。这时候需要通过Sconscript文件进行构建加载更新软件包。Sconscriptimport os from building import * cwd GetCurrentDir() src Glob(*.c) add cubemx drivers src Split( Src/stm32f4xx_hal_msp.c Src/main.c ) path [cwd] path [cwd /Inc] group DefineGroup(cubemx, src, depend [], CPPPATH path) Return(group)然后再全部构建一下发现还有报错。双击错误提示处软件会自动跳转到出错的地方。发现原因就是新版drv_usart.c想读取cfg-flowcontrol判断硬件流控模式但旧版serial.h定义的结构体里根本没这个成员编译器直接报错。所以我们将这段switch注释掉就行了一般用不到硬件流控。然后重新构建。至此RT-Thread 工程已成功创建完成。接下来我们将开始编写应用程序代码。六、编写应用代码RT-Thread Studio 生成的模板工程里有两个main.c位置说明编译方式cubemx/Src/main.cCubeMX 生成的 main带__WEAK弱符号不会被调用applications/main.c你写代码的地方链接器优先使用这个因为 CubeMX 的 main 带__WEAK弱符号链接器会自动选择applications/main.c里的int main(void)作为入口。两个 main 不会冲突。查看cubemx/Src/main.c。__WEAK int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals / MX_GPIO_Init(); MX_USART1_UART_Init(); / USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop / / USER CODE BEGIN WHILE / while (1) { / USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }再查看applications/main.c。/* * Copyright (c) 2006-2026, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2026-07-23 RT-Thread first version */ #include rtthread.h #define DBG_TAG main #define DBG_LVL DBG_LOG #include rtdbg.h int main(void) { int count 1; while (count) { LOG_D(Hello RT-Thread!); rt_thread_mdelay(1000); } return RT_EOK; }6.1 将外设初始化搬到应用 main把 CubeMX 生成的外设初始化函数搬到applications/main.c里#include rtthread.h #include gpio.h #include main.h #include usart.h int main(void) { /* CubeMX 初始化GPIO 模式、USART1 波特率/引脚 */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* ... 后续创建线程 */ }6.2 创建三个线程分别实现三个功能线程功能周期thread1串口打印 Thread1 run每 2 秒thread2串口打印 Thread2 run每 3 秒thread3PF9LED0和 PF10LED1交替闪烁每 1 秒切换完整代码如下含详细注释/* * Copyright (c) 2006-2026, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2026-07-23 RT-Thread first version */ #include rtthread.h /* RT-Thread 内核头文件线程、信号量、rt_kprintf 等 */ #include gpio.h /* CubeMX 生成的 GPIO 初始化声明 */ #include main.h /* CubeMX 主头文件引脚定义、外设句柄 */ #include usart.h /* CubeMX 生成的 USART 初始化声明 */ static rt_thread_t thread1; /* 线程句柄指向 thread1 */ static rt_thread_t thread2; /* 线程句柄指向 thread2 */ static rt_thread_t thread3; /* 线程句柄指向 thread3 */ /*--------------------------------------------------------- * 线程 1 入口每 2 秒打印一次 Thread1 run *---------------------------------------------------------*/ static void thread1_entry(void *parameter) { while(1) { rt_kprintf(Thread1 run\r\n); /* 串口输出 */ rt_thread_mdelay(2000); /* 挂起 2 秒让出 CPU */ } } /*--------------------------------------------------------- * 线程 2 入口每 3 秒打印一次 Thread2 run *---------------------------------------------------------*/ static void thread2_entry(void *parameter) { while(1) { rt_kprintf(Thread2 run\r\n); rt_thread_mdelay(3000); /* 挂起 3 秒 */ } } /*--------------------------------------------------------- * 线程 3 入口LED 交替闪烁PF9 / PF10每 1 秒切换一次 *---------------------------------------------------------*/ static void thread3_entry(void *parameter) { while(1) { /* LED0 灭LED1 亮 */ HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_SET); rt_thread_mdelay(1000); /* 保持 1 秒 */ /* LED0 亮LED1 灭 */ HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_RESET); rt_thread_mdelay(1000); /* 保持 1 秒 */ } } /*--------------------------------------------------------- * 主函数初始化硬件创建并启动三个线程 *---------------------------------------------------------*/ int main(void) { /* CubeMX 初始化GPIO 模式、USART1 波特率/引脚 */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* 创建并启动线程 1打印 thread1 */ thread1 rt_thread_create(thread1, /* 线程名称FinSH 可见 */ thread1_entry, /* 入口函数 */ RT_NULL, /* 入口参数 */ 512, /* 栈大小字节 */ 5, /* 优先级0~31越小越高 */ 15); /* 时间片线程一次能跑多久 */ if(thread1 ! RT_NULL) { rt_thread_startup(thread1); /* 将线程加入就绪队列 */ } /* 创建并启动线程 2打印 thread2 */ thread2 rt_thread_create(thread2, thread2_entry, RT_NULL, 512, 5, 15); if(thread2 ! RT_NULL) { rt_thread_startup(thread2); } /* 创建并启动线程 3LED 闪烁 */ thread3 rt_thread_create(thread3, thread3_entry, RT_NULL, 512, 5, 15); if(thread3 ! RT_NULL) { rt_thread_startup(thread3); } /* main 线程不能退出否则调度器会跑飞 */ /* 用 mdelay 循环挂起自己让 tshell 和其他线程能正常调度 */ while(1) { rt_thread_mdelay(1000); /* 挂起 1 秒让出 CPU */ } return RT_EOK; /* 实际上不会跑到这里 */ }6.3 编译报错全部构建发现报错。程序找不到这两个初始化函数定义的地方也就是说gpio.c和usart.c没有被编译。查看cubemx文件发现gpio.c和usart.c不见了是被排除构建了。为什么会造成这样的问题呢是因为SConscript 是一个Python 脚本是 scons 编译系统的花名册。它用src列表告诉 scons这个目录下只有这些 .c 要编译别的不管。src Glob(*.c) src Split( Src/stm32f4xx_hal_msp.c Src/main.c )这条命令的意思是总共只编译两个文件stm32f4xx_hal_msp.c和main.c。CubeMX 生成的gpio.c、usart.c——SConscript 眼里不存在。所以这导致了gpio.c和usart.c没有被构建。解决方案是我们手动把它们添加到构建里。将gpio.c和usart.c重新添加构建。再次编译0 errors0 warnings ✅七、实验验证7.1 调试终端验证RT-Thread Studio 自带终端。连接后复位板子可以看到输入list_thread查看线程状态7.2 硬件验证断开终端连接否则占用串口点击烧录按钮向下箭头图标将 USB Type-C线连接到板子打开串口助手115200-8-N-1勾选加回车换行按复位键看到开发板上两个 LED 交替闪烁串口助手有线程打印信息实验成功。八、总结从零到三个线程同时跑通核心就三步建工程RT-Thread Studio 新建基于芯片的模板配外设CubeMX 配置时钟 / GPIO / 串口生成代码写代码多线程交替打印 LED 闪烁RT-Thread Studio CubeMX 的组合是目前 STM32 开发可视化配置 RTOS 生态最快捷的路线之一。但两者之间有一些集成细节需要注意——本文踩的坑大部分都是 CubeMX 和 RT-Thread 之间约定不同导致的。掌握了这些以后用 CubeMX 配其他外设SPI、I2C、TIM也是同样的套路。通过网盘分享的文件Demo.zip链接: https://pan.baidu.com/s/1SaHbVXh7IT_oiTI3MCazXQ?pwdtaoq提取码: taoq--来自百度网盘超级会员v3的分享若发现文中疏漏欢迎指正交流。创作不易还望多多支持。