资讯详情

资讯详情

在Windows上用VS Code搭建STM32F103C8T6开发环境:TaoToken统一Key接入CMake工具链

1. Windows 下 STM32F103C8T6 开发环境为什么值得用 VS Code CMake 重搭一遍STM32F103C8T6 这块最小系统板十几块钱就能买到Cortex-M3 内核、64KB Flash、20KB RAM资料多到翻不完。很多人第一次点灯是在 Keil 或 IAR 里完成的但用久了会发现两个问题一是工程文件是二进制格式Git diff 基本没法看二是编辑器体验和现代前端/后端开发差得太远补全慢、跳转飘。VS Code CMake Ninja arm-none-eabi-gcc 这套组合本质上是把嵌入式工程拉回到「纯文本 命令行」的世界。CMakeLists.txt 是文本链接脚本是文本启动汇编是文本所有东西都能进版本控制也能被 AI 辅助工具读懂。这一点很关键——当你想让 AI 帮你补全寄存器操作、解释中断向量表、生成外设初始化代码时它需要看到完整的工程上下文而不是一个.uvprojx二进制文件。这套环境适合谁适合已经会一点 C 语言、手上有一块 STM32F103C8T6 和 ST-Link 烧录器、想在 Windows 上把编译烧录流程彻底搞明白的人。不适合完全没碰过单片机、连 GPIO 是什么都不知道的纯小白因为启动文件和链接脚本这两块需要一点耐心。我这次会把整条链路走通从工具链安装、CMakeLists 编写、启动汇编和链接脚本、到cmake --build编译出 bin、st-flash烧录、串口验证最后再把 AI 辅助编码工具的 Base URL 统一改到 TaoToken 通道让补全和问答稳定可用。目标是一次性跑通而不是每换一台电脑就重来一遍。先说清楚整体结构避免后面迷路。工程目录大概长这样Chapter1/ ├── CMakeLists.txt ├── stm32_from0_c8t6.ld ├── INC/ ├── SRC/ │ ├── startup.s │ ├── crt0.s │ └── main.c ├── tool/ │ └── arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi/ └── .vscode/ ├── c_cpp_properties.json └── tasks.json工具链放在工程内的tool/目录而不是塞进系统环境变量这是有意的。我电脑上同时存在 2016 版和 2024 版的 GCC如果都加进 PATH编译时到底用哪个版本全靠运气。把工具链路径写进 CMakeLists用set(ENV{PATH} ...)临时前置就能精确锁定版本换项目也不互相干扰。2. TaoToken 统一 Key 通道的前置准备Base URL、API Key 与模型 ID 三件套在讲 AI 辅助编码工具接入之前先把 TaoToken 这条通道说清楚。它的作用是把多个模型的调用收敛到一个统一的 Base URL 和一把 Key 上你在 VS Code 里用的补全插件、对话插件、甚至命令行里的 coding agent都可以指向同一个入口不用每个工具单独配一套密钥。需要准备的三件套是项目值说明Base URLhttps://taotoken.net/api所有请求的统一入口注意不要带多余路径API Key在控制台生成形如sk-开头的一串字符Model ID按需选择例如对话类、代码类模型各有对应 ID控制台地址在这里生成 Key 的时候建议单独建一个给嵌入式项目用方便后面排查问题时能快速定位是哪个工具在发请求https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Key 管理页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档在这里不同工具的配置字段名不完全一样遇到base_url、baseURL、api_base这几种写法时对照一下https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite如果你只是想先验证 Key 能不能用、模型通不通不用急着装插件直接打开模型对话页面发一句话最快https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite长期在 VS Code 里做嵌入式编码、想让 agent 帮你改 CMakeLists、读启动汇编、生成外设驱动可以考虑 Coding Plan额度更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite这里要强调一点TaoToken 是模型调用的统一入口不是编辑器替代品。VS Code 还是 VS CodeCMake 还是 CMake它只是让你在 VS Code 里调用的 AI 能力有一个稳定的出口。别把它理解成「装了就能自动写代码」它解决的是「多个工具各配一套 Key、经常 401」这个具体问题。配置的时候有个容易踩的坑Base URL 到底带不带/v1。不同客户端处理方式不同有的会自动补/v1/chat/completions有的需要你写全。稳妥做法是先按文档给的https://taotoken.net/api填如果报 404 再检查客户端是不是重复拼接了路径。这个后面排障章节会展开。3. 可复制配置CMakeLists、链接脚本与 VS Code 三件套这一节是整篇的核心配置能直接抄。先看顶层CMakeLists.txt我把它拆成几段讲但你可以整段复制。第一段是工具链路径和系统设置。注意COMPILER_PATH指向工程内的tool/目录CMAKE_SYSTEM_NAME必须设成Generic这是交叉编译的标志cmake_minimum_required(VERSION 3.24.1 FATAL_ERROR) set(COMPILER_PATH ${CMAKE_SOURCE_DIR}/../tool/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi/bin) set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR cortex-m3) if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Windows) set(env_list_delimeter ;) else() set(env_list_delimeter :) endif() set(ENV{PATH} ${COMPILER_PATH}${env_list_delimeter}$ENV{PATH}) find_program(CMAKE_C_COMPILER arm-none-eabi-gcc) find_program(CMAKE_OBJCOPY arm-none-eabi-objcopy) find_program(CMAKE_OBJDUMP arm-none-eabi-objdump) find_program(CMAKE_AS arm-none-eabi-as) find_program(CMAKE_AR arm-none-eabi-ar) find_program(CMAKE_RANLIB arm-none-eabi-ranlib) find_program(CMAKE_READELF arm-none-eabi-readelf) find_program(CMAKE_NM arm-none-eabi-nm) find_program(CMAKE_STRIP arm-none-eabi-strip) find_program(CMAKE_GDB arm-none-eabi-gdb) find_program(CMAKE_CXX_COMPILER arm-none-eabi-g)第二段是编译标志。-mcpucortex-m3 -mthumb -marcharmv7-m这三个是 Cortex-M3 的标配--specsnosys.specs让链接器不拉标准 C 库-Wl,--gc-sections配合-ffunction-sections -fdata-sections能显著减小固件体积set(C_FLAG) string(APPEND C_FLAG -stdgnu99) string(APPEND C_FLAG -ffunction-sections -fdata-sections) set(CPU_FLAG -mcpucortex-m3 -mthumb -marcharmv7-m) set(SPEC_FLAG --specsnosys.specs) set(LD_FLAGS -Wl,--gc-sections -ereset_handler -nostartfiles) string(APPEND LD_FLAGS -Wl,-Mapout.map) string(APPEND LD_FLAGS -T ${CMAKE_CURRENT_LIST_DIR}/stm32_from0_c8t6.ld) set(CMAKE_C_FLAGS ${C_FLAG} ${CPU_FLAG} ${SPEC_FLAG}) set(CMAKE_CXX_FLAGS ${C_FLAG} ${CPU_FLAG} ${SPEC_FLAG}) set(CMAKE_ASM_FLAGS ${CPU_FLAG} -x assembler-with-cpp) set(CMAKE_EXE_LINKER_FLAGS ${CPU_FLAG} ${LD_FLAGS}) SET(CMAKE_C_FLAGS_DEBUG -Og -g -ggdb3) SET(CMAKE_C_FLAGS_RELEASE -O3) SET(CMAKE_ASM_FLAGS_DEBUG -g -ggdb3) SET(CMAKE_ASM_FLAGS_RELEASE )第三段是工程定义、源文件收集和后处理命令。file(GLOB ... CONFIGURE_DEPENDS)会自动扫描SRC/下的.c和.s新增文件不用改 CMakeListsproject(stm32_from0 LANGUAGES C ASM) set(KERNEL_NAME app) set(CMAKE_EXECUTABLE_SUFFIX .elf) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) set(KERNEL_ELF_NAME ${KERNEL_NAME}.elf) set(KERNEL_BIN_NAME ${KERNEL_NAME}.bin) set(KERNEL_HEX_NAME ${KERNEL_NAME}.hex) add_executable(${KERNEL_NAME}) file(GLOB SRC_LIST CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/SRC/*.c ${CMAKE_SOURCE_DIR}/SRC/*.s) target_sources(${KERNEL_NAME} PRIVATE ${SRC_LIST}) target_include_directories(${KERNEL_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/INC) add_custom_command( TARGET ${KERNEL_NAME} POST_BUILD COMMAND ${CMAKE_OBJCOPY} --output-targetbinary ${KERNEL_ELF_NAME} ${KERNEL_BIN_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} ) add_custom_command( TARGET ${KERNEL_NAME} POST_BUILD COMMAND ${CMAKE_OBJCOPY} --gap-fill;0xff --output-targetihex ${KERNEL_ELF_NAME} ${KERNEL_HEX_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} ) set(FLASH_COMMAD st-flash) add_custom_target(flash COMMAND ${FLASH_COMMAD} --reset --freq10000 write ${EXECUTABLE_OUTPUT_PATH}/${KERNEL_NAME}.bin 0x8000000)链接脚本stm32_from0_c8t6.ld定义了内存布局C8T6 是 64KB Flash 20KB RAM起始地址分别是0x8000000和0x20000000ENTRY(reset_handler) MEMORY { RAM (xrw) : ORIGIN 0x20000000, LENGTH 20K FLASH (rx) : ORIGIN 0x8000000, LENGTH 64K } __STACKSIZE__ 1024; SECTIONS { .vectors : { . ALIGN(4); KEEP(*(.vectors .vectors.*)) . ALIGN(4); } FLASH .text : { . ALIGN(4); *(.text) . ALIGN(4); } FLASH .data : { __data_start ALIGN(4); KEEP(*(.data)) __data_end ALIGN(4); } RAM AT FLASH __data_load_start LOADADDR(.data); __data_size SIZEOF(.data); .bss (NOLOAD): { __bss_start ALIGN(4); *(.bss) __bss_end ALIGN(4); } RAM .stack : { __stack_start ALIGN(4); . ALIGN(. __STACKSIZE__, 4); __stack_end ALIGN(4); } RAM }VS Code 这边需要两个配置文件。.vscode/c_cpp_properties.json让 C/C 插件读取compile_commands.json这样跳转和补全才准{ configurations: [ { name: Embedded_learn, compileCommands: ${workspaceFolder}/build/compile_commands.json } ], version: 4 }.vscode/tasks.json把配置、编译、烧录三个动作绑成快捷键{ version: 2.0.0, tasks: [ { label: cmake-configure, type: shell, command: cmake, args: [ -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOLTRUE, -Bbuild, -GNinja ], options: { cwd: ${workspaceFolder} }, problemMatcher: [] }, { label: cmake-build, type: shell, command: cmake, args: [--build, build, --config, Release, --target, app], options: { cwd: ${workspaceFolder} }, dependsOn: cmake-configure, problemMatcher: [] }, { label: flash, type: shell, command: cmake, args: [--build, build, --target, flash], options: { cwd: ${workspaceFolder} }, dependsOn: cmake-build, problemMatcher: [] } ] }如果你用的是 Cline 这类带 MCP 的插件配置里同样要写全三件套Base URL 填https://taotoken.net/apiKey 填控制台生成的Model ID 按插件要求填。Codex 的auth.json也是类似结构把base_url指向同一个地址即可。核心原则就一条所有工具的 Base URL 保持一致Key 用同一把出问题时只需要换一个地方。4. 验证请求从 cmake 配置到 st-flash 烧录成功配置写完了现在跑一遍完整流程确认每一步都有明确输出。第一步在工程根目录打开终端执行配置命令。这一步不编译代码只生成 Ninja 构建文件和compile_commands.jsoncmake -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOLTRUE -Bbuild -GNinja成功的话会看到类似输出-- The C compiler identification is GNU 13.3.1 -- The ASM compiler identification is GNU -- Found assembler: .../arm-none-eabi-gcc.exe -- Configuring done -- Generating done -- Build files have been written to: .../Chapter1/build这时候build/目录下会出现compile_commands.json打开看一眼command字段确认 GCC 路径和编译参数跟你设置的一致。这一步很关键因为 VS Code 的跳转全靠它。第二步编译cmake --build build --config Release --target app成功后会看到链接过程和 objcopy 的输出build/bin/下生成app.elf、app.bin、app.hex。用arm-none-eabi-size build/bin/app.elf看一下体积text data bss dec hex filename 312 0 1028 1340 53c build/bin/app.elftext是 Flash 占用data bss是 RAM 占用。C8T6 有 64KB Flash 和 20KB RAM这个数字离上限还很远。第三步烧录。ST-Link 的 SWD 接口接好SWCLK、SWDIO、GND、3.3V执行cmake --build build --target flash成功输出类似st-flash --reset --freq10000 write .../build/bin/app.bin 0x8000000 st-flash 1.7.0 2024-xx-xxTxx:xx:xx INFO common.c: STM32F1xx: 64 KiB Flash, 20 KiB RAM 2024-xx-xxTxx:xx:xx INFO common.c: Flash written and verified! jolly good!看到Flash written and verified就说明固件已经进芯片了。当前main.c里只有一个死循环所以板子上看不出任何现象这是正常的。第四步串口验证。把main.c改成往 USART1 发一句话确认程序真的在跑#include stdint.h #define RCC_APB2ENR (*(volatile uint32_t *)0x40021018) #define GPIOA_CRH (*(volatile uint32_t *)0x40010804) #define USART1_SR (*(volatile uint32_t *)0x40013800) #define USART1_DR (*(volatile uint32_t *)0x40013804) #define USART1_BRR (*(volatile uint32_t *)0x40013808) #define USART1_CR1 (*(volatile uint32_t *)0x4001380C) static void uart_init(void) { RCC_APB2ENR | (1 2) | (1 14); GPIOA_CRH ~(0xF 4); GPIOA_CRH | (0xB 4); USART1_BRR 0x1D4C; USART1_CR1 (1 3) | (1 13); } static void uart_send(char c) { while (!(USART1_SR (1 7))); USART1_DR c; } void main(void) { uart_init(); const char *msg stm32f103c8t6 cmake ok\r\n; while (*msg) uart_send(*msg); while (1) { } }重新编译烧录用串口工具波特率 115200打开对应 COM 口能看到stm32f103c8t6 cmake ok。到这一步整条链路就通了CMake 配置 → 编译 → objcopy 生成 bin → st-flash 烧录 → 串口输出。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth 报错环境搭起来的过程中报错基本集中在两类一类是编译烧录链路一类是 AI 工具接入。分开说。编译类报错一arm-none-eabi-gcc: command not found这是COMPILER_PATH写错了或者工具链没解压到tool/目录。检查CMakeLists.txt里的路径注意 Windows 下路径分隔符用/或\\别用单个\。另外确认bin/目录下确实有arm-none-eabi-gcc.exe。编译类报错二undefined reference to reset_handler链接脚本里的ENTRY(reset_handler)和启动汇编里的.global reset_handler对不上或者startup.s没被file(GLOB ...)扫到。检查SRC/目录下文件后缀是不是.sCMake 的 GLOB 只匹配你写的模式。编译类报错三region FLASH overflowed固件超过 64KB 了。用arm-none-eabi-size看text字段如果接近 65536说明代码太大。检查是不是误链接了标准库确认--specsnosys.specs和-Wl,--gc-sections都生效了。烧录类报错st-flash: command not foundst-link 工具没加进 PATH。要么把st-flash.exe所在目录加进系统环境变量要么在 CMakeLists 里把FLASH_COMMAD改成绝对路径。烧录类报错Failed to connect to targetSWD 接线问题。检查 SWCLK、SWDIO、GND、3.3V 四根线确认 ST-Link 驱动装好了设备管理器里能看到。有时候是板子没供电ST-Link 的 3.3V 带不动整块板子需要单独供电。AI 工具类报错401 UnauthorizedKey 不对或者没带上。检查三件套Base URL 是不是https://taotoken.net/apiKey 是不是sk-开头且没多余空格Model ID 是不是插件支持的那个。401 基本都是 Key 的问题去控制台重新生成一把试试。AI 工具类报错local proxy failed客户端在本地起了代理但没起来或者端口被占用。检查插件设置里是不是开了「使用本地代理」之类的选项关掉它让请求直连 Base URL。这类报错跟网络环境有关但不要往「需要特殊网络工具」的方向想就是本地代理配置冲突。AI 工具类报错reading choices或choices field missing返回的 JSON 结构跟客户端预期不一致。常见原因是 Base URL 多写了/v1或者少写了导致请求打到了错误的端点。把 Base URL 改回https://taotoken.net/api让客户端自己拼接路径。AI 工具类报错OAuth相关失败有些插件默认走 OAuth 登录流程而不是 API Key。在插件设置里找「使用 API Key」或「自定义 Base URL」的选项切过去填上三件套。OAuth 那条路跟统一 Key 通道是两套机制别混用。VS Code 跳转失效compile_commands.json not found配置阶段没加-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOLTRUE或者c_cpp_properties.json里的路径不对。确认build/compile_commands.json存在路径用${workspaceFolder}/build/compile_commands.json。排障的时候有个通用思路先确认命令行能跑通再去看插件。命令行cmake --build成功、st-flash成功说明工具链没问题剩下的就是插件配置。反过来如果命令行都失败别急着调插件先把 CMake 和工具链搞定。6. 把 AI 补全接进这套工程统一 Key 通道的日常用法环境跑通之后AI 辅助编码才真正有用武之地。因为现在工程是纯文本的AI 能看到CMakeLists.txt、链接脚本、启动汇编和main.c的完整上下文补全和问答的准确率会高很多。日常用法大概有这几类。第一类是解释性问答比如把startup.s里的中断向量表贴给模型问「这些.word分别对应什么异常」它能结合 Cortex-M3 手册给你讲清楚。第二类是生成外设初始化代码比如「用寄存器方式初始化 TIM2 做 1ms 中断」它能给出可编译的代码。第三类是改构建脚本比如「把 Release 优化等级从 -O3 改成 -Os」它直接给你改好的 CMakeLists 片段。要让这些稳定可用关键还是 Base URL 统一。我试过在 VS Code 里同时装对话插件和补全插件如果各配各的 Key过一段时间就会出现某个插件 401、另一个正常的情况排查起来很烦。统一到 TaoToken 之后只需要维护一把 Key哪个工具出问题一眼就能看出来。具体配置上对话类插件一般在设置里找Base URL和API Key两个字段填https://taotoken.net/api和你的 Key。补全类插件类似有的叫Endpoint有的叫API Base值是一样的。Cline 这类带 MCP 的配置文件里通常长这样{ apiProvider: openai, openAiBaseUrl: https://taotoken.net/api, openAiApiKey: sk-你的Key, openAiModelId: 你的模型ID }Codex 的auth.json结构不同但核心字段也是base_url和api_key指向同一个地址。配置完之后在插件里发一句「解释一下这个工程的链接脚本」如果它能正确读到stm32_from0_c8t6.ld的内容并解释 RAM AT FLASH的含义说明接入成功了。有个实用技巧把常用的提示词存成 VS Code 的 snippet比如「解释当前选中的汇编代码」「为这个外设生成寄存器级初始化」「检查 CMakeLists 有没有冗余配置」用的时候直接触发比每次手打快很多。最后说一个我踩过的坑。刚开始我把工具链路径写死在系统环境变量里结果换了个项目、换了个 GCC 版本编译出来的固件行为不一样查了半天才发现是 PATH 里旧版本优先。后来改成在 CMakeLists 里用set(ENV{PATH} ...)前置每个工程锁定自己的工具链版本这个问题就再没出现过。嵌入式开发里工具链版本一致性比什么都重要别图省事全塞进系统变量。到这里Windows 下 VS Code CMake 的 STM32F103C8T6 开发环境就算完整跑通了。编译、烧录、串口验证、AI 补全四条线都通了后面移植驱动、点灯、调外设就是在这个基础上往上加代码的事了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →