使用 VSCode 开发调试 STM32 单片机尝试


本文记录基于 Windows + DAP-Link 开发 STM32F103C8T6 的实践过程,其他操作系统或芯片应该也只是大同小异的问题。

注意:工作空间中千万不要出现中文目录和空格!



一、环境准备

硬件环境就是 STM32F103C8T6 核心板和 DAP 调试器,复杂的主要在软件部分。

调试时需要让gdb链接openocd,因此需要telnet工具。Windows下直接在Windows功能里打开telent client并重启就行

1.1_软件

  1. VSCode

    可以使用普通版或便携版,我使用的是大佬制作的便携版:https://portapps.io/app/vscode-portable/

  2. STM32CubeMX

    用来生成 Markfile 工程,已有工程模板的话不必须安装。使用 CubeMX 时需要用到 Java , Java 64位下载地址:https://java.com/en/download/manual.jsp

  3. GNU Arm Embedded Toolchain

    ARM 的 GUN 工具链,下载地址:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads

    安装完成后需要添加到环境变量,使用命令 arm-none-eabi-gcc -v 测试。

  4. OpenOCD

    下载调试用的工具,已编译好的Windows平台可用二进制文件下载地址: https://gnutoolchains.com/arm-eabi/openocd/

    同样安装完成后需要添加到环境变量,使用命令 openocd -v 测试。

  5. make

    下载地址:http://gnuwin32.sourceforge.net/packages/make.htm

    同上,环境变量,make -v

  • 添加环境变量

    因为所有个工具都放在了同一个目录下,所以我喜欢这么加环境变量,环境变量添加完后需要点击所有的“确定”然后重启命令窗口才生效。

    如果出现配置完环境变量 VSCode 中的终端识别不到的情况重启电脑可以解决。

1.2_VSCode-插件

  1. C/C++
实时语法检查。
  1. ARM

    ARM的汇编语法高亮

  2. Cortex-Debug

MCU的调试核心,比 VSCode 默认的调试界面强大很多。为了更好的使用这个工具进行调试我们还需要对应单片机的 .svd 文件,这个文件定义了某个芯片的非常详细的信息,包含了哪些片内外设、每一个外设的硬件寄存器、每一个寄存器中每一个数据位的值以及详细的说明信息等等。svd 文件可以在单片机的固件库原包里找到,也可以去其他地方下载,这里推荐一个地方:<https://github.com/posborne/cmsis-svd/tree/master/data>

二、用CubeMX新建Makefile工程

CubeMX 的下载和安装就不多说了,注意运行它需要 java ,而且网络不好的情况还需要挂代理。

2.1_添加软件包

启动 CubeMX 后点击 "Help" -> "Manage embedded software packages" 可以进入软件包管理页(快捷键Alt+U)。进入后根据需要安装相应型号的软件包即可。

2.2_创建工程

  1. 点击软件首页的 ACCESS TO MCU SELECTOR 进入MCU选择器选择一个芯片,然后软件会跳到工程配置界面。

  2. 配置RCC. 时钟是必须要配置的,先在 Pinout&onfiguration 里配置时钟源引脚,然后去 Clock Configuration 中配置时钟树。配置时钟树时先选择好时钟源输入,然后在 HCLK(MHz) 中输入需要的频率并回车软件就会自动配置后面的部分。

  3. 选择调试模式和基础时钟源。在 Pinout&onfiguration -> SYS -> Debug 中选择 Serial Wire,时钟源同样在 SYS 标签下,选择默认的 SysTick 即可。

  4. 初始化一个连接 LED 的 GPIO 口。

2.3_生成工程

  1. 进入 Project Manager 选项卡,依次填入工程名称、工程路径、Toolchain选择Makefile.

  2. 点击 GENERAATE CODE 即可在指定路径生成工程。


三、VSCode_写代码和编译

3.1_编译和下载

将 CubeMX 生成的工程文件夹拖入到 VSCode 中打开,这时候如果不出意外的话在 VSCode 的终端中输入 make 就可以成功的编译你的工程了(前提是正确安装了 "GNU Arm Embedded Toolchain" 和 "make" 并配置了环境变量)。

