首页 关于
树枝想去撕裂天空 / 却只戳了几个微小的窟窿 / 它透出天外的光亮 / 人们把它叫做月亮和星星
目录

新建一个STM32工程

本文从零开始新建一个工程,并导入各种源代码文件,进行编译和烧录,最终可以控制开发板上的LED灯不断的闪烁。 然后对这些文件按照我的个人习惯做一些整理,建立不同的目录,把源代码分门别类的保存起来,以方便后续工作。

在MCU上即使简单地控制一个LED灯,我们也需要经过三个环节。 首先,要在一个文本文件中用C语言或者汇编写程序;然后,对这些源代码文件进行编译链接生成处理器可以识别的目标代码, 或者说是可执行文件;最后再把目标代码烧录到芯片上,才可以看到我们的控制程序能否正常运行。

而这些环节需要用到一系列的工具。编辑代码需要用到文本编辑器,生成目标代码需要用到编译器和链接器, 把目标代码烧录到芯片上又要用到烧录器。实际上我们完全可以用记事本编辑源代码,用GCC或者什么其它的编译链接器生成目标代码。 而把目标代码烧录到芯片上的本质就是通过某种通信协议(比较常见的是JTAG)把目标代码发送给MCU, 由MCU把目标代码写到一个FLASH或者ROM中,保证下次上电时仍然能够使用这些目标代码。 所以我们会看到像JLink,STLink等五花八门的工具用于烧录程序。

为了简化开发过程,就有了IDE(Integrated Development Environment, 集成开发工具),把文本编辑器、代码编译链接器、 烧录器等工具整合到一个软件里。IDE确实为我们的开发工作提供了很多便利,尤其是入门而言可以屏蔽掉很多细节,让我们直奔主题。 很多教程中使用的IDE都是德国的KEIL公司开发的μVision IDE,所以我们也是用这款工具。

以后随着研究的深入,可能IDE并不能满足我们所有的需求,那时我们会专门在Linux平台下搭建一个开发环境。 但是关于用什么开发环境,我想说好用就行,它们都只是工具而已。本文中的1到3节内容可能和常见的手把手教程没什么两样, 都是截了一大堆图放在那里,一步一步讲如何创建工程、添加代码、编译调试的。没兴趣的读者可以跳过去, 相关例程参见这里第四部分才是对目录中问题的回答。

1. 新建工程文件

安装完μVision之后,打开软件我们可以看到如图1(a)所示的界面,点击菜单栏下的【project】->【New μVision Project】如图1(b)指引。

图1(a) μVision初始界面 图1(b) 新建工程菜单项

点击【project】->【New μVision Project】后,将弹出如图2(a)所示的对话框中选择一个路径保存工程。 这里选择的路径是"E:\2. Work\XiaoTuOS"并将之命名为"project"。点击保存按钮后,就会出现图2(b)中所示的对话框,提示我们选择目标芯片。 这里选择的是"STM32F407ZETx"系列芯片,点击OK进入下一步。

图2(a) 选择保存工程文件的路径 图2(b) 选择目标芯片"STM32F407ZETx"

然后就会进入图3(a)所示的界面,在这个界面中,我们可以选择一些库添加进来。但这里我们选择Cancel不添加任何库,因为我们要自己写。 选择Cancel之后就结束了配置过程,我们将得到图3(b)中所示的界面。

图3(a) 选择库文件(这里我们不添加任何库) 图3(b) 工程文件创建结束
对比图3(b)和图1(a)中的project选项卡,可以看到新建的工程树。这是一棵空树,还没有添加任何源文件。

2. 添加源文件和编译

打开工程文件所在的目录,我们可以看到下图4(a)中所示的目录和文件。它们都是由μVision软件生成的, 其中只有"project.uvprojx"是不可以随便删除的工程文件,其它都是一些配置项可以删除,但删除后我们还得重新配置。 然后,我们把《通用IO端口驱动LED灯》一文中用到的所有文件都直接拷贝到工程文件所在的目录下, 如图4(b)所示那样。

图4(a) 工程文件目录下的子目录和文件 图4(b) 拷贝的源文件和头文件
然后我们把其中的"*.c"和"*.s"文件添加到工程树下。我们有两种方式添加文件,分别如图5(a)和图5(b)所示。在图5(a)中,我们通过右键目录树中的"Source Group 1", 在弹出的菜单中选择"Add Existing Files..."。在图5(b)中通过点击工具栏中的图标""打开如图所示的对话框, 点击其中的"Add Files..."按钮触发添加文件。
图5(a) 通过右键目录树中的Group添加源文件 图5(b) 通过项目管理器添加源文件
触发添加文件后,将弹出如下图6(a)中所示的对话框。在对话框中,选择需要添加的3个文件"main.c","system_stm32f4xx.c"和"startup_stm32f40_41xxx.s",点击"Add"按钮, 就可以将之添加到目录树中。如果没有找到某个文件,通过修改文件类型就应该可以找到。一路确认之后,我们可以看到图6(b)所示的目录树中,已经把这三个文件添加进来了。
图6(a) 添加源文件的对话框 图6(b) 添加源文件后的目录树
但是这个时候点击图标""进行编译有可能会报错,说一些头文件找不到, 如下图7中所示的那样。根据其中的错误信息,打开main.c文件的话,可以看到其中的头文件是用尖括号<>括起来的 #include <stm32f407.h>,这是因为当前的工作目录不是编译器默认需要查找的目录, 如果将其改成#include "stm32f407.h"就可以找到了。但在这里我们不改代码,通过添加查找路径来消除这一错误。
图7 添加源文件的对话框
我们可以通过图标""打开如图8(a)所示的对话框,点击"C/C++"选项卡,可以看到"Include Path"一项是空的。 点击"Include Path"项后的""在打开的对话框,依次点击其中用红色数字标记的按钮, 就可以得到如图8(b)所示的界面,我们选择那些头文件所在的目录"E:\2. Work\XiaoTuOS",一路确认后,再次进行编译就应该能够成功了。
图8(a) 工程对象配置对话框之C/C++选项卡 图8(b) 添加include搜索路径

