vscode + PlatformIO嵌入式芯片开发环境搭建

背景

谈到嵌入式开发,当然离不开STM32;谈到STM32开发当然离不开Keil MDK,目前几乎所有的STM32教程的项目就是基于Keil这个开发工具,尽管Keil非常稳定、使用率也非常高,但是不可否认的是作为一款老牌嵌入式开发IDE,Keil已经太老了。

如果说古老的UI界面只是难以操作,可以让人勉强接受,那以GB 2313为编码方式实现中文显示,完完全全体现出这个IDE是上个时代的产物了。

为了尝试使用更优雅的解决方案,我找到了PlatformIO,一个作为vscode插件的嵌入式开发解决方案,接下来就记录一下用PlatformIO实现编译、烧写、串口通讯、STLink调试、变量查找的过程。

安装

1.vscode安装

vscode相信大部分编程爱好者电脑上都有,在浏览器内核的帮助下使得vscode启动非常迅速,再加上各种插件实现代码提示、代码补全、编译等各种功能,使其变成一个非常棒的编辑器。(而且还免费)

在嵌入式开发的时候,我们可以安装C/C++的插件,实现代码提示、代码补全等功能以配合开发需求。

2. PlatformIO安装

安装PlatformIO不需要想Keil一样安装一个软件(可能还需要付费),只需要在插件中搜索并安装即可。

3. 驱动安装

跟普通的嵌入式开发一样,如果你的设备与电脑连接需要驱动,那同样需要将驱动安装上,PlatformIO支持许多嵌入式芯片包括但不限于STM32、Arduino等,这一步需要安装你的芯片可能所需的驱动。

本文以STM32为例,我就需要安装CH340作为串口驱动。

实现

1.新建项目

在安装完PlatformIO并启用后,在vscode的侧边栏可以看到一只小蚂蚁,那个就是PlatformIO的插件,点击就进入了控制界面,如果没有界面就点击左下栏的PIO Home-Open即可。

新建一个PlatformIO项目可以点击Quick Access里面的New Project。

并为新项目命名,在Board中选择你的嵌入式芯片对应的型号,以及需要开发对应的Framework。

PlatformIO支持许多嵌入式芯片,但是如果没有你的的话可以上官网找找,或者找个同类型的先新建,因为在项目中可以调用自己的头文件。

安装成功后项目目录格式应该会是这样,以下是各个目录的含义和作用:

目录名 含义/作用 备注
.pio 项目编译的过程文件和编译文件会存放在这。 编译成功后的二进制文件也在里面的build文件夹。
include 头文件存放位置,只有头文件有效 include里的文件需要在项目配置文件中添加路径。
lib Library文件夹,放一个个独立的头文件和对应的源文件 每个库可以为单独一个文件夹放在lib目录下。
src 源文件存放位置,只有源文件有效 main.c就放在src文件夹里。
test 放测试文件。

至此,新建项目成功。

2.迁移项目并编译

以STM32学习出发,大部分STM32学习代码都是以Keil项目为单位,而我们想要在PlatformIO上尝试运行这些项目,就需要将项目迁移过来,本文以以下这个STM32项目为例。

在迁移项目时,我们需要把项目所需的文件以PlatformIO的项目目录格式进行分类。

  • 头文件
  • 源文件
  • 单独的库

以本项目为例,APP文件夹中的led文件夹就是一个库文件,包含独立的头文件和源头文件;User文件里的.h文件就为头文件,.c文件就为源文件;Libraries里的STM32F10x_StdPeriph_Driver文件夹里也是有一大堆头文件和源文件。

将对应的文件按照PlatformIO的项目目录格式放置在对应的目录下,并在platformio.ini文件里配置头文件的路径,以及项目所需的部分配置。

主要以main.c文件出发,找所需的文件,并将所需的文件放在对应的目录,确保能被搜索到。

在所有依赖文件都安放好后,点击项目里的Build或者下方栏的“打勾符号”进行编译。

注意!:如果所有文件都安装好了所需的依赖都有了,但是还是无法编译成功,出现类似如下报错:报错内容有出现multiple definition重复定义报错的问题。

那应该就是我们自己添加的文件和我们在新建项目时选择的Framwork里PlatformIO为我们提供的文件出现的重叠,如果是重复定义,我们可以删掉这些重复定义的文件,或者可以的话删掉这整个文件。这个问题困扰了我好几天!

在编译后输出绿色的SUCCESS后,我们就可以在.pio/build/<你的嵌入式芯片型号>/目录下找到firmware文件,这就是编译后的文件。

至此,项目迁移并编译成功。

3.程序烧写

以STM32芯片程序烧写为例,最基础的方法是通过串口烧写,目前大部分烧写工具都是通过串口连接后使用.hex文件烧写,由于PlatformIO编译默认生成的是.bin和.elf文件,如果我们需要用hex文件通过其他烧写工具烧写的话需要使用一个python脚本将.elf文件转换为.hex文件。

当然PlatformIO本身也支持串口烧写,所以我们一个一个来讲。

3.1 hex文件生成

我们在项目的根目录下(和platformio.ini文件同级)新建一个export_hex.py,内容如下:

Import("env")
 
# # Custom HEX from ELF
 
env.AddPostAction(
 
    "$BUILD_DIR/${PROGNAME}.elf",
 
    env.VerboseAction(" ".join([
 
        "$OBJCOPY", "-O", "ihex", "-R", ".eeprom",
 
        '"$BUILD_DIR/${PROGNAME}.elf"', '"$BUILD_DIR/${PROGNAME}.hex"'  # 加个单引号
 
    ]), "Building $BUILD_DIR/${PROGNAME}.hex")
 
)

