如何在 VScode 创建 stm32 项目?
一、参考来源
VSCode开发STM32快速搭建开发环境零基础教程!哔哩哔哩bilibili
上面的链接是主要参考的来源。
二、工具链
本次使用的工作有
arm-none-eabi-gcc
来作为编译器;pyocd
作为烧写器;vscode
作为编辑器;vscode 的插件
cortex-debug
作为调试工具;STM32cubeMX
作为模板的生成;make
作为构建工具。
三、VScode 的相关插件
C\C++
插件:作为 C 语言的主要插件。
Cortex-debug
插件:作为调试的插件。
四、配置过程
4.1 使用 stm32cubeMX
生成模板
使用 stm32cubeMX 的目的是使用其生成的 makefile 文件,嘻嘻。因为其他的不会用,现不深究。但有一点要注意, stm32cubeMX 使用的是 stm 公司新推出的 hal 库 ,而当前项目使用的却是其另一种推出的 stm32标准库。因此,在后面的演示,我会把除 makefile 外的文件均删除。。。
现演示的是怎生成模板:
打开 stm32cubeMX ,点击 ACCESS TO MCU SELECTOR 。
使用英文输入法输入你想要的芯片型号。
并在右侧的列表中选择芯片,注意其封装。
其他配置不在当前演示的重点,日后学到,再作重视。
这里的重点是 (4) 。我们选择 makefile 。而toolchain folder location的话,我未设置,好像也行,因为我把 arm-none-eabi-gcc 已经加载到环境变量了。
上图,就是生成的目录。我把其他文件都删去,只保留 Makefile (好像有点傻傻的样子,哈哈,T^T)。
其中包括 .s 文件和 .ld 文件 ,因为我还未测试过,所以在演示中,我选择用回固件库里的。
4.2 搭建以固件库为基础的项目架构
项目的基本目录
其中我定义了
Driver 放 stm32 标准库的内容
src 放自己写的业务代码
Makefile 构建工具
上图为 Driver 目录下的结构,其中
- CMSIS 放 core 代码,对应标准库里的
即,
- FWLB 放的是外设的文件,直接把标准库里的 inc 目录和 src 目录复制过来就行,标准库里的如下图,
- LINK_SCRIPTS 选择的是
即,project -> template -> TrueSTUDIO -> STM3210E-EVAL -> stm32_flash.ld。此目录放的是链接脚本。STM公司已经帮我们为不同的编译工具和不同芯片类型写了一个模板。
其中 TrueSTUDIO 适用于 gcc 工具。 stm3210e 里放的是大容量的,而其他的区别,日后再作研究。
- STARTUP 放的是启动文件。
同样,我们选择 TrueSTUDIO 里提供的模板,好像 gcc-ride7 里的也行,未测试过。
最后,还要把一些中断之类的文件从模板中复制过来。
请注意,systme_stm32f10x.c 就不要复制了,因为在上面中已经有复制到其他地方了。不然在链接阶段会报 重复定义
这样,我们的基本项目架构就完成了。
4.3 在 vscode
里构建智能提示
在 vscode 使用快捷键 Ctrl+Shift+P
。键入 C/C++
,选择 C/C++: Edit Configurations(UI)
把编译器改为 gcc
, 而 IntelliSense 改为 windows-gcc-arm
。
这里的作用是为了在智能提示里的 uint32_t
不报错。
当你有其他库的头文件不在当前项目里,请在这里增加路径。不过一般不用修改,但在插件 keil assistent
里就有这样的应用。
添加相应的宏。这很重要,在 stm32cubeMX 里和 stm32 固件库 里的有不同,请注意。
在这里,我们会增加两个
USE_STDPERIPH_DRIVER 表明我们使用的是标准固件库
STM32F10X_HD 表明我们的芯片是 F1 系列的大容量产品
另外,加一些补充
__CC_ARM 若使用 keil assistent 插件导入 keil 项目时,就要加入这个才能使
uint32_t
不会报错同时,其头文件也要包含 ARMCC 的 include 和 include/rw 目录。
不过插件会做好配置,不用我们操心 。
4.4 修改 makefile
,搭建 task
在 main.c 文件里键入测试代码
#include "stm32f10x.h"
void GPIO_config(void);
void LED_on(void);
void LED_off(void);
void delay(uint32_t i);
int main(void) {
GPIO_config();
while (1) {
LED_off();
delay(0x0FFFFF);
LED_on();
delay(0x0FFFFF);
}
return 0;
}
void GPIO_config(void) {
GPIO_InitTypeDef GPIO_init_args;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_init_args.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_init_args.GPIO_Pin = GPIO_Pin_1;
GPIO_init_args.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_init_args);
}
void LED_on(void) {
GPIO_ResetBits(GPIOB, GPIO_Pin_1);
}
void LED_off(void) {
GPIO_SetBits(GPIOB, GPIO_Pin_1);
}
void delay(volatile uint32_t i) {
while (i--);
}
然后,我们还要修改 makefile 里的内容。
TAGET
生成的目标名称C_SOURCE
C/C++ 文件,例
######################################
# source
######################################
# C sources
C_SOURCES += $(wildcard Driver/CMSIS/*.c)
C_SOURCES += $(wildcard Driver/FWLB/src/*.c)
C_SOURCES += $(wildcard src/*.c)
-
ASM_SOURCE
启动文件或汇编文件,例# ASM sources ASM_SOURCES = Driver/STARTUP/startup_stm32f10x_hd.s
LDSCRIPT
链接脚本,例
#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = Driver/LINK_SCRIPTS/stm32_flash.ld
-
C_INCLUDE
C/C++ 的头文件搜索目录,例
# C includes
C_INCLUDES = \
-Isrc \
-IDriver/CMSIS \
-IDriver/FWLB/inc
-
C_DEFS
一些配置用的宏定义,一般用来指定开启某些功能用的,例
# C defines
C_DEFS = \
-DUSE_STDPERIPH_DRIVER \ # 不定义的话,FWLB的内容不会被包含
-DSTM32F10X_HD # 定义设备
4.5 构建编译任务
构建 tasks
。菜单中选择 Terminal --> Configure Tasks... --> 选择 gcc.exe 生成(其实,哪个都行,反正都要改)。然后把 tasks.json 化简,并把部分信息整理下。下面是我的例子,
{
"version": "2.0.0",
"tasks": [
{
"type": "shell", // 不知是有何用的,我仿别人的
"label": "build", // 这会在 Ctrl+Shift+B 时显示
"command": "make", // 这是运行的程序
"args": [ // 例如 > make
]
"group": "build", // 这个好像很重要,其与下一组 tasks 一样才能做选择
}
]
}
然后选择 Ctrl+Shift+B ,因为只有一个任务,故 vscode 自动运行了。
但是,运行了一会儿,就出现报错,
C:\Users\11207\AppData\Local\Temp\cczTFbui.s: Assembler messages:
C:\Users\11207\AppData\Local\Temp\cczTFbui.s:599: Error: registers may not be the same -- `strexb r0,r0,[r1]'
C:\Users\11207\AppData\Local\Temp\cczTFbui.s:629: Error: registers may not be the same -- `strexh r0,r0,[r1]'
make: *** [Makefile:141: build/core_cm3.o] Error 1
解决方法,参考自 (20条消息) VS Code + GCC 搭建 STM32 开发环境qq_32166451的博客-CSDN博客vs开发stm环境
问题出在标准固件库里,这里的汇编与 gcc 的不一致,故要修改文件 core_cm3.c。
在文件 core_cm3.c 里搜索 strexb 和 strexh ,把两行语句里的 =r
修改成 =&r
。
保存后,可再尝试。最后编译成功会得出下面类型的语句
arm-none-eabi-size build/stm_gcc.elf
text data bss dec hex filename
1376 8 540 1924 784 build/stm_gcc.elf
arm-none-eabi-objcopy -O ihex build/stm_gcc.elf build/stm_gcc.hex
arm-none-eabi-objcopy -O binary -S build/stm_gcc.elf build/stm_gcc.bin
4.6 烧录程序
烧录的程序,我们使用的是 pyocd 。其可以通过 pip install pyocd
来安装。可参考 玩转 pyocd - 哈拎 - 博客园 (cnblogs.com)。
我记录一些基本应用。
> > pyocd list
# Probe Unique ID
--------------------------------------------------
0 Keil Software Fire CMSIS-DAP HS-00012048
当你连接上仿真器后,使用此命令就可以读出其类型。
其与 keil MDK 一样,其有些芯片不在自身的库内,可以使用命令下载 ,但很慢 。庆幸的是,也可以其与 keil 芯片包通用。
我把从野火论坛下载的包放出来。因为我的芯片是 stm32f103ve6 ,所以我选择了 F1xx 的包。
从其文档里得到一信息,包导入的方式可以是在命令行里以额外参数的方式,也可以在项目里键入配置信息。我这使用第二种方法。
创建 pyocd.yaml 文件
pack:
- Keil.STM32F1xx_DFP.2.4.0.pack
注: - keil... 是指其路径。
然后使用 pyocd list -t
, -t
即是 --taget
。可以行一些信息,
> > pyocd list -t
......
stm32f103rb STMicroelectronics STM32F103RB STM32F1 Series, STM32F103 pack
stm32f103rc STMicroelectronics STM32F103RC builtin
stm32f103rd STMicroelectronics STM32F103RD STM32F1 Series, STM32F103 pack
stm32f103re STMicroelectronics STM32F103RE STM32F1 Series, STM32F103 pack
stm32f103rf STMicroelectronics STM32F103RF STM32F1 Series, STM32F103 pack
stm32f103rg STMicroelectronics STM32F103RG STM32F1 Series, STM32F103 pack
stm32f103t4 STMicroelectronics STM32F103T4 STM32F1 Series, STM32F103 pack
stm32f103t6 STMicroelectronics STM32F103T6 STM32F1 Series, STM32F103 pack
......
这里说明,当前环境下,存在了 F10x 的芯片了。
然后就是配置烧录任务。在 tasks.json 里键入
{
"tasks": [
{
...
},
{
"type": "shell",
"label": "update",
"command": "pyocd",
"args": [
"load", // 烧录命令
"-t", // 选择目标芯片
"stm32f103ve", // 芯片型号
"./build/test2.elf" // 下载文件,可以是 elf, hex, bin。其中 bin 文件
// File to write to memory. Binary files can have an optional base address appended to the file name as '@<address>', for instance 'app.bin@0x20000'.
],
"group": "build",
}
]
}
当然还有其他功能,日后再细看。
4.7 调试程序
点击左侧面板的调试,选择创建 launch.json 文件
然后选择 GDB 那一行。
点击右下角的 add configuration... 选择 cortext-debug: PyOcd
。
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"cwd": "${workspaceFolder}",
"executable": "./build/stm_gcc.elf", // 修改成相应的 elf 路径
"name": "Debug with PyOCD",
"request": "launch",
"type": "cortex-debug",
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"servertype": "pyocd"
/* 重点 */
"targetId": "stm32f103ve", // 芯片型号
"cmsisPack": "Keil.STM32F1xx_DFP.2.4.0.pack" // 包路径
}
]
}
配置完,就能像平时那样调试了。