程序编译完成就可以得到 hex 文件了,想要把这个文件下载进单片机有一百种办法,你可以在 J-Flash、OpenOCD、pyOCD 等工具中选择一个你喜欢的。

3.2_vscode的配置文件

通过上面的介绍已经可以对工程进行编译和下载了,但是仍有很多不足。比如工程文件中会有一大堆画波浪线的错误(前提是安装了C/C++插件)、工程的编译下载过程很繁琐等,因此我们还需要进一步配置些东西。

vscode的配置文件是放在与 .vscode 这个文件夹下的,如果 VSCode 未自动创建的话我们就需要手动创建,它在工程的根目录下

  1. c_cpp_properties.json

    • .vscode 目录下建立 c_cpp_properties.json 文件,需要用这个文件记录头文件的包含路径和全局宏定义。具体要哪些路径和哪些宏定义可以去 Makefile 目录下的 C_INCLUDESC_DEFS 找。
    • 不过只把那几项添加进来还是不够的,有些用到的头文件 CubeMX 生成的工程里并没有携带,这些C语言的标准库头文件是需要在 arm-none-eabi-gcc 的安装路径里找的。至于怎么找当然是有技巧的,在命令行里输 echo 'main(){}' | arm-none-eabi-cpp -E -v -(CMD) 就可以看到 arm-none-eabi-cpp 默认的头文件和库文件路径了,把它们添加进去。
    • 但是当你把这几个头文件加进去你会发现还是会报错,多半是什么 uint32_t 未定义之类的。这是因为 GNU-ARM 的 stdint.h 会向下钻取并生成 stdint-gcc.h ,后者依赖于一个宏,同时它也依赖其他宏才能到达那里,但是由于这些宏我们未定义所以会报错。解决这个问题的办法就是手动定义那些宏,使用 arm-none-eabi-gcc -dM -E - < nul(CMD) 可以查看 arm-gcc 的内置宏定义,查出来结果可能有几百条,不过不要在乎那些,把这些全添加进去报错就会消失了,(在添加的时候只保留第一个空格前边的内容,这点小事让Excel干就好了)。
    • 如果还是提示有问题那多半是 VSCode 的问题,重启一下试试(打开命令窗口输 ">reload windw")。
    • (PS.额外添加的这点东西只是为了告诉vscode我们有哪些东西,并不会影响gcc的编译(毕竟我们添加的都是gcc默认包含的),更不要在Markfile文件中同步修改)

    {
    "configurations": [
    {
    "name": "Win32",
    "includePath": [
    "${workspaceFolder}/**",
    "c:/42hdst/software/hardware/gcc-arm-none-eabi/9.2.1/bin/../lib/gcc/arm-none-eabi/9.2.1/include",
    "c:/42hdst/software/hardware/gcc-arm-none-eabi/9.2.1/bin/../lib/gcc/arm-none-eabi/9.2.1/include-fixed",
    "c:/42hdst/software/hardware/gcc-arm-none-eabi/9.2.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include",
    "${workspaceFolder}/Inc/*",
    "${workspaceFolder}/Drivers/STM32F1xx_HAL_Driver/Inc/*",
    "${workspaceFolder}/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy/*",
    "${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32F1xx/Include/*",
    "${workspaceFolder}/Drivers/CMSIS/Include/*"
    ],
    "defines": [
    "_DEBUG",
    "UNICODE",
    "_UNICODE",
    "USE_HAL_DRIVER",
    "STM32F103xB",
    "__DBL_MIN_EXP__",
    "__HQ_FBIT__",
    ......
    ......
    ......
    "__ATOMIC_RELEASE"
    ],
    "intelliSenseMode": "msvc-x64"
    }
    ],
    "version": 4
    }
  2. tasks.json 和 launch.json

    至此用 VSCode 愉快的写代码就已经没有问题了,剩下的就是调试方面的工作了。这两个文件分别是任务和调试用的,用VSCode调试代码痛快不痛快方便不方便就全看这两个文件的水平高低了,想要写得好就得有个好老师,先观摩观摩 github 上的一个项目:


四、Github项目——VS-Code-STM32-IDE

  • 项目地址:https://github.com/damogranlabs/VS-Code-STM32-IDE
  • This project transform VS Code to a great IDE that can be used with STM32CubeMX tool to create a projects without any limitations and code size restrictions, without any bloatware and fast user setup (once all prerequisites are installed). Project is based on python scripts and is therefore fully customizable. OpenOCD tool and Cortex-Debug VS Code plugin is used for debug purposes.

4.1_环境准备

使用这个工具必须要用的除了上面提到的 arm-gcc、make、openocd 三个软件和 C/C++、ARM、Cortex-Debug 三个插件外还需要用到 Python 和 VSCode 中的 Python 插件。

4.2_使用方法

  1. 准备安装好所有的工具和软件。arm-gcc、make、openocd 三个工具怎么用自己定吧,可以配置好环境变量也可以按他说的解压到推荐目录%userprofile%\ AppData \ Roaming \ GNU MCU Eclipse中。

  2. 需要有一个用 CubeMX 生成的 Makefile 工程,工程从哪来前面说过了。

  3. 将从 GitHub 上下载到的 "ideScipts" 文件夹复制到工程目录下。

  4. 使用 VSCode 打开工程文件夹,然后用 python 运行 update.py 脚本,按提示操作(如果他的 python 脚本有什么语法错误的话不用理他,超纲了。能用就行):

    • 第一次运行不成功,说需要 .code-workspace 文件,所以在工程的根目录下给它建一个。

    • 正式运行 update.py 脚本,这次运行应该就不会报错了,按它的步骤走就行了:

      # 因为我的 arm-gcc 添加到了环境变量,所以它能检测到,不废话当然 yes.
      Default path to 'arm-none-eabi-gcc executable (arm-none-eabi-gcc.exe)' detected at 'C:\42HDST\Software\Hardware\gcc-arm-none-eabi\9.2.1\bin\arm-none-eabi-gcc.EXE'
      Use this path? [y/n]: y # 确认 make 的路径,还是yes.
      Default path to 'make executable (make.exe)' detected at 'C:\42HDST\Software\Hardware\make\3.8.1\bin\make.EXE'
      Use this path? [y/n]: y # 确认 openocd 的路径,还是yes.
      Default path to 'OpenOCD executable (openocd.exe)' detected at 'C:\42HDST\Software\Hardware\OpenOCD\0.10.0\bin\openocd.EXE'
      Use this path? [y/n]: y # 调试器配置文件的路径
      Enter path or command for 'OpenOCD ST Link interface path ('stlink.cfg')':
      Paste here and press Enter: C:\42HDST\Software\Hardware\OpenOCD\0.10.0\share\openocd\scripts\interface\cmsis-dap.cfg WARNING: Exception error overwriting 'toolsPaths.json' file:
      [Errno 2] No such file or directory: 'C:/Users/luhua/AppData/Roaming/Code/User/toolsPaths.json' # 芯片配置文件的路径
      Enter path(s) to OpenOCD configuration file(s):
      Example: 'target/stm32f0x.cfg'. Absolute or relative to OpenOCD /scripts/ folder.
      If more than one file is needed, separate with comma.
      Paste here and press Enter: C:\42HDST\Software\Hardware\OpenOCD\0.10.0\share\openocd\scripts\target\stm32f1x.cfg # svd文件路径
      Enter path or command for 'stm32SvdPath':
      Paste here and press Enter: ./STM32F103xx.svd
  5. 脚本运行完之后能会有些报错,但是无伤大雅,现在我们绝对可以用它生成的文件下载和调试工程了。即便不直接用它生成的东西对我们自己写配置文件也是很有参考价值的


五、自定义配置文件

已经有了一个好老师,接下来我们尝试自己写任务和调试的配置文件吧,这看起来很简单。

5.1_任务文件