然后在platformio.ini文件里添加一行extra_scripts = export_hex.py,使其在每次编译后运行一遍这个脚本,如图所示。

至此,重新编译后,就会在.pio/build/<你的嵌入式芯片型号>/目录下多生成一个firmware.hex程序,然后打开其他烧写程序工具,选择这个程序就可以成功烧写了。

3.2 PlatformIO程序烧写

platformIO在有串口接入的情况下默认使用的是串口烧写程序,但是出于严谨和方便维护的情况下,严格的配置方式是在platformio.ini文件中配置烧写方式为串口(upload_protocol = serial)。

点击编译按钮隔壁的”Upload”按钮,platformIO就会开始自动寻找对应的COM口,并自动烧写。

以STM32为例,platformIO使用的是它下载下来的stm32flash工具烧写的,如果需要自定义的话,可以将upload_protocol设为custom,并自定义烧写命令,如上图注释代码所示。

至此,实现串口烧写程序。

4. 程序调试

PlatformIO支持大部分主流的仿真器,以STLink为例,在嵌入式芯片按照要求连接好STLink仿真器并接入到电脑后,查看硬件管理器里有没有找到STLink设备,如果能找到就成功连接好仿真器了。

platformio.ini文件中将debug_tool设置为stlink,由于stlink也支持程序烧写,所以其实把upload_protocol写为stlink也是没问题的,也方便,如图所示。

在硬件连接成功,配置文件也配置好之后,就可以在vscode侧边栏的调试里,找到对应项目名的PIO Debug项目的调试方法。

在点击运行和调试后,程序会自动烧写并上传,然后静置一会。。。就会开始vscode的调试啦,由于身边暂时没有开发板,没有办法嵌入式芯片的调试照片,大概长这样子:

可以在需要调试那行设置断点,程序运行到那行的时候可以知道,而且侧边栏可以查看当前所有变量的值,基本拥有所有调试所需的功能。

至此,PlatformIO的STLink仿真器设置完成。

当然PlatformIO也支持其他仿真器,如cmsis-dap等,也支持设定为custom进行自定义debug,使用cmsis-dap时是使用自带的openocd工具进行自动运行调试器等,具体就没有再细究了。

5.串口通讯

platformIO也支持串口通讯,在platformio.ini配置文件中配置如下。

具体的每行的含义应该很明显了,在配置完成后,在确保串口连接成功,可以找到串口文件的情况下就可以点击”Upload”隔壁的”Monitor”启动串口通讯了,哦对了,如果不指定monitor_port的话,platformIO会自己找合适的设备,如果只有一个的话基本上就不会错。

在这个情况下就成功实现串口通讯了,直接打字回车发送就行啦。

6. 其他小技巧

在使用过STM32学习资料的朋友都知道,每个程序就是以一个Keil项目储存的,由于一个嵌入式芯片所需的文件基本都类似,所以在platformIO中可以使用不同的虚拟环境以支持不同的文件和不同的同芯片开发板。

以我个人开发场景为例,我手上有两个STM32F103ZE芯片的开发板,但是一个是以小车为目标设计的,一个是学习板,由于两个开发板的芯片相同,所以我可以在一个platformIO项目中同时实现对两个开发板的分别烧写、调试等。

具体实施如下。

我的platformio.ini配置如下:

[env]
platform = ststm32
board = genericSTM32F103ZE
framework = cmsis

build_flags = 
    -I include/STM32F10x_StdPeriph_Driver/inc
    -I include
    -D USE_STDPERIPH_DRIVER
    -D STM32F10X_MD

monitor_speed = 115200
monitor_echo = yes
monitor_rts = 0
monitor_dtr = 0

extra_scripts = export_hex.py

[env:car]
upload_protocol = stlink
debug_tool = stlink


[env:board]
upload_protocol = serial

其中第一个[env]的内容为公共的,两块开发板这里的配置都是一样的,然后不同的地方就分别分为[env:car][env:board],其中[env:car]是专门为STM32小车的配置,由于STM32小车配有STLink仿真器,所以对于小车的开发我采用stlink烧写并调试,而对于[env:board]学习板的开发,我只采用串口烧写。

在完成如此配置后,我的运行界面如下,我可以选择在Default中选择同时为两个项目同时进行操作,我也可以单独为两个项目做对应的操作。

由于一个项目还是只能有一个main.c,所以我的方案是,在根目录下为两个项目分别建立文件夹,存储对应的程序,在需要的时候复制到main.c中并使用对应的编译烧写方案,实现同一个项目快速开发多块开发板,而且不需要像Keil一样为了烧写其他程序还要打开一个新的项目,再编译,再打开烧写工具烧写。

至此,所有的关于platformIO的使用技巧就说完啦。

大家可以在官方文档里,对PlatformIO有更深的了解。

总结

Keil就像一个可能不是那么讨人喜欢但是永远陪在你身边,在你不得已的时候永远可以站出来稳定帮助你的老工具,而platformIO更像一个年轻人,为你提供一切便利的方法,可能它没有那么靠谱,有时候报的错误让你摸不着头脑,网上的资料也不是那么丰富,那么全面,也不能让你放下心把大型的项目交给它,但是我们的科技就是在这样一个又一个年轻人站出来,尝试去创造出更好、更适合的世界,才能变得更好。

我对PlatformIO的了解也非常有限,我没有尝试过使用起来那个test文件夹,我对cmsis-dap仿真器的使用也失败了,我还有很多要学习的地方,希望这篇文章可以帮助像几个星期前的我一样的朋友,如果有其他人有更好的想法或者解决方案也很希望可以一起沟通。

本文由博客一文多发平台 OpenWrite 发布!

热门相关:福慧双全   绝色符师:龙皇的狂傲妃   惊悚乐园   校花之贴身高手   拳皇之梦