工程搭建 VSCode
2026-06-26
通过STM32F103C8T6的标准库工程点亮LED为例,介绍如何使用vscode搭建STM32工程,实现stlink调试器编译、下载、仿真
烧录例如gd32、air32等国产芯片不可使用stlink,需要更换为 jlink、ulink、daplink等仿真器配置方法参考仿真器概述
准备工作
获取仿真器、芯片配置文件、链接脚本文件、寄存器描述文件、标准外设库等文件。
stlink-dap.cfg
该文件是调试工具的仿真器配置文件,主要用于配置仿真器的接口类型、速度等参数。
在OpenOCD安装目录里可找到。
stm32f1x.cfg
该文件是调试工具的目标芯片配置文件,主要用于配置目标芯片的型号、内存映射等参数。
在OpenOCD安装目录里可找到。
STM32F103xx_FLASH.ld
该文件是编译器的链接脚本文件,主要用于配置目标芯片的内存布局、入口点等参数。
在STM32CubeMX创建gcc工程里可找到。
在STM32CubeIDE创建gcc工程里可找到。
在stsw-stm32054_v3-6-0.zip解压后的目录里的stm32_flash.ld修改FLASH及RAM大小后得来的。
STM32F103xx.svd
该文件是的寄存器描述文件,主要用于描述目标芯片的寄存器信息,便于在调试时查看寄存器状态。
标准外设库
该文件是ST官方提供的标准外设库,主要用于简化开发过程,提供了对芯片外设的封装和驱动。
在stsw-stm32054_v3-6-0.zip解压后的目录里可找到CMSIS及STM32F10x_StdPeriph_Driver。
stm32f10x_conf.h
该文件是标准外设库的配置文件,主要用于配置标准外设库的功能和参数。
在stsw-stm32054_v3-6-0.zip解压后的目录里的示例工程里有很多。
创建工程
创建目录结构、复制文件
新建工程目录project,并拖拽所有准备文件到project目录下,最终目录结构如下:
+ project# 工程根目录
stlink-dap.cfg# 仿真器配置文件
stm32f1x.cfg# 目标芯片配置文件
STM32F103xx_FLASH.ld# 链接脚本文件
STM32F103xx.svd# 目标芯片寄存器
stm32f10x_conf.h# 标准外设库配置文件
CMSIS# 架构库目录
…
STM32F10x_StdPeriph_Driver# 标准外设库目录
…
build# 空目录、编译镜像输出
…
添加代码补全和智能提示
c_cpp_properties.json 的核心作用是为 C/C++ 语言服务提供编译环境信息,从而让代码补全、跳转定义、悬停提示、错误检查等功能正常工作。 对编译、仿真、镜像输出、程序下载无影响。
参照以下路径及内容完成添加
project# 工程根目录
stlink-dap.cfg# 仿真器配置文件
stm32f1x.cfg# 目标芯片配置文件
STM32F103xx_FLASH.ld# 链接脚本文件
STM32F103xx.svd# 目标芯片寄存器
stm32f10x_conf.h# 标准外设库配置文件
CMSIS# 架构库目录
…
STM32F10x_StdPeriph_Driver# 标准外设库目录
…
build# 空目录、编译镜像输出
…
.vscode# vscode配置目录
c_cpp_properties.json# C/C++配置文件
{
"configurations": [
{
"name": "Win32",
// includePath 实现代码补全和智能提示的头文件搜索路径
"includePath": [
"${workspaceFolder}/CMSIS/CM3/CoreSupport",
"${workspaceFolder}/CMSIS/CM3/DeviceSupport/ST/STM32F10x",
"${workspaceFolder}/STM32F10x_StdPeriph_Driver/inc",
"${workspaceFolder}/"
],
// defines 实现代码补全和智能提示的宏定义
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"STM32",
"STM32F10X_MD",
"USE_STDPERIPH_DRIVER"
],
"cStandard": "c11",
"cppStandard": "gnu++14",
"intelliSenseMode": "windows-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}添加main.c
main.c 是汇编里面指定的C语言入口,这里添加了LED闪烁来进行测试。
project# 工程根目录
stlink-dap.cfg# 仿真器配置文件
stm32f1x.cfg# 目标芯片配置文件
STM32F103xx_FLASH.ld# 链接脚本文件
STM32F103xx.svd# 目标芯片寄存器
stm32f10x_conf.h# 标准外设库配置文件
CMSIS# 架构库目录
…
STM32F10x_StdPeriph_Driver# 标准外设库目录
…
build# 编译输出目录
…
.vscode# vscode配置目录
c_cpp_properties.json# C/C++配置文件
main.c# LED点亮示例代码
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void delay(int32_t cnt)
{
for (int32_t i = 0; i < cnt; i++)
for (int32_t j = 0; j < 1000; j++)
__NOP();
}
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {
.GPIO_Pin = GPIO_Pin_13,
.GPIO_Mode = GPIO_Mode_Out_PP,
.GPIO_Speed = GPIO_Speed_50MHz};
GPIO_Init(GPIOC, &GPIO_InitStruct);
while (1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_13);
delay(1000);
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
delay(1000);
}
}添加头文件、源文件路径配置
CMakeLists.txt 是 CMake 构建系统的配置文件,它不是 VS Code 专属文件,而是跨平台的构建系统定义文件。
CMake 指定了包含哪些源文件、头文件、宏定义、编译器参数等配置,生成Makefile供 MinGW使用。
参照以下路径及内容完成添加
project# 工程根目录
stlink-dap.cfg# 仿真器配置文件
stm32f1x.cfg# 目标芯片配置文件
STM32F103xx_FLASH.ld# 链接脚本文件
STM32F103xx.svd# 目标芯片寄存器
stm32f10x_conf.h# 标准外设库配置文件
CMSIS# 架构库目录
…
STM32F10x_StdPeriph_Driver# 标准外设库目录
…
build# 空目录、编译镜像输出
…
.vscode# vscode配置目录
c_cpp_properties.json# C/C++配置文件
main.c# LED点亮示例代码
CMakeLists.txt# CMAKE编译配置文件
# 设置 CMake 最低支持版本
cmake_minimum_required(VERSION 3.17)
# Cmake 交叉编译配置
set(CMAKE_SYSTEM_NAME Generic)
# 定义工程名称
project("demo")
# 指定编译工具
set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
set(CMAKE_CXX_COMPILER "arm-none-eabi-g++")
set(CMAKE_ASM_COMPILER "arm-none-eabi-gcc")
set(CMAKE_AR "arm-none-eabi-ar")
set(CMAKE_OBJCOPY "arm-none-eabi-objcopy")
set(CMAKE_OBJDUMP "arm-none-eabi-objdump")
set(CMAKE_SIZE "arm-none-eabi-size")
# 编译相关选项
set(MCU_FLAGS "-mcpu=cortex-m3 -mthumb -mfloat-abi=soft")
set(CMAKE_C_FLAGS_DEBUG "-g -ggdb -Og")
set(CMAKE_C_FLAGS_RELEASE "-O3")
# set(CMAKE_C_FLAGS "${MCU_FLAGS} -ffunction-sections -fdata-sections -fno-builtin -fno-common -Wextra -Werror -Wno-unknown-pragmas -Wl,-u,_printf_float") #-w -Wall
set(CMAKE_C_FLAGS "${MCU_FLAGS} -ffunction-sections -fdata-sections -fno-builtin -fno-common ") # -Wall -Wno-unknown-pragmas
set(CMAKE_ASM_FLAGS "${MCU_FLAGS} -x assembler-with-cpp")
if(RELEASE)
message("build for release!")
set(CMAKE_BUILD_TYPE "Release")
add_definitions(-DRELEASE)
else()
message("build for debug!")
set(CMAKE_BUILD_TYPE "Debug")
add_definitions(-DDEBUG)
endif()
# 设置编译器选项
add_definitions(-DUSE_STDPERIPH_DRIVER)
add_definitions(-DSTM32F10X_MD)
# 添加头文件搜索路径
include_directories(
${PROJECT_SOURCE_DIR}/CMSIS/CM3/CoreSupport
${PROJECT_SOURCE_DIR}/CMSIS/CM3/DeviceSupport/ST/STM32F10x
${PROJECT_SOURCE_DIR}/STM32F10x_StdPeriph_Driver/inc
${PROJECT_SOURCE_DIR}/
)
# 添加源文件
file(GLOB CMSIS_LIST
${PROJECT_SOURCE_DIR}/CMSIS/CM3/CoreSupport/core_cm3.c
${PROJECT_SOURCE_DIR}/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c
)
aux_source_directory(${PROJECT_SOURCE_DIR}/STM32F10x_StdPeriph_Driver/src STD_LIST)
# 设置启动文件路径
set(START_UP_ASM ${PROJECT_SOURCE_DIR}/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/gcc_ride7/startup_stm32f10x_md.s)
#设置支持 ASM
enable_language(ASM)
#设置启动文件 C 属性
set_property(SOURCE ${START_UP_ASM} PROPERTY LANGUAGE C)
# 设置链接脚本路径
set(LINKER_SCRIPT ${PROJECT_SOURCE_DIR}/STM32F103C8T6.ld)
# 设置链接器选项
set(CMAKE_EXE_LINKER_FLAGS " -specs=rdimon.specs --specs=nano.specs -specs=nosys.specs -T${LINKER_SCRIPT} -Wl,-Map=${PROJECT_BINARY_DIR}/${DEVICE_TYPE}.map,--cref -Wl,--gc-sections")
#生成目标文件
add_executable(app.elf main.c ${START_UP_ASM} ${CMSIS_LIST} ${STD_LIST})
#设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
#设置 ELF 转换路径
set(ELF_FILE ${PROJECT_BINARY_DIR}/app.elf)
set(HEX_FILE ${PROJECT_BINARY_DIR}/app.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/app.bin)
add_custom_command(TARGET "app.elf" POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Obinary ${ELF_FILE} ${BIN_FILE}
COMMAND ${CMAKE_OBJCOPY} -Oihex ${ELF_FILE} ${HEX_FILE}
COMMAND ${CMAKE_COMMAND} -E copy ${HEX_FILE} "${PROJECT_BINARY_DIR}/bin/${PROJECT_NAME}.hex"
COMMAND ${CMAKE_COMMAND} -E copy ${BIN_FILE} "${PROJECT_BINARY_DIR}/bin/${PROJECT_NAME}.bin"
COMMAND ${CMAKE_COMMAND} -E copy ${ELF_FILE} "${PROJECT_BINARY_DIR}/bin/${PROJECT_NAME}.elf"
COMMAND ${CMAKE_SIZE} --format=berkeley ${ELF_FILE} ${HEX_FILE}
COMMENT "Building ${PROJECT_NAME} (bin, hex, elf) and print size")添加编译、下载等批处理
tasks.json 是的任务配置文件,用来定义和运行编译、构建、测试等外部命令,对调试仿真无影响。
参照以下路径及内容完成添加
project# 工程根目录
stlink-dap.cfg# 仿真器配置文件
stm32f1x.cfg# 目标芯片配置文件
STM32F103xx_FLASH.ld# 链接脚本文件
STM32F103xx.svd# 目标芯片寄存器
stm32f10x_conf.h# 标准外设库配置文件
CMSIS# 架构库目录
…
STM32F10x_StdPeriph_Driver# 标准外设库目录
…
build# 空目录、编译镜像输出
…
.vscode# vscode配置目录
c_cpp_properties.json# C/C++配置文件
tasks.json# 任务配置文件
main.c# LED点亮示例代码
CMakeLists.txt# CMAKE编译配置文件
{
"version": "2.0.0",
"options": {
"cwd": "${workspaceFolder}/build"
},
"tasks": [
{
// 清理编译输出目录
"label": "clean",
"type": "shell",
"command": "rm * -r",
"problemMatcher": []
},
{
// 生成编译配置文件
"label": "cmake",
"type": "shell",
"command": "cmake",
"args": [
"-G",
"MinGW Makefiles",
".."
],
"dependsOn": [
"clean" // 生成编译配置文件前先清理编译输出目录
],
"problemMatcher": []
},
{
// 编译生成可执行文件
"label": "make",
"type": "shell",
"command": "make ", // 单线程编译
// "command": "make -j32", // 多线程编译,指定编译线程数为32
// "command": "make -j${env:NUMBER_OF_PROCESSORS}", // 多线程编译,指定编译线程数为CPU核心数
// 添加CTRL+SHIFT+B快捷键,执行make任务
"group": {
"kind": "build",
"isDefault": true
}
},
{
// 重新生成编译配置文件并编译生成可执行文件
"label": "rebuild",
"dependsOrder": "sequence",
"dependsOn": [
"cmake",
"make"
],
"problemMatcher": []
},
{
// 下载可执行文件到目标芯片
"type": "shell",
"label": "download",
"command": "openocd",
"args": [
"-f",
"../stlink-dap.cfg", // 仿真器配置文件路径
"-f",
"../stm32f1x.cfg", // 目标芯片配置文件路径
"-c",
"init",
"-c",
"halt",
"-c",
"program app.bin 0x8000000", // 下载可执行文件到目标芯片的起始地址
"-c",
"reset",
"-c",
"shutdown"
],
"group": "build",
"dependsOn": "make",
"problemMatcher": []
}
]
}添加调试器配置
launch.json 是仿真时的配置文件,指定了调试器型号、目标芯片的型号及寄存器地址描述。
该文件只对仿真有影响,对编译、镜像输出、程序下载无影响。
参照以下路径及内容完成添加
project# 工程根目录
stlink-dap.cfg# 仿真器配置文件
stm32f1x.cfg# 目标芯片配置文件
STM32F103xx_FLASH.ld# 链接脚本文件
STM32F103xx.svd# 目标芯片寄存器
stm32f10x_conf.h# 标准外设库配置文件
CMSIS# 架构库目录
…
STM32F10x_StdPeriph_Driver# 标准外设库目录
…
build# 空目录、编译镜像输出
…
.vscode# vscode配置目录
c_cpp_properties.json# C/C++配置文件
tasks.json# 任务配置文件
launch.json# 调试仿真配置文件
main.c# LED点亮示例代码
CMakeLists.txt# CMAKE编译配置文件
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug STM32",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/build/app.elf", // 可执行文件路径
"request": "launch",
"type": "cortex-debug", // 调试类型
"runToEntryPoint": "main", // 运行到入口点
// "runToEntryPoint": "SystemInit",
"servertype": "openocd", // 调试服务器类型
"configFiles": [
"${workspaceFolder}/stlink-dap.cfg", // 仿真器配置文件路径
"${workspaceFolder}/stm32f1x.cfg", // 目标芯片配置文件路径
],
// "showDevDebugOutput": "raw", // 显示调试输出
"svdFile": "${workspaceFolder}/STM32F103xx.svd", // 寄存器描述文件路径
"preLaunchTask": "make"
}
]
}编译、仿真、下载
参考VSCode环境搭建 测试章节
常见问题
core_cm3.c.obj Error 1
错误日志如下:
C:\Users\user\AppData\Local\Temp\cc8pmURd.s: Assembler messages:
C:\Users\user\AppData\Local\Temp\cc8pmURd.s:599: Error: registers may not be the same -- `strexb r0,r0,[r1]'
C:\Users\user\AppData\Local\Temp\cc8pmURd.s:629: Error: registers may not be the same -- `strexh r0,r0,[r1]'
make[2]: *** [CMakeFiles\app.elf.dir\build.make:106: CMakeFiles/app.elf.dir/CMSIS/CM3/CoreSupport/core_cm3.c.obj] Error 1
make[1]: *** [CMakeFiles\Makefile2:86: CMakeFiles/app.elf.dir/all] Error 2
make: *** [Makefile:90: all] Error 2原因分析:
gcc version 10.3.1 和 旧版 CMSIS 之间的兼容性问题:
GCC 10+ 对寄存器分配更激进,容易将 strexb/strexh 的输入输出分配到同一寄存器
旧版 CMSIS 的内联汇编约束不够严格(缺少 & earlyclobber 修饰符)
/**
* @brief STR Exclusive (8 bit)
*
* @param value value to store
* @param *addr address pointer
* @return successful / failed
*
* Exclusive STR command for 8 bit values
*/
uint32_t __STREXB(uint8_t value, uint8_t *addr)
{
uint32_t result=0;
// __ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
__ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
return(result);
}
/**
* @brief STR Exclusive (16 bit)
*
* @param value value to store
* @param *addr address pointer
* @return successful / failed
*
* Exclusive STR command for 16 bit values
*/
uint32_t __STREXH(uint16_t value, uint16_t *addr)
{
uint32_t result=0;
// __ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
return(result);
}中文路径
项目目录不能包含中文,会出现引用不到的问题如下:
* 正在执行任务: cmake -G 'MinGW Makefiles' ..
-- The C compiler identification is GNU 16.1.0
-- The CXX compiler identification is GNU 16.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: C:/Program Files/mingw64/bin/cc.exe
-- Check for working C compiler: C:/Program Files/mingw64/bin/cc.exe - broken'rm' 不是内部或外部命令
报错内容如下:
* 终端将被任务重用,按任意键关闭。
* 正在执行任务: rm * -r
'rm' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
* 终端进程“C:\Windows\System32\cmd.exe /d /c rm * -r”启动失败(退出代码: 1)。原因: VSCODE终端适配了pnpm等环境,添加了额外的参数造成冲突。
"command": "rm * -r",
"command": "cmd /c if exist * (del /f /s /q * >nul 2>&1) else (echo build folder is empty)",