任务文件 tasks.json ,有了任务这个东西我们就可以一键让系统自动执行好几条指令了,不用再一条一条敲。要实现 STM32 的基本开发我们总要最少设置这么几个任务——编译、下载并复位、编译且下载并复位。

  1. 编译工程,Build project. 参考参考大佬的代码,然后修修补补就成了。

    /* !!! json 文件中不能有注释,复制代码时一定要删除干净 !!! */
    {
    /* 标签 */
    "label": "Build project",
    /* build 组里边默认执行的任务,就是按 Ctrl+Shift+B 肯定执行它 */
    "group": {
    "kind": "build",
    "isDefault": true
    },
    /* 命令和参数,这里用的是绝对路径,如果配置好了环境变量也可以不写路劲。"args" 里是参数,可以写多个 */
    "type": "shell",
    "command": "C:/42HDST/Software/Hardware/make/3.8.1/bin/make.EXE",
    "args": [
    "GCC_PATH=C:/42HDST/Software/Hardware/gcc-arm-none-eabi/9.2.1/bin",
    /* -j4 是说使用四个CPU线程编译,我的CPU只有4个线程,四舍五入就是满载了 */
    "-j4"
    ],
    /* 这一块的意思是如果在运行任务时终端出现了 "Warning"、"error" 等等东西就把他们显示到问题面板上,详见图 */
    "problemMatcher": {
    "pattern": {
    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
    "file": 1,
    "line": 2,
    "column": 3,
    "severity": 4,
    "message": 5
    }
    },
    "presentation": {
    /* 使用这句话获取控制面板焦点,也就是说这个任务执行完焦点自动跑到终端输出哪里 */
    "focus": true
    }
    }

  2. 编译下载并复位,CPU: Build, Download and run

    {
    /* !!! json 文件中不能有注释,复制代码时一定要删除干净 !!! */
    "label": "CPU: Build, Download and run",
    "type": "shell",
    /* 这次使用的是相对路径,LHardware是我配置的一个环境变量,LHardware=C:/42HDST/Software/Hardware */
    "command": "${env:LHardware}/OpenOCD/0.10.0/bin/openocd.EXE",
    "args": [
    /* 这三个文件一定要找对,调试器配置文件、芯片配置文件和编译生成的 .elf 文件 */
    "-f",
    "${env:LHardware}/OpenOCD/0.10.0/share/openocd/scripts/interface/cmsis-dap.cfg",
    "-f",
    "${env:LHardware}/OpenOCD/0.10.0/share/openocd/scripts/target/stm32f1x.cfg",
    "-c",
    "program build/STM32F103C8Tx.elf verify reset exit"
    ],
    "problemMatcher": [],
    /* 这个任务依赖于另一个任务 */
    "dependsOn": "Build project"
    }

5.2_调试文件

  1. 有了 "Build Project" 任务我们就可以写调试文件 launch.json 了,因为调试之前总需要重新下载代码吧。

  2. 要想好好调试先得有个好工具,所以再次强调一下 "Cortex-Debug" 插件和对应芯片的 .svd 文件。

    {
    /* !!! json 文件中不能有注释,复制代码时一定要删除干净 !!! */
    "name": "Cortex debug",
    "type": "cortex-debug",
    "request": "launch",
    /* 调试器选择,很重要 */
    "servertype": "openocd",
    /* 输出路径 */
    "cwd": "${workspaceFolder}",
    /* elf 文件的路径,调试用的 */
    "executable": "build/STM32F103C8Tx.elf",
    /* svd 文件路径 */
    "svdFile": "./STM32F103xx.svd",
    /* 下面这两个是调试器和芯片的配置文件 */
    "configFiles": [
    "${env:LHardware}/OpenOCD/0.10.0/share/openocd/scripts/interface/cmsis-dap.cfg",
    "${env:LHardware}/OpenOCD/0.10.0/share/openocd/scripts/target/stm32f1x.cfg"
    ],
    /* 依赖于 "Build project" 任务 */
    "preLaunchTask": "Build project"
    }