3. 烧录和在线调试

点击图标""就可以把刚刚编译成功的代码烧录到STM32上,但在这之前我们还需要做一些配置工作。 仍然是通过图标""打开工程对象配置对话框,点击如图9(a)所示的"Debug"选项卡。 打开"Use"之后的下拉菜单,选择仿真器。然后点击其后的"Settings"按钮,根据图9(b)中红色标记的内容设置为SW模式,不出意外,应该可以看到蓝色标记的内容。 如果没有看到,应该是没有连接到片子上。正常情况下能够看到蓝色标记的内容就可以烧写程序了。

图9(a) 工程对象配置对话框之Debug选项卡 图9(b) 仿真器配置
在连接着仿真器的情况下,通过快捷键<ctrl-F5>,或者点击图标""就可以进行在线调试了。

到这里,就已经可以随意地建工程,添加代码,编译和调试了,去开发任何定义清楚的功能了。 下面的内容,完全是我的个人习惯的一些介绍,也是对目录中问题的解答。

4. 文件和目录整理

在项目比较简单的时候,我们把所有的文件都堆在一个目录下无所谓。但是等到项目庞大到一定程度,又添加了很多第三方的库的时候,还把它们堆放在一起, 维护起来就会很困难。所以,我都会建立一些目录,把这些源代码按功能和模块分别存放,但实际做得时候每次都有点差异,组织成什么样完全凭心情,不过大体上还是一致的。

一般情况下,针对一块板子我会专门建一个目录。比如说,对于我们现在研究的这块板子,我就会建一个XiaoTuOS的目录。在该目录下一般会有如下的子目录和文件:

对于本文中使用的这个例程,我们在《通用IO端口驱动LED灯》中也做了类似的划分。 目录树可以参考左图,建立了inc, lib和pro三个子目录。

把"types.h"文件放置在了inc目录下,它是几乎所有的源代码都要包含的头文件,里面定义了uint8,uint16等变量类型,和一些特殊的数据结构。

在lib目录下建立了两个子目录"stm32"和"cmsis","cmsis"是Cortex-M4内核的工具库,"stm32"则是具体MCU上各种外设的工具库。 实际上这两个都是对MCU芯片的库,Cortex-M4是ARM提供的处理器内核,具有一定的通用性,可能可以用到其它公司的芯片上,所以将其与STM32分开。

把所有前缀为"cortex_m4"的文件按照源文件和头文件分别放置在"cmsis"的src和inc两个子目录中。目前我们只有一个"cortex_m4_scb.h", 而且还没有关于处理器内核的"*.c"文件。

而"stm32"目录下的文件则相对较多。在其中的"src"子目录下,有一个汇编语言写的文件"startup_stm32f40_41xxx.s", 这个文件是我直接从官方提供的库中拷贝过来的,作用是启动芯片。而其中的"system_stm32f4xx.c"也是用于启动的,只是是用C语言写的,主要用来配置系统时钟。 在"inc"目录下的文件则是用于访问芯片上的flash、gpio控制器和rcc控制器的,其中的"ioafmap"定义了各个引脚的功能。

"pro"目录下目前只有一个工程目录"Particle"。我们在图4(a)中讲了,创建工程文件之后,系统会自动生成很多文件, 但其中只有"*.uvprojx"是不可以随意删除的,因为这个文件中记录了添加到工程中的文件和它们的路径,Include查找路径等信息。 它是一个xml格式的文本文件,有兴趣的读者可以拿个记事本什么的打开看看。 在"Particle"目录下专门建立了一个"app"的子目录,其中保存了我们的"main.c"文件。它是我们具体功能实现的核心代码, 通过调用库、和src中公共代码组合出我们想要的功能。

对应的,我们回到图5所描述的界面,对工程做一些调整。首先在工程树下建立"app"和"libstm32"两个Group, 并按照我们的目录结构划分添加源代码如下图10(a)所示。再按照图10(b)中所示的样子,添加Include查找路径。

图10(a) 整理目录结构添加源代码 图10(b) 整理目录结构添加Include路径

这样的文件组织形式,在我目前看来是挺方便的,不知道以后会不会觉得很繁琐,那时候再说吧。 写这部分的目的是想告诉读者,其实文件目录怎么组织都不是重点,不一定非要按照某些教程写的那样在建立工程文件之前,先建了各种各样的目录。 我们完全可以根据个人喜好,做一些个性化的配置,开心就好。

5. 总结

这一篇文章是后来补的,一开始觉得创建一个工程是很理所当然的事情,但后来发现入门的时候,很多理所当然的事情都显得高深莫测。 所以,补了这篇文章。

虽然新建一个工程的时候会生成很多文件,但实际很关键的文件只有一个"*.uvprojx",它描述了整个工程的组织形式, 编译方式等等各种信息。所以其它的文件删了都不会有大的影响,顶多就是一些仿真器配置信息需要再重新配置一下。

至于工程目录应该怎么组织才合理,完全是仁者见仁,智者见智,只要用起来舒服,怎么都行。不过我们还是应该有一些套路在里面的, 否则每次新建一个工程的时候就会有很多重复性的工作要做,还是很烦的。




Copyright @ 高乙超. All Rights Reserved. 京ICP备16033081号-1