新建一个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) 工程文件创建结束 |
2. 添加源文件和编译
打开工程文件所在的目录,我们可以看到下图4(a)中所示的目录和文件。它们都是由μVision软件生成的, 其中只有"project.uvprojx"是不可以随便删除的工程文件,其它都是一些配置项可以删除,但删除后我们还得重新配置。 然后,我们把《通用IO端口驱动LED灯》一文中用到的所有文件都直接拷贝到工程文件所在的目录下, 如图4(b)所示那样。
图4(a) 工程文件目录下的子目录和文件 | 图4(b) 拷贝的源文件和头文件 |
图5(a) 通过右键目录树中的Group添加源文件 | 图5(b) 通过项目管理器添加源文件 |
图6(a) 添加源文件的对话框 | 图6(b) 添加源文件后的目录树 |
#include <stm32f407.h>
,这是因为当前的工作目录不是编译器默认需要查找的目录,
如果将其改成#include "stm32f407.h"
就可以找到了。但在这里我们不改代码,通过添加查找路径来消除这一错误。
图7 添加源文件的对话框 |
图8(a) 工程对象配置对话框之C/C++选项卡 | 图8(b) 添加include搜索路径 |
3. 烧录和在线调试
点击图标""就可以把刚刚编译成功的代码烧录到STM32上,但在这之前我们还需要做一些配置工作。 仍然是通过图标""打开工程对象配置对话框,点击如图9(a)所示的"Debug"选项卡。 打开"Use"之后的下拉菜单,选择仿真器。然后点击其后的"Settings"按钮,根据图9(b)中红色标记的内容设置为SW模式,不出意外,应该可以看到蓝色标记的内容。 如果没有看到,应该是没有连接到片子上。正常情况下能够看到蓝色标记的内容就可以烧写程序了。
图9(a) 工程对象配置对话框之Debug选项卡 | 图9(b) 仿真器配置 |
到这里,就已经可以随意地建工程,添加代码,编译和调试了,去开发任何定义清楚的功能了。 下面的内容,完全是我的个人习惯的一些介绍,也是对目录中问题的解答。
4. 文件和目录整理
在项目比较简单的时候,我们把所有的文件都堆在一个目录下无所谓。但是等到项目庞大到一定程度,又添加了很多第三方的库的时候,还把它们堆放在一起, 维护起来就会很困难。所以,我都会建立一些目录,把这些源代码按功能和模块分别存放,但实际做得时候每次都有点差异,组织成什么样完全凭心情,不过大体上还是一致的。
一般情况下,针对一块板子我会专门建一个目录。比如说,对于我们现在研究的这块板子,我就会建一个XiaoTuOS的目录。在该目录下一般会有如下的子目录和文件:
- doc: 目录,用于存放各种说明文档
- inc: 目录,用于存放各种头文件,其内部根据不同模块可能还会建一些子目录
- src: 目录,用于存放一些公用的源代码(目前我已经不太喜欢这个目录了)
- pro: 目录,用于存放一个板子下为了实现不同功能而建立的各种工程文件,而且是为了每一个工程建立一个目录
- lib: 目录,用于存放各种库,为每一个库建立一个子目录
- .gitignore: 文件,版本控制器git根据该文件屏蔽一些不希望加入版本控制的文件。
- README.md: 文件,用Markdown标记语言写的说明文件,主要介绍项目干啥用的,怎么使用等等内容。
对于本文中使用的这个例程,我们在《通用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",它描述了整个工程的组织形式, 编译方式等等各种信息。所以其它的文件删了都不会有大的影响,顶多就是一些仿真器配置信息需要再重新配置一下。
至于工程目录应该怎么组织才合理,完全是仁者见仁,智者见智,只要用起来舒服,怎么都行。不过我们还是应该有一些套路在里面的, 否则每次新建一个工程的时候就会有很多重复性的工作要做,还是很烦的。