P、重要补充

  1. 进一步解决 C/C++ 插件的报错

      经过之前的一通操作,又是加 include 路径又是加 define 的,基本已经可以达到 C/C++ 插件在用户代码的文件里面不报错了。但是仍有意外,我们不可能只在用户代码里呆着而是经常需要进到库函数里面看看,但是这个时候报错就又来了,比如在 stm32f1xx_hal_gpio.c 中就会疯狂报错,虽然知道这并不影响什么,在 keil 里边库函数还有几个报错呢,但是就是很不痛快。

      不过好在功夫不负有心人,这个问题的终极解决方案终于被我给找到了,我们只需要在 c_cpp_properties.json 文件中略微调一个值就可以。打开 c_cpp_properties.json 翻到最后应该能找到这么一句话 "intelliSenseMode": "msvc-x64" 这是什么意思?这是说智能感应模式是msvc-x64,搜搜msvc是什么鬼吧——MSVC是指微软的VC编译器!淦,我们明明用的是 GCC 吧!坑人呢。所以直接把这个 "msvc-x64" 改成 "gcc-x86" 莫名其妙的问题就不会再出现了,如果不放心可以建个标签把 gcc 的路径写进去。(这里之所以改成 "gcc-x86" 是因为不能选 "gcc-arm" )

  2. 关于 GCC 编译生成的 bin 文件太大的问题

    GCC 编译生成的文件是大,虽然我们用的是 GNU Arm Embedded Toolchain, 但编译出来的文件依然很大。一个基础的配置了 LED 灯的代码 Keil 编译出来只有 5k 而 GCC 编译出来的却有 29k ,优化调到 OPT = -Os 也没什么效果。关于这个问题我想说的有以下几点:

    1. 避免使用 printf() 等 C 语言标准库函数可以大幅减小 bin 文件的体积。
    2. 在 Makefile 中不使用 -u _printf_float-u _scanf_float 参数可以大幅减小 bin 文件的体积,只是这样 C 标准库中浮点数和字符串互转的功能就不起作用了。
    3. 删掉没有使用的函数也能缩小 bin 文件大小,但是有点麻烦。
    4. GCC 编译出来的文件虽然大,但它和 Keil 编译出的文件关系也只是加法不是乘法,因为在 LED 和 Printf 的基础工程上再加上 FreeRTOS 编译出来的 bin 文件大小是 34k 较之前只增了 5k ;同样在此基础上加上 FreeRTOS 后 Keil 编译出来的 bin 文件是 13k ,较之前增加了 8k ,这样看 GCC 就没有那么可恶了。
    5. 如果使用了 OS 的话,那几乎可以肯定它是一定使用了 C 标准库的函数了,所以。。。
    6. 想来在单片机领域 VSCode 和 GCC 算是高级玩家的奢侈玩法,因此那种对于 Flash 只有几 KB 甚至不到 1KB 的芯片还是乖乖用 Keil 吧。虽然用盗版软件不好,但是我们是学习用途嘛。

参考资料


