正点原子STM32新建工程
MDK 源自德国的 KEIL 公司,是 RealView MDK 的简称。
MDK5 由两个部分组成: MDK Core 和 Software Packs。
MDK Core 又分成四个部分: uVision IDE with Editor(编辑器), ARMC/C++ Compiler(编译器), Pack Installer(包安装器), uVision Debugger with Trace(调试跟踪器)。Software Packs(包安装器)又分为: Device(芯片支持), CMSIS(ARM Cortex 微控制器软件接口标准) 和 Mdidleware(中间库)三个小部分。MDK5 安装包可以在: http://www.keil.com/demo/eval/arm.htm 下载到。
新建工程步骤:
- 首先,打开 MDK(以下将 MDK5 简称为 MDK)软件。然后点击 ProjectàNew uVision Project如图 3.2.1 所示:
弹出如图 3.2.2 所示界面:
在桌面新建一个 TEST 的文件夹,然后在 TEST 文件夹里面新建 USER 文件夹,将工程名字设为 test,保存在这个 USER 文件夹里面之后, 弹出选择器件的对话框,如图 3.2.3 所示。
因为 ALIENTEK 精英 STM32F103 所使用的 STM32 型号为 STM32F103ZET6,所以在这里我们选择STMicroelectronicsàSTM32F1 SeriesàSTM32F103àSTM32F103ZET6(如果使用的是其他系列的芯片,选择相应的型号就可以了,特别注意: 一定要安装对应的器件 pack 才会显示这些内容哦!!,如果没得选择,请关闭 MDK,然后安装 光盘: 6,软件资料\1,软件\MDK5\ Keil.STM32F1xx_DFP.1.0.5.pack 这个安装包)。
点击 OK,MDK 会弹出 Manage Run-Time Environment 对话框, 如图 3.2.4 所示:
这是 MDK5 新增的一个功能,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境直接点击 Cancel即可,得到如图 3.2.5 所示界面:
到这里只是建了一个框架,还需要添加启动代码,以及.c 文件等。启动代码是一段和硬件相关的汇编代码。 是必不可少的! 这代码主要作用如下: 1、堆栈(SP)的初始化; 2、初始化程序计数器(PC); 3、设置向量表异常事件的入口地址; 4、调用 main 函数。ST 公司提供了 3 个启动文件给我们,分别用于不同容量的 STM32 芯片,这三个文件是:startup_stm32f10x_ld.s
startup_stm32f10x_md.s
startup_stm32f10x_hd.s
其中, ld.s 适用于小容量 产品; md.s 适用于中等容量产品; hd 适用于大容量产品;这里的容量是指 FLASH 的大小.判断方法如下:
小容量: FLASH≤32K
中容量: 64K≤FLASH≤128K
大容量: 256K≤FLASH
开发板使用的是 STM32F103ZET6, FLASH 容量为 512KB,属于大容量产品,所以选择 startup_stm32f10x_hd.s 作为启动文件。
这三个启动文件在开发板光盘à4, 程序源码àSTM32 启动文件 文件夹里面(也可以从我们 的 论坛 下载 到 ,下 载地 址 : http://www.openedv.com/posts/list/313.htm ), 这 里我们 把startup_stm32f10x_hd.s 拷贝到刚刚新建的 USER 文件夹里面。不过这个启动文件,我们做了一点点修改,具体是 Reset_Handler 函数,该函数修改后代码如下:
这段代码屏蔽了复位中断服务函数(Reset_Handler)对函数 SystemInit 的调用,如果是库函数版本,可以取消这个函数的注释,并在外部实现 SystemInit 函数。在图 3.2.5 中,我们找到 Target1àSource Group1à双击à设置打开文件类型为 Asm Sourcefileà选择 startup_stm32f10x_hd.sà点击 Add,如图 3.2.6 所示:
这里看到的 2 个文件夹: Listings 和 Objects,是 MDK5 自行创建的,用于保存编译过程中生成的一些文件,后续会介绍。 添加完后,我们得到如图 3.2.7 所示的界面:
至此就可以开始编写自己的代码了。不过, 在此之前,我们先来做两件事: 第一件,先编译一下,看看什么情况?编译后如图 3.2.8 所示:
图 3.2.8 中 1 处为编译当前目标按钮; 2 处为全部重新编译按钮(工程大的时候,编译耗时较久,建议少用)。 出错和警告信息在下面的 Bulilt Output 对话框中提示出来了。 因为工程中没有 main 函数, 所以报错了。接下来,第二件事, 让我们看看存放工程的文件夹有什么变化?打开我们刚刚建立的TEST\USER 文件夹,可以看到里面多了 2 个文件夹: Listings 和 Objects,如图 3.2.9 所示:
在 USER 文件夹下, startup_stm32f10x_hd.s(启动文件)和 test.uvprojx(MDK5 工程文件)是我们必须用到的 2 个文件,然后 Listings 和 Objects 文件夹是 MDK5 自动生成的,如果打开Listings 和 Objects 文件夹,就可以看到里面多了一些文件,这就是 MDK 编译过程产生的中间文件, 如果工程量大,产生的文件更多(多的可达 100 MB 以上!!)。
MDK5.14 已经默认将这些文件生成在了 Listings 和 Objects 文件夹里面,但是 MDK5.11A及之前版本是不会自动生成这两个文件夹的,所有中间文件都是生成在工程同面目录下,也就是 USER 文件夹下,这样会显得比较混乱。这里,我们不用 MDK5 自己生成的这两个文件夹来存放中间文件, 而是在 TEST 目录下新建一个新的 OBJ 文件夹来存放这些中间文件。这样, USER 文件夹专门用来存放启动文件(startup_stm32f10x_hd.s)、工程文件(test.uvprojx)等不可缺少的文件,而 OBJ 则用来存放这些编译过程中产生的中间文件(包括.hex 文件也将存放在这个文件夹里面)。然后把 Listings 和Objects 文件夹里面的东西全部移到 OBJ 文件夹下(当然要先关闭 MDK 软件)。整理后效果如图 3.2.10 所示:
由于上面我们还没有任何代码在工程里面,这里我们把系统代码 COPY 过来(即 SYSTEM文件夹,该文件夹由 ALIENTEK 提供,可以在光盘任何一个实例的工程目录下找到,不过不要拷贝错了! 不要把库函数代码的系统文件夹拷贝到寄存器代码里面用,反之亦然! 这些代码在任何 STM32F10x 的芯片上都是通用的,可以用于快速构建自己的工程,后面会有详细介绍)。完了之后, TEST 文件夹下的文件如图 3.2.11 所示:
然后我们在 USER 文件夹下面找到 test.uvprojx,打开它, 然后在 Target 目录树上点击右键àManage Project Items, 弹出如图 3.2.12 所示对话框:
在上面对话框的中间栏,点新建(用红圈标出)按钮(也可以通过双击下面的空白处实现),新建 USER 和 SYSTEM 两个组。 然后点击 Add Files 按钮,把 SYSTEM 文件夹三个子文件夹里面的: sys.c、 usart.c、 delay.c 加入到 SYSTEM 组中。注意: 此时 USER 组下还是没有任何文件,得到如图 3.2.13 所示的界面:
点击 OK,退出该界面返回 IDE。 这时,我们在 Target1 树下发现多了 2 个组名,就是我们刚刚新建的 2 个组。如图 3.2.14 所示:
接着,我们新建一个 test.c 文件,并保存在 USER 文件夹下。 然后双击 USER 组,会弹出加载文件的对话框,此时我们在 USER 目录下选择 test.c 文件,加入到 USER 组下。 得到如图3.2.15 所示的界面:
至此,我们就可以开始编写我们自己的代码了。 我们在 test.c 文件里面输入如下代码:#include "sys.h"
#include "usart.h"
#include "delay.h"
int main(void)
{
u8 t=0;
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,115200); //串口初始化为 115200
while(1)
{
printf("t:%d\r\n",t);
delay_ms(500);
t++;
}
} 如果我们此时编译的话,生成的中间文件,还是会存放在 Listings 和 Objects 文件夹下,所以,我们先设置输出路径,再编译。 点击 (Options for Target 按钮),弹出 Options forTarget’ Target 1’ 对话框,选择 Output 选项卡à选中 Create Hex File(用于生成 Hex 文件,后面会用到) à点击 Select Folder for Objectsà找到 OBJ 文件夹à点击 OK,如图 3.2.16 所示:
接着,再设置 Listings 文件路径,在图 3.2.16 的基础上,打开 Listing 选项卡à点击 Select Folder for Listingsà找到 OBJ 文件夹à点击 OK,如图 3.2.17 所示:
最后点击 OK,回到 IDE 主界面。如图 3.2.18 所示:
这个界面,同我们刚输入完代码的时候一样,在第一行,会出现一个红色的“X”,把光标放上面,会看到提示信息:fatal error:‘sys.h’ file not found,意思是找不到 sys.h 这个源文件。这是 MDK4.7 以上才支持的动态语法检查功能,不需要编译,就可以实时检查出语法错误,方便编写代码,非常实用的一个功能,后续会详细介绍。当然,我们也可以编译一下, MDK 会报错,然后双击第一个错误即可定位到出错的地方,如图 3.2.19 所示:
双击红圈内的内容, 你会发现在 test.c 的第 1 行出现了一个浅绿色的三角箭头,说明错误是这个地方产生的(这个功能很实用的哦!熟悉 C++的人就知道 C++也有这个功能,快速定位错误、警告产生的地方。)。
错误提示,已经很清楚的告诉我们错误的原因了: 就是 sys.h 的 include 路径没有加进去,MDK 找不到 sys.h,从而导致了这个错误。现在我们再次点击 (Options for Target 按钮),弹出 Options for Target’ Target 1’ 对话框,选择 C/C++选项卡,如图 3.2.20 所示:
这里特别提醒大家: 图中 1 处,我们必须根据所用 STM32F1 型号的容量,来输入相关宏定义,对于 STM32F103 系列芯片,设置原则如下:
16KB≤FLASH≤32KB | 选择: STM32F10X_LD |
64KB≤FLASH≤128KB | 选择: STM32F10X_MD |
256KB≤FLASH≤512KB | 选择: STM32F10X_HD |
因为精英板使用的是 STM32F103ZET6, FLASH 容量为 512KB,所以,这个位置我们设置为: STM32F10X_HD。
图中 2 处是编译器优化选项,有-O0~-O3 四种选择(default 则是-O2),值越大,优化效果越强,但是仿真调试效果越差。这里我们选择-O0 优化,以得到最好的调试效果,方便开发代码,在代码调试结束后,大家可以选择-O2 之类的优化,得到更好的性能和更少的代码占用量。图中 3 处, One ELF Section per Function 主要是用来对冗余函数的优化。通过这个选项,可以在最后生成的二进制文件中将冗余函数排除掉,以便最大程度地优化最后生成的二进制代码,所以,我们一般勾选上这个,这样可以减少整个程序的代码量。
然后在 Include Paths 处(4 处),点击 5 处的按钮。在弹出的对话框中加入 SYSTEM 文件夹下的 3 个文件夹名字,把这几个路径都加进去(此操作即加入编译器的头文件包含路径, 后面会经常用到)。如图 3.2.21 所示:
点击 OK 确认,回到 IDE,此时再点击 按钮,再编译一次,发现没错误了,得到如图 3.2.22所示的界面:
因为我们之前选择了生成 Hex 文件,所以在编译的时候, MDK 会自动生成 Hex 文件(图中圈出部分),这个文件在 OBJ 文件夹里面,串口下载的时候,我们就是下载这个文件到STM32F1 里面的,这个在后面的程序下载一节会介绍。这里有的朋友编译后,可能会出现一个警告: warning: #1-D last line of file ends without a newline。这个警告是在告诉我们,在某个 C 文件的最后,没有输入新行,我们只需要双击这个警告,跳转到警告处,然后在后面输入多一个空行就好了。至此,一个完整的 STM32F1 开发工程在 MDK5 下建立了。 接下来我们就可以进行代码下载和仿真调试了。
3.3 MDK5 使用技巧
3.3.1 文本美化
文本美化,主要是设置一些关键字、注释、数字等的颜色和字体。 前面我们在介绍 MDK5新建工程的时候看到界面如图 3.2.22 所示,这是 MDK 默认的设置, 可以看到其中的关键字和注释等字体的颜色不是很漂亮,而 MDK 提供了我们自定义字体颜色的功能。我们可以在工具条上点击 (配置对话框)弹出如图 3.3.1.1 所示界面:
在该对话框中,先设置 Encoding 为:Chinese GB2312(Simplified),然后设置 Tab size 为: 4。以更好的支持简体中文(否则,拷贝到其他地方的时候,中文可能是一堆的问号),同时 TAB间隔设置为 4 个单位。然后,选择: Colors&Fonts 选项卡,在该选项卡内,我们就可以设置自己的代码的子体和颜色了。由于我们使用的是 C 语言,故在 Window 下面选择:C/C++ Editor Files在右边就可以看到相应的元素了。如图 3.3.1.2 示:
然后点击各个元素修改为你喜欢的颜色(注意双击,且有时候可能需要设置多次才生效,MDK 的 bug),当然也可以在 Font 栏设置你字体的类型,以及字体的大小等。设置成之后,点击 OK,就可以在主界面看到你所修改后的结果,例如我修改后的代码显示效果如图 3.3.1.3 示:
这就比开始的效果好看一些了。 字体大小,则可以直接按住: ctrl+鼠标滚轮,进行放大或者缩小,或者也可以在刚刚的配置界面设置字体大小。
细心的读者可能会发现,上面的代码里面有一个 u8,还是黑色的,这是一个用户自定义的关键字,为什么不显示蓝色(假定刚刚已经设置了用户自定义关键字颜色为蓝色)呢?这就又要回到我们刚刚的配置对话框了,单这次我们要选择 User Keywords 选项卡,同样选择: C/C++Editor Files,在右边的 User Keywords 对话框下面输入你自己定义的关键字,如图 3.3.1.4 示:
图 3.3.1.4 中我定义了 u8、 u16、 u32 等 3 个关键字,这样在以后的代码编辑里面只要出现这三个关键字,肯定就会变成蓝色。点击 OK,再回到主界面,可以看到 u8 变成了蓝色了,如图 3.3.1.5 示:
3.3.2 语法检测&代码提示
MDK4.70 以上的版本,新增了代码提示与动态语法检测功能,使得 MDK 的编辑器越来越好用了,这里我们简单说一下如何设置,同样,点击 ,打开配置对话框,选择 Text Completion选项卡,如图 3.3.2.1 所示:
Strut/Class Members,用于开启结构体/类成员提示功能。Function Parameters,用于开启函数参数提示功能。Symbols after xx characters,用于开启代码提示功能,即在输入多少个字符以后,提示匹配的内容(比如函数名字、结构体名字、变量名字等),这里默认设置 3 个字符以后,就开始提示。如图 3.3.2.2 所示:
Dynamic Syntax Checking,则用于开启动态语法检测,比如编写的代码存在语法错误的时候,会在对应行前面出现 图标,如出现警告,则会出现 图标,将鼠标光标放图标上面,则会提示产生的错误/警告的原因,如图 3.3.2.3 所示:
这几个功能,对我们编写代码很有帮助,可以加快代码编写速度,并且及时发现各种问题。不过这里要提醒大家,语法动态检测这个功能, 有的时候会误报(比如 sys.c 里面,就有误报),大家可以不用理会,只要能编译通过(0 错误, 0 警告),这样的语法误报,一般直忽略即可。
3.3.3 代码编辑技巧
这里给大家介绍几个我常用的技巧,这些小技巧能给我们的代码编辑带来很大的方便,相信对你的代码编写一定会有所帮助。
1) TAB 键的妙用
首先要介绍的就是 TAB 键的使用,这个键在很多编译器里面都是用来空位的,每按一下移空几个位。如果你是经常编写程序的对这个键一定再熟悉不过了。但是 MDK 的 TAB 键和一般编译器的 TAB 键有不同的地方,和 C++的 TAB 键差不多。 MDK 的 TAB 键支持块操作。也就是可以让一片代码整体右移固定的几个位,也可以通过 SHIFT+TAB 键整体左移固定的几个位。假设我们前面的串口 1 中断响应函数如图 3.3.3.1 所示:
图 3.3.3.1 中这样的代码大家肯定不会喜欢,这还只是短短的 30 来行代码,如果你的代码有几千行,全部是这个样子,不头大才怪。看到这样的代码我们就可以通过 TAB 键的妙用来快速修改为比较规范的代码格式。选中一块然后按 TAB 键, 你可以看到整块代码都跟着右移了一定距离,如图 3.3.3.2 所示:
接下来我们就是要多选几次,然后多按几次 TAB 键就可以达到迅速使代码规范化的目的,最终效果如图 3.3.3.3 所示
图 3.3.3.3 中的代码相对于图 3.3.3.1 中的要好看多了,经过这样的整理之后, 整个代码一下就变得有条理多了,看起来很舒服。
2) 快速定位函数/变量被定义的地方 上一节,我们介绍了 TAB 键的功能,接下来我们介绍一下如何快速查看一个函数或者变量所定义的地方。
大家在调试代码或编写代码的时候,一定有想看看某个函数是在那个地方定义的,具体里面的内容是怎么样的,也可能想看看某个变量或数组是在哪个地方定义的等。尤其在调试代码或者看别人代码的时候,如果编译器没有快速定位的功能的时候, 你只能慢慢的自己找,代码量比较少还好,如果代码量一大,那就郁闷了,有时候要花很久的时间来找这个函数到底在哪里。型号 MDK 提供了这样的快速定位的功能。只要你把光标放到这个函数/变量(xxx)的上面(xxx 为你想要查看的函数或变量的名字),然后右键, 弹出如图 3.3.3.4 所示的菜单栏 :
在图 3.3.3.4 中,我们找到 Go to Definition Of‘STM32_Clock_Init’ 这个地方,然后单击左键就可以快速跳到 STM32_Clock_Init 函数的定义处(注意要先在 Options for Target 的 Output选项卡里面勾选 Browse Information 选项,再编译,再定位,否则无法定位!)。如图 3.3.3.5 所示:
对于变量,我们也可以按这样的操作快速来定位这个变量被定义的地方,大大缩短了你查找代码的时间。很多时候,我们利用 Go to Definition 看完函数/变量的定义后,又想返回之前的代码继续看,
此时我们可以通过 IDE 上的 按钮(Back to previous position)快速的返回之前的位置,这个按钮非常好用!
3) 快速注释与快速消注释接下来,我们介绍一下快速注释与快速消注释的方法。在调试代码的时候, 你可能会想注释某一片的代码,来看看执行的情况, MDK 提供了这样的快速注释/消注释块代码的功能。也是通过右键实现的。这个操作比较简单,就是先选中你要注释的代码区,然后右键,选择AdvancedàComment Selection 就可以了。 以 Stm32_Clock_Init 函数为例,比如我要注释掉下图中所选中区域的代码,如图 3.3.3.6 所示:
我们只要在选中了之后,选择右键,再选择 AdvancedàComment Selection 就可以把这段代码注释掉了。执行这个操作以后的结果如图 3.3.3.7 所示:
这样就快速的注释掉了一片代码,而在某些时候,我们又希望这段注释的代码能快速的取消注释, MDK 也提供了这个功能。与注释类似,先选中被注释掉的地方,然后通过右键àAdvanced,不过这里选择的是 Uncomment Selection。
3.3.4 其他小技巧除了前面介绍的几个比较常用的技巧,这里还介绍几个其他的小技巧,希望能让你的代码编写如虎添翼。
第一个是快速打开头文件。在将光标放到要打开的引用头文件上,然后右键选择 Open Document“XXX”,就可以快速打开这个文件了(XXX 是你要打开的头文件名字)。如图 3.3.4.1所示:
第二个小技巧是查找替换功能。这个和 WORD 等很多文档操作的替换功能是差不多的,在 MDK 里面查找替换的快捷键是“CTRL+H”,只要你按下该按钮就会调出如图 3.3.4.2 所示界面:
这个替换的功能在有的时候是很有用的,它的用法与其他编辑工具或编译器的差不多,相信各位都不陌生了,这里就不啰嗦了。
第三个小技巧是跨文件查找功能,先双击你要找的函数/变量名(这里我们还是以系统时钟初始化函数: Stm32_Clock_Init 为例),然后再点击 IDE 上面的 ,弹出如图 3.3.4.3 所示对话框:
点击 Find All, MDK 就会帮你找出所有含有 Stm32_Clock_Init 字段的文件并列出其所在位置,如图 3.3.4.4 所示:
该方法可以很方便的查找各种函数/变量,而且可以限定搜索范围(比如只查找.c 文件和.h文件等),是非常实用的一个技巧。