使用 VSCode 开发调试 STM32 单片机尝试的更多相关文章

  1. 使用vscode开发调试.net core应用程序并部署到Linux跨平台

    使用VS Code开发 调试.NET Core RC2应用程序,由于.NET Core 目前还处于预览版. 本文使用微软提供的示例进行开发及调试. https://github.com/aspnet/ ...

  2. 玩转VSCode-完整构建VSCode开发调试环境

    随着VSCode的不断完善和强大,是时候将部分开发迁移到VS Code中了. 目前使用VS2019开发.NET Core应用,一直有一个想法,在VS Code中复刻VS的开发环境,同时迁移到VS Co ...

  3. 使用Vscode 开发调试 C/C++ 项目

    需要安装的扩展 C/C++ 如果是远程 Linux上开发还需要安装 Remote Development 创建工作目录后,代码远程克隆... 省略.. 创建项目配置文件,主要的作用是代码智能提示,错误 ...

  4. Linux下开发STM32单片机

    一开始学习51单片机就是用的MDK这个IDE软件,IDE软件虽然看起来直观好像更加容易入门(因为有界面看起来很形象),但是实际上IDE却是向我们这些入门人员隐藏了背后真实存在的过程,让我们以为编译就是 ...

  5. 使用vscode Container开发调试envoy

    由于我最近在研究 envoy 这个项目,这是个cpp的项目,对于我这种cpp新人来说还是比较有压力的,感觉处处都是坑,开个引导文章记录一下. 如果要研究 envoy 项目源码,那肯定是需要代码跳转的, ...

  6. STM32单片机应用与全案例实践 /stm32自学笔记 第二版 pdf

    STM32单片机应用与全案例实践pdf https://pan.baidu.com/s/16WrivuLcHvLTwS__Zcwl6Q 4rj3 stm32自学笔记 第二版 pdf https://p ...

  7. 为vscode开发一款svn右键菜单扩展

    在我平时的工作中会经常用到svn blame这个命令,但是vscode现有的svn扩展普遍都不能自定义右键菜单. 所以我产生一个想法:自己动手为vscode开发一款svn的扩展来定制右键菜单,本文记录 ...

  8. envoy开发调试环境搭建

    image 前段时间研究envoy的filter开发,在windows机器环境上面折腾了会,这里记录一下,希望能够帮助到大家少走一些坑 主要是使用vscode devContainer的方式来搭建开发 ...

  9. 使用VS Code从零开始开发调试.NET Core 1.0

    使用VS Code 从零开始开发调试.NET Core 1.0. .NET Core 是一个开源的.跨平台的 .NET 实现. VS Code 全称是 Visual Studio Code,Visua ...

随机推荐

  1. Share Keyboard, Mouse and Clipboard between Multiple Computers

    Synergy version: 1.4.12 Server Download and install synergy-1.4.12-Linux-i686.deb on Mint 14; Run it ...

  2. SpringBoot开发一

    项目介绍 牛客高级项目课,主要是完成牛客网的讨论社区的搭建.项目在github上. 涉及到的技术架构: Spring,SpringBoot,SpringMVC,MyBatis,Redis,Kafka( ...

  3. iOS开发之Lame编译

    前言 为了保证音频格式在多端通用,需要将音频转化为MP3格式,本文讲解了如何使用Shell脚本来编译lame库. 编译脚本 #!/bin/sh CONFIGURE_FLAGS="--disa ...

  4. SSH以及ROS远程登录设置保姆级教程

    本文用来实现在同一局域网内的两台计算机之间的相互通信,实现一台计算机登录到另一台计算机,本文基于SSH来实现. 1.SSH简介 Secure Shell(SSH)是由 IETF(The Interne ...

  5. mybaits进阶01

    在以上mybait入门的改进(增加了接口让增删改查 后期跟容易) 注意:主配置文件和映射配置文件内容不变,但是映射文件要和对应接口放于同目录下并且名称必须相同 一.接口创建 public interf ...

  6. Centos7 出现Welcome to emergency mode!【紧急模式】

    Centos7 出现Welcome to emergency mode![紧急模式] 做mount挂载时,修改了  /etc/fstab 文件,导致Centos7重启时出现如下图所示错误:   输入r ...

  7. HBuilder mui 手机app开发 Android手机app开发 ios手机app开发

    经过一段时间的学习,做公司项目,对mui框架有了更加深入完整的了解,其实刚开始接触HBuilder中的mui框架只是简单的了解,并没有深入的研究,后来由于工作的需求,不得不深入研究,并运用的项目中去. ...

  8. js 遍历数组对象求和

    这个通常是求多个商品的总价遇到的情形: [ 0: {id: 1, name: "服务费", price: "1.00"} 1: {id: 2, name: &q ...

  9. .Net Core NPOI读取Excel 并转为数据实体类

    创建应用程序 这里直接创建Console程序 引用NPOI的NuGet包 PM> Install-Package NPOI -Version 2.5.1 直接Nuget包管理器添加 导入Exce ...

  10. 【spring 注解驱动开发】spring组件注册

    尚学堂spring 注解驱动开发学习笔记之 - 组件注册 组件注册 1.@Configuration&@Bean给容器中注册组件 2.@ComponentScan-自动扫描组件&指定扫 ...