第3章 MDK开发环境 本章主要介绍本书的软件开发环境——MDK5及其应用。首先介绍ST官方固件库; 接着介绍MDK5软件及其安装和注册的过程; 然后介绍怎样基于ST官方固件库来新建一个工程模板; 最后介绍针对开发板下载程序的3种方式,以及在MDK5中对程序进行调试的方法。 本章的学习目标如下: 了解STM32应用开发的两种方式; 理解ST官方固件库的概念以及它在STM32应用开发过程中的作用; 了解CIMIS的含义以及定义它的目的; 掌握ST官方固件库的目录结构以及其中的重要文件/文件夹的作用; 掌握MDK5的安装及注册过程; 掌握在MDK5中基于ST官方固件库新建工程模板的方法; 掌握开发板下载程序的3种方式; 掌握在MDK5中对程序进行调试的方法。 视频 3.1STM32官方固件库 意法半导体公司为了方便用户开发程序,提供了一套丰富的STM32固件库,这个STM32官方固件库到底是什么?它对开发程序有什么用处?用它进行开发与直接操作寄存器进行开发这两种方式又有什么区别和联系? 3.1.1库开发与寄存器开发 很多用户都是在学习了51单片机之后再学习STM32单片机的。在51单片机的应用程序开发过程中,往往是通过直接操作51单片机的寄存器来对它进行控制的。例如,如果要控制51单片机的某个I/O口的电平状态,以端口0为例,假定要使端口0的全部引脚都输出低电平,则可以通过操作寄存器P0来完成,程序代码如下: P0 = 0x00; 在STM32单片机的应用程序开发过程中,要使GPIOA的所有引脚都输出低电平,同样可以通过操作相应的寄存器GPIOA_ODR来完成,程序代码如下: GPIOA_ODR = 0x0000; 但是,相比于51单片机只有几十个寄存器,STM32单片机的寄存器数目一般都要有上百个,甚至数百个,如果继续用这种直接操作寄存器的方式来对STM32单片机进行应用程序的开发,就需要熟练地掌握每个寄存器的用法,这不仅非常麻烦,还容易出错。 基于上述原因,意法半导体公司推出了自己的官方固件库,固件库是许多函数的集合,这些函数的作用为: 向下与STM32单片机的各个寄存器打交道,向上为用户提供调用函数的接口(API),不同的函数实现不同的功能。也就是说,固件库中的每一个函数对底层寄存器的操作都被封装起来,它只向用户提供一个实现该操作的接口,用户不需要知道该函数具体是怎样操作以及操作哪个/些寄存器,只需要知道该函数是实现了什么样的功能,并懂得怎样使用该函数即可。 还是上面的例子,也可以通过调用固件库中的函数来实现,固件库中有一个GPIO_Write()函数,它的程序代码为: void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) { /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); GPIOx->ODR = PortVal; } 可能大家现在还不能完全明白该函数中每一条代码的具体含义,但是应大体看出,该函数要实现的主要功能是: 给GPIOx(参数)的ODR寄存器赋值PortVal(参数)。 所以,可以操作如下: GPIO_Write(GPIOA, 0x0000); 这样,通过调用库函数而无须再去操作寄存器,就实现了上面的功能。或许这个简单的操作还不足以说明固件库功能的强大之处,但当对STM32单片机外设的工作原理有了一定的了解后,再去回看固件库,会发现库函数大多都是按照其实现的功能来命名的,而且STM32单片机的寄存器大多都是32位的,不像51单片机操作起来那样简单、不易出错,那时就感受到通过调用固件库进行应用程序开发的方便之处。 这里需要说明的是,有了STM32官方固件库,并不代表在应用程序的开发过程中就不再需要跟STM32单片机的寄存器打交道了。任何一款处理器,无论它多么高级,都是通过操作它的寄存器来对它进行控制。调用库函数,归根结底,还是通过对STM32单片机的寄存器进行操作来实现其相应的功能。所以,在对STM32单片机进行应用程序开发的过程中,仅仅掌握固件库是远远不够的,还需要理解STM32单片机及其外设的工作原理,然后需要通过了解库函数的实现细节,来加深对这些工作原理的理解,在这一系列过程中,仍然需要不断地和STM32单片机的寄存器打交道,只有在掌握了STM32单片机及其外设的工作原理,并了解了库函数的实现细节后,库函数的使用才能取得事半功倍的效果。此外,固件库不是万能的,它只是意法半导体公司给大家提供的一个能够实现许多不同功能的函数的集合。但是,在某些应用程序的开发过程中,这些函数可能并不能满足实际的开发需求,在这种情况下,只能通过自己直接操作寄存器来完成要实现的功能。所以,在应用库函数时,只有在很好地理解了它的实现细节的情况下,才能够在实际的应用程序开发过程中做到举一反三,游刃有余。 通过本节的学习,应该对STM32官方固件库的作用有了一个基本的认识,并且能够看出通过操作库函数与直接操作寄存器这两种应用程序开发方式的不同。后面将结合具体的实例进一步讲解对STM32官方固件库的使用。 3.1.2CMSIS STM32官方固件库是一系列函数的集合,这些函数需要满足什么要求呢?这里涉及标准,即本节要介绍的CMSIS。 前面介绍过ARM公司和意法半导体公司,ARM公司是一个做芯片标准的公司,它负责的是芯片内核的架构设计,而像意法半导体公司、TI公司等不做标准,它们负责的是在ARM公司提供的芯片内核的基础上设计自己的芯片。因此,所有CortexM3内核的芯片的内核架构都是相同的,不同的是它们的存储器容量、片上外设、I/O或其他模块,对于这些资源,不同的公司可以根据自己的不同需求进行不同的设计,即使是同一家公司设计的基于CortexM3内核的不同款芯片,它们的这些资源也不尽相同,比如STM32F103VCT和STM32F103ZET,它们在片上外设方面就有很大的不同。在这里通过图31来更好地对它进行表述。 图31CM3内核芯片的设计架构 由图31可以看出,所有基于CortexM3内核的芯片都必须遵循ARM公司设计的CortexM3内核的标准,而ARM公司为了让不同芯片公司设计生产出的不同的基于CortexM3标准的芯片在软件上能够基本兼容,就和各芯片生产商提出了一套需要大家共同遵守的标准——CMSIS(Cortex Microcontroller Software Interface Standard),翻译为“Cortex微控制器软件接口标准”,而ST官方固件库就是根据这套标准进行设计的。 CMSIS是为CortexM处理器系列提供的与(芯片)生产商无关的硬件抽象层,它定义了通用的工具接口。CMSIS使得处理器和外设能够具有一致的设备支持和简单的软件接口,同时简化了软件的复用,减少了单片机开发人员的学习过程,并且缩短了新设备推向市场的时间。 CMSIS是为了能够同各个芯片和软件供应商密切合作而定义的,它提供了一套通用的方式来连接外设、实时操作系统以及中间级组件。CMSIS的目的就是使得来自多个中间级供应商的软件能够统一。 CMSIS应用程序的基本结构如图32所示。 图32CMSIS应用程序的基本结构 由图32可以看出,CMSIS层在整个系统中处于中间层,它向下负责与内核以及各个外设打交道,向上为实时操作系统和用户程序提供可调用的函数接口。如果没有CMSIS标准,各个芯片生产商可能就会按照自己喜欢的风格来设计库函数,这会使得芯片在软件上难以兼容,而CMSIS的作用就是强制规定,所有的芯片生产商都必须按照此标准来进行设计。 举个简单的例子。在使用CortexM3内核的单片机的时候需要首先对整个系统进行初始化,CMSIS规定,系统初始化函数的名字必须为SystemInit,所以,各个芯片公司在编写自己库函数的时候就必须用SystemInit()函数首先对系统进行初始化。此外,CMSIS还对各个外设驱动文件以及一些重要函数的命名进行规范,如3.1.1节中提到的函数GPIO_Write(),就必须按照CMSIS的规范来命名。这就保证了各芯片生产商生产出的CortexM3芯片在软件上具有较好的兼容性。 3.1.3STM32官方固件库包 本节介绍STM32官方固件库包的结构及其所包含的内容。ST官方提供的固件库完整包可以在官方网站下载,固件库是在不断完善升级的,所以会有不同的版本,这里为大家提供的是V3.5版本的固件库。 将下载的固件库包解压缩到STM32F10x_StdPeriph_Lib_V3.5.0文件夹后,可以看到文件夹中的内容如图33所示。 图33ST官方固件库包解压缩后的文件夹 文件夹的结构如图34所示。 图34ST官方固件库文件夹的结构 从图33中可以看到,固件库包STM32F10x_StdPeriph_Lib_V3.5.0中包含4个子文件夹,其中,最重要的是Libraries文件夹,从图34中可以看到,该文件夹又包含了2个子文件夹,分别是CMSIS文件夹和STM32F10x_StdPeriph_Driver文件夹,固件库中几乎所有的核心文件都在这两个文件夹或其子文件夹中。 CMSIS文件夹包含了两个子文件夹,分别是CM3文件夹和Documentation文件夹,后者包含的是文档,无须太在意; 从图34中可以看出,CM3又包含两个子文件夹,分别是CoreSupport文件夹和DeviceSupport文件夹。进入CoreSupport文件夹,可以看到,该文件夹包含两个文件——core_cm3.c和core_cm3.h,如图35所示。 这两个文件是CMSIS的核心文件,提供进入CM3内核的接口,是ARM公司提供的,对所有的CM3内核的芯片都是一样的。所以,对于开发者来说,这两个文件永远都不需要修改,大家也无须再对它进行深入研究。 图35CoreSupport文件夹的内容 对于CM3文件夹下的另一个子文件夹DeviceSupport,一直双击到进入DeviceSupport\ST\STM32F10x子文件夹下,可以看到,其中包含的文件和子文件夹如图36所示。 图36STM32F10x文件夹的内容 图36中有3个文件: stm32f10x.h、system_stm32f10x.c和system_stm32f10x.h。其中,源文件system_stm32f10x.c和它对应的头文件system_stm32f10x.h的功能是设置系统以及总线的时钟,文件中有一个非常重要的函数——SystemInit(),这个函数在系统启动的时候必须被调用,以设置系统的时钟。stm32f10x.h头文件也非常重要,它几乎在STM32单片机整个应用程序开发过程中都会被用到,因为它包含了许多重要的结构体以及宏的定义。此外,它还包含了系统寄存器定义声明以及包装内存操作,具体将会在后面介绍。 DeviceSupport\ST\STM32F10x文件夹中还包括一个startup子文件夹。顾名思义,这个文件夹中放的是启动相关的文件,双击进入该文件夹,可以看到,其中包含arm、gcc_ride7、iar和TrueSTUDIO这4个子文件夹,再双击进入arm文件夹,可以看到,其中包含8个以startup开头以.s为扩展名的文件,如图37所示。其他3个文件夹也类似。 图37相关启动文件所在的文件夹 这8个文件都是用于启动相关的文件,根据芯片容量的不同有不同的应用。这里的容量是指芯片Flash的大小,判断方法如下: 小容量: 16KB≤Flash≤32KB 中容量: 64KB≤Flash≤128KB 大容量: 256KB≤Flash≤512KB 超大容量: Flash≥1024KB 这8个文件适用的芯片情况如下: startup_stm32f10x_cl.s——STM32F105xx/STM32F107xx。 startup_stm32f10x_hd.s——大容量的STM32F101xx/STM32F102xx/STM32F103xx。 startup_stm32f10x_hd_vl.s——大容量的STM32F100xx。 startup_stm32f10x_ld.s——小容量的STM32F101xx/STM32F102xx/STM32F103xx。 startup_stm32f10x_ld_vl.s——小容量的STM32F100xx。 startup_stm32f10x_md.s——中容量的STM32F101xx/STM32F102xx/STM32F103xx。 startup_stm32f10x_md_vl.s——中容量的STM32F100xx。 startup_stm32f10x_xl.s——超大容量的STM32F101xx/STM32F103xx。 对于天信通采用的开发板,当然是选择startup_stm32f10x_cl.s启动文件。 图38inc文件夹中的.h文件列表和 src文件夹中的.c文件列表 至此,CMSIS文件夹中的内容全部都介绍完了。现在,回到Libraries文件夹中,看看它的另一个子文件夹STM32F10x_StdPeriph_Driver中的内容。双击进入该文件夹,可以看到,它主要包含inc和src两个子文件夹。可以看到,inc文件夹包含一组.h文件,src文件夹包含一组.c文件,而且它们之间是互相对应的,即在inc文件夹中的每一个.h文件在src文件夹中都有一个同名的.c文件与之相对应,如图38所示。 这两个文件夹中所包含的是固件库中的核心文件,src文件夹中包含的是固件库中的源文件(src是source的简写),inc中包含的是与之对应的固件库中的头文件(inc是include的缩写),每一对源文件和头文件对应的是芯片的一个外设的相关操作函数,从文件的名称中也能大体看出。 对于Libraries文件夹就全部介绍完了。该文件夹中的许多文件,在新建工程时都会用到,相信到时大家会对它们有更深刻的理解。 最后,再回到固件库包文件夹STM32F10x_StdPeriph_Lib_V3.5.0,看看其他文件或文件夹。双击进入Project文件夹,可以看到其中包含两个子文件夹,分别是STM32F10x_StdPeriph_Examples和STM32F10x_StdPeriph_Template。对于STM32F10x_StdPeriph_Examples,顾名思义,其中存放的是ST官方提供的芯片外设固件的实例程序,这些程序对今后的学习和开发都十分重要,可以参考其中的源代码,将其修改后变为自己的代码来驱动开发板的相关外设(其实,市面上许多开发板配套的例程都参考了其中的例程源代码)。STM32F10x_StdPeriph_Template中存放的是工程模板相关的文件和文件夹,其中的许多文件在新建工程时也会用到。 STM32F10x_StdPeriph_Lib_V3.5.0中的Utilities文件夹下存放的是官方评估版的一些相关源码,可以略过。 最后,固件库包中还包含一个stm32f10x_stdperiph_lib_um.chm文件,直接打开可以看到,这是固件库的一个帮助文档,这个文档是英文的,在学习和开发过程中,经常需要查阅该文档。 视频 3.2MDK5简介 MDK是RealView MDK的简称,源自德国的Keil公司。全球有超过10万嵌入式开发工程师使用MDK,目前其最新版本为MDK5.14,该版本使用μVision5 IDE集成开发环境,是目前针对ARM处理器,尤其是CortexM内核处理器的最佳开发工具。 MDK5向后兼容MDK4和MDK3等,同时又加强了针对CortexM微控制器开发的支持,并且对传统的开发模式和界面进行了升级。MDK有两个组成部分: MDK Core和Software Packs。其中Software Packs可独立于工具链进行新芯片的支持和中间库的升级,如图39所示。 图39MDK的两个组成部分 从图39可以看出,MDK Core又分成4部分: μVision IDE with Editor(编辑器)、ARM C/C++ Compiler(编译器)、Pack Installer(包安装器)、μVision Debugger with Trace(调试跟踪器)。μVision IDE从MDK4.7版开始就加入了代码提示和语法动态检测等实用功能,相对于以往的IDE改进很大。 Software Packs(包安装器)又分为Device(芯片支持)、CMSIS(Cortex微控制器软件接口标准)和MDK Professional Middleware(中间库)3部分,通过包安装器,可以安装最新的组件,从而支持新的器件,提供新的设备驱动库以及最新例程等,加速产品开发进度。 以往版本的MDK将所有组件都包含到一个安装包里,显得太“笨重”。MDK5则与它们不同,MDK Core是一个独立的安装包,它并不包含器件支持和设备驱动等组件,但是一般都会包含CMSIS 组件,大小为350MB左右,相比MDK4.70A的超过500MB“瘦身”不少。器件支持、设备驱动、CMSIS等组件,则可以在安装完MDK5后,双击MDK5的Build Toolbar的最后一个图标调出Pack Installer,来进行各种组件的安装。 在安装完MDK5后,为了让MDK5能够支持STM32F107芯片的开发,还需要安装STM32F1的器件支持包Keil.STM32F1xx_DFP.1.0.5.pack。 图310安装MDK5的相关文件夹 3.3MDK5的安装 3.3.1MDK5的安装步骤 在MDK5文件夹中,有给大家提供的MDK5安装及注册软件以及STM32F1的器件支持包,如图310所示。 首先双击mdk514.exe,在弹出的对话框中单击Next按钮,如图311所示。 在弹出的对话框中,选中“I agree to all the terms of the preceding License Agreement”,单击Next按钮,如图312所示。 图311MDK5的安装界面(1) 图312MDK5的安装界面(2) 在弹出的对话框中,分别单击2个Browse按钮可以分别选择软件和支持包的安装路径,这里要注意的是,安装路径不能包含中文名字,选择好后单击Next按钮,如图313所示。 图313MDK5的安装界面(3) 在弹出的对话框中填写相应的姓名、公司和邮箱的信息后,单击Next按钮,如图314所示。 图314MDK5的安装界面(4) 然后,软件会进入安装过程,如图315所示。 在软件安装的最后阶段,会弹出询问是否要安装ULINK Drivers的对话框,单击“安装”按钮,如图316所示。 图315MDK5的安装界面(5) 图316MDK5的安装界面(6) 最后,单击Finish按钮,完成软件的安装,如图317所示。 图317MDK5的安装完成界面 可以看到,MDK会自动弹出Pack Installer界面,如图318所示。 图318MDK弹出的Pack Installer界面 从图318可以看出,CMSIS和MDK的中间支持包已经在MDK5.14的安装过程中安装好了。对于其他各种支持包,程序会自动去Keil的官网下载,不过这个过程可能会失败,如图319所示。 图319下载失败 单击“确定”按钮,关闭Pack Installer安装界面。所有的支持包都可以在官网下载。 对于STM32F107开发板,至少需要安装CMSIS和STM32F107的器件支持包,因为CMSIS在MDK5.14的安装过程中已经安装好了,所以无须再下载安装,只需安装STM32F107的器件支持包。这个器件支持包已经为大家准备好了,即图310中MDK文件夹中的Keil.STM32F1xx_DFP.1.0.5.pack文件,注意,这个文件只是STM32F1系列芯片的器件支持包,对其他系列的芯片不适用。 双击该文件,在弹出的对话框中,单击Next按钮,如图320所示。 图320STM32F1系列芯片器件支持包的安装界面 软件开始进入安装过程,如图321所示。 图321STM32F1系列芯片器件支持包的安装界面 最后,单击Finish按钮完成安装,如图322所示。 图322STM32F1系列芯片器件支持包的安装完成界面 3.3.2MDK5的注册 双击桌面上的Keil μVision5图标,打开MDK5软件,如图323所示。 在打开的MDK5的软件界面中,单击菜单命令File→License Management,如图324所示。 图323Keil μVision5图标 图324在MDK5的菜单栏中单击菜单命令File→License Management 在弹出的对话框中,可以看到,现在的软件还是评估版的,如图325所示。 图325License Management对话框 使用评估版软件是有限制的——不能编译超过32KB的程序代码,所以,需要对软件进行注册后,才能正常使用。给大家提供的注册软件在图310所示的MDK5文件夹中的Keil_ARM_MDK_5.00_Keygen_serial_Crack子文件夹中,进入该文件夹,双击Keil_ARM_MDK_5.00_Keygen_serial_Crack.exe,如图326所示(如果遇到因杀毒软件而禁止运行的情况,就先关闭杀毒软件)。 在弹出的对话框中,将图325中的CID复制到相应的CID文本框中,在Target下拉列表框中选择ARM,在下面的下拉列表框中选择MDK Professional,然后单击Generate按钮,文本框中会生成一串注册码,如图327所示。 图326MDK5的相关注册软件 图327MDK5的注册软件界面 将此注册码再复制到图325中New License ID Code(LIC)文本框中,并单击Add LIC按钮,如图328所示。 图328软件注册成功 可以看到,软件注册成功。 3.4基于固件库新建工程模板 本节介绍怎样在MDK5中基于ST官方固件库来新建一个工程。首先,需要新建一个文件夹,将其命名为Template。 图329在MDK5的菜单栏中单击菜单命令 Project→New μVision Project 打开MDK5.14,单击菜单命令Project→New μVision Project,如图329所示。 在弹出的对话框中,找到刚才建立的Template文件夹,并在其中新建一个USER文件夹,然后双击USER文件夹,我们的工程就建立在其中,将其命名为Template,并单击“保存”按钮,如图330所示。 图330Template文件夹中的USER文件夹 然后,会弹出一个为工程选择设备的对话框,在其中为建立的工程选择相关类型的芯片,因为使用的开发板的芯片是STM32F107VCT6,所以选择STMicroelectronics→STM32F1 Series→STM32F107→STM32F107VC,然后单击OK按钮,如图331所示。 图331Select Device for Target对话框 注意,这里只有像前面那样安装了相关的器件支持包,才会有相应的芯片可供选择。然后,MDK5会弹出Manage RunTime Environment对话框,如图332所示。 图332Manage RunTime Environment对话框 这是MDK5新增的一个功能,在这个对话框中,可以根据实际情况添加自己需要的组件,从而便于应用程序的开发。这里不对它进行详细介绍,直接单击Cancel按钮即可。 现在,MDK5软件界面如图333所示,工程只是初步建立起了一个框架,还需要添加相关的启动文件、外设驱动文件等。 图333工程初步框架 再进入工程安装的USER文件夹中,可以看到,现在已生成两个文件夹和两个文件,如图334所示。 图334工程的USER文件夹 其中,Template.uvprojx就是我们建立的工程文件。Listings和Objects这两个文件夹是在新建工程的过程中由MDK5自动生成的,用来存放工程在以后编译过程中将会产生的中间文件。为了能够使MDK5.14新建的工程与之前版本新建的工程更好地兼容,将这两个文件夹都删除掉,我们会在后面的步骤中新建一个OBJ文件夹,用来代替它们完成相应的功能,即存放工程在编译过程中产生的中间文件。当然,也可以不删除它们,只是不会用到它们而已。 接下来,在工程的Template文件夹下,新建3个与USER文件夹同一级的文件夹,分别将它们命名为CORE、OBJ和FWLIB,如图335所示。 图335工程的Template文件夹 我们知道,OBJ将被用来存放工程在编译过程中产生的中间文件; CORE被用来存放工程的核心文件和启动文件; 顾名思义,FWLIB被用来存放ST官方提供的库函数文件。此外,USER除了存放Template工程文件,还会被用来存放主函数文件main.c以及其他相关文件等。 下面将ST官方固件库中新建工程时用到的相关文件分别复制到上面的4个文件夹中。 图336Template工程目录下的 FWLIB子文件夹 首先,找到ST官方固件库包STM32F10x_StdPeriph_Lib_V3.5.0,定位到STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver,在该文件夹下可以看到有两个子文件夹inc和src,将它们复制到Template工程目录下的FWLIB子文件夹中,如图336所示。 然后,将固件库包STM32F10x_StdPeriph_Lib_V3.5.0定位到STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport,将该文件夹下的两个文件core_cm3.c和core_cm3.h复制到Template工程目录下的CORE子文件夹中,再将固件库包定位到STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm,将该文件夹下的startup_stm32f10x_cl.s文件也复制到Template工程目录下的CORE子文件夹中,如图337所示,这里选择startup_stm32f10x_cl.s文件,是为了对应开发板的STM32F107芯片。 接下来,再将固件库包定位到STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x,将该文件夹下的stm32f10x.h、system_stm32f10x.c和system_stm32f10x.h这3个文件复制到Template工程目录下的USER子文件夹中,最后,将固件库包定位到STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template,将该文件夹下的main.c、stm32f10x_conf.h、stm32f10x_it.c和stm32f10x_it.h这4个文件复制到Template工程目录下的USER子文件夹中,system_stm32f10x.c文件因为刚刚已经复制过了,所以无须再复制,如图338所示。 在将STM32固件库包中的相关文件复制到Template工程目录下的几个子文件夹后,还需要将它们添加到Template工程中。 图337Template工程目录下的CORE子文件夹 图338Template工程目录下的USER子文件夹 在MDK5软件界面中左侧的Project窗口中(如果没有出现,可以通过单击菜单命令View→Project Window调出),右击Target1,在弹出的快捷菜单中选择Manage Project Items命令,或直接单击菜单栏的图标,在弹出的对话框中,在Project Targets一栏,将Target1更名为Template,使之与我们的工程名相同; 在Groups一栏,将Source Group1删除,并添加3个文件夹CORE、FWLIB和USER,然后单击OK按钮,如图339所示。 图339Manage Project Items对话框 现在,在MDK5软件界面左侧的Project框中,就可以看到刚才修改和添加的文件夹,如图340所示。 然后,再次用刚才的方法进入Manage Project Items对话框,将相关文件添加到Template工程的CORE、FWLIB和USER这3个子文件夹中。 首先,在Groups一栏中选择CORE子文件夹,并在Files一栏的下面单击Add Files按钮,在弹出的对话框中找到CORE子文件夹(默认在Template文件夹中寻找),然后选中该文件夹下的core_cm3.c和startup_stm32f10x_cl.s文件(注意,这里因为有.s文件,所以需在文件类型下拉列表中选择All Files),最后单击Add按钮,如图341所示。 图340Template工程目录结构 图341向工程的CORE子文件夹添加文件 然后,单击Close按钮关闭此对话框,在Manage Project Items对话框中的Files一栏可以看到这两个文件已被添加到CORE子文件夹中,如图342所示。 图342相关文件已被添加到工程的CORE子文件夹中 用相同的方法,将相关文件添加到FWLIB和USER这两个子文件夹中。 在Manage Project Items对话框中的Groups一栏中,选择FWLIB子文件夹,然后单击Add Files按钮,在弹出的对话框中,找到FWLIB子文件夹,因为添加的是.c文件而不是.h文件,所以,再单击进入FWLIB文件夹下的src子文件夹,然后,按Ctrl+A快捷键,选中所有的文件,并单击Add按钮,将它们全部添加到FWLIB子文件夹中,分别如图343和图344所示。 图343向工程的FWLIB子文件夹中添加文件 图344相关文件已被添加到工程的FWLIB子文件夹中 在图343中,因为要添加的文件全部都是.c文件,所以文件类型可以默认选择为C Source file。需要注意的是,在实际开发过程中,一般是用到哪个外设,才向FWLIB子文件夹添加这个外设相关的.c文件,以免工程太大,编译起来太慢,这里是为了讲解需要才将它们一次性全部加进来。 最后,用相同的方法将Template工程的USER子文件夹下的main.c、stm32f10x_it.c和system_stm32f10x.c文件添加到Template工程的USER子文件夹下,并单击OK按钮,如图345所示。 图345将相关文件添加到USER子文件夹中 在MDK5界面左侧的Project框中,可以看到各文件都被相应地添加到Template文件夹下的CORE、FWLIB和USER 3个子文件夹中,如图346所示。 图346Template工程目录结构 下面生成工程。在生成之前,首先应当选择工程在生成过程中产生的中间文件存放的位置。在MDK5的工具栏上单击图标(也可选择菜单命令Project→Options for Target ‘Template’),如图347所示。 图347工程选项图标 在弹出的对话框中,在最顶部的标签列表中选择Output,然后单击Select Folder for Objects按钮,在弹出的对话框中,选择存放位置为Template工程目录下的OBJ子文件夹,然后单击OK按钮,回到Options for Target ‘Template’对话框,再次单击OK按钮,如图348所示。 图348选择生成工程的中间文件存放的目录 单击工具栏的图标(也可以选择菜单命令Project→Build Target),如图349所示。试着生成工程。 图349Build Target图标 可以看到,在MDK5下方的Build Output框中出现了许多错误信息,如图350所示。 图350Build Output框 这是因为,还没有将头文件的路径包含到工程中,也就是说,需要告诉MDK工程所使用到的每一个头文件的具体路径,否则MDK不会自动去寻找。 现在再次单击图标,在弹出的对话框中,选择C/C++标签,然后单击下方Include Paths文本框后边的“…”按钮,如图351所示。 图351Options for Target ‘Template’ 在弹出的对话框中,添加工程中用到的头文件的具体路径,在Template工程目录中共有3个子文件夹,分别是CORE、FWLIB\inc和USER,将它们添加进来,单击OK按钮,如图352所示。 图352添加头文件的路径 这里需要注意的是,必须添加包含头文件的最后一级文件夹,因为MDK只会进入我们添加的某个文件夹的当前这一级去寻找头文件,而不会进入该文件夹的子文件夹中去寻找,例如,FWLIB文件夹下的inc子文件夹下包含工程要用到的头文件,那么必须添加FWLIB/inc而非FWLIB。 因为3.5版本的库函数在配置和选择外设的时候是通过宏定义完成的,所以需要配置一个全局的宏定义变量。因此,在如图351所示的Options for Target ‘Template’对话框中,在上方Preprocessor Symbols下的Define文本框中输入“STM32F10X_CL,USE_STDPERIPH_DRIVER”,单击OK按钮,如图353所示。 图353输入预处理器宏定义 注意,这两个宏之间是逗号而不是句号。此外,STM32F10X_CL对应的是STM32F107芯片,如果是其他类型的芯片,则需进行相应修改。 现在,再次尝试生成工程,可以看到,还是出现了一个错误,如图354所示。 图354工程生成过程中报错 stm32_eval.h是意法半导体公司提供的几种测试评估样板相关的文件,这里用不到它,也没有包含它,所以会报错。可以将下面一段代码复制到main.c文件中。 #include "stm32f10x.h" void Delay(u32 count) { u32 i = 0; while(i++ < count); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_SetBits(GPIOE, GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14); while(1) { GPIO_ResetBits(GPIOE, GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14); Delay(3000000); GPIO_SetBits(GPIOE, GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14); Delay(3000000); } } 然后再次生成工程,这次可以发现,工程生成成功,如图355所示。 图355工程生成成功 3.5程序的下载和调试 在建立完一个工程并编写好相应的程序后,就需要将程序下载到开发板中来观察运行结果。MDK提供了强大的程序仿真功能,可以让程序在MDK中仿真运行或仿真调试。此外,也可以通过JLINK仿真器将程序下载到开发板中来对其进行硬件调试。 视频 3.5.1程序的下载 天信通STM32F107开发板共有3种程序下载的方式,分别为通过串口下载、通过USB下载和通过JLINK仿真器下载。 1. 串口下载 通过串口下载程序需要使用ST官方提供的Flash Loader Demonstrator软件,首先需要安装此软件,安装文件在Flash_Loader_Demonstrator文件夹中,安装步骤非常简单,只需要保留默认设置操作,安装完成后,在“开始”→“所有程序”→STMicroelectronics→Flash Loader Demonstrator中就可以看到该软件,如图356所示。 图356Flash Loader Demonstrator软件 下面介绍怎样用Flash Loader Demonstrator软件通过串口给开发板下载程序,操作步骤如下: (1) 完成硬件方面的连接。先通过串口线或USB转串口线(接开发板的RS232接口)将开发板和PC连接起来,再通过跳线帽将开发板的串口下载跳线端子J4短接,最后通过5V电源适配器(不要用USB线)给开发板供电,如果一切正常,开发板电源指示灯D6会亮。 (2) 在“开始”→“所有程序”→STMicroelectronics→Flash Loader Demonstrator中打开Flash Loader Demo软件,会出现如图357所示的串口参数设置界面,在界面中设置相应的串口参数。其中,Port Name(即COM口)需要根据实际情况来进行设置(可在PC的设备管理器的端口中查看,本例中为COM3),其他串口参数可以按照图357进行设置,其中,Baud Rate(即波特率)一般设为115200bps,Timeout(超时时间)一般设为5s。 图357串口参数设置界面 (3) 按下开发板上的RESET按键(即S5键),然后松开,此时开发板就进入了串口下载模式,并等待着PC的连接,现在单击图357中的Next按钮,如果连接成功,则会出现如图358所示的连接成功界面; 如果连接不成功,则会弹出相应的提示对话框,需要根据提示重新进行连接。 图358连接成功界面 (4) 如果连接成功,则在如图358所示的连接成功界面中单击Next按钮,会出现如图359所示的设备选择界面,在设备选择界面的Target后面选择STM32_Connectivityline_256K,并单击Next按钮。 图359设备选择界面 (5) 在出现的如图360所示的操作选择界面中,可选择进行相关程序的擦除、下载、上传、Flash保护的使能/失能以及选项字节配置等操作。这里主要介绍程序下载操作。在如图360所示的操作选择界面中,选中Download to device单选按钮,然后单击Download form file文本框右面的“…”按钮,选择要下载的.hex文件,并在文本框下面选中Erase necessary page单选按钮,再选中Jump to the user program复选框,最后单击Next按钮。 图360操作选择界面 下面具体说明以上的操作。 在单击Download form file文本框右面的“…”按钮选择要下载的.hex文件时,会弹出如图361所示的对话框,需要将“查找范围”定位到要下载程序的工程目录下的OBJ子文件夹,因为3.4节新建工程模板时将此文件夹作为存放编译过程中所产生中间文件的位置,还需要将文件类型选择为hex Files,然后选择之前在编译过程中生成的Template.hex文件,并单击“打开”按钮。 图361选择文件对话框 需要注意的是,在之前编译工程的时候,必须在工程选项的Output选项卡中选中Creat HEX File复选框,如图362所示,否则不会生成.hex文件。 图362工程选项对话框 Download form file文本框下面有3个选项,其中,如果选择Erase necessary page,则在向开发板下载程序的过程中会首先擦除开发板主控芯片Flash中需要擦除的数据; 如果选择No Erase,则在下载过程中不会擦除Flash中的数据; 如果选择Global Erase,则在下载过程中会首先擦除Flash中所有的数据。很显然,应当选择Erase necessary page。因为如果选择No Erase,则下载完一次程序后Flash中可能还存有以前残留的数据没有被覆盖掉; 如果选择Global Erase,则每次下载程序都需要将Flash中的数据全部擦除一次,不仅没有必要,而且会减少Flash的使用寿命。这里需要说明的是,如果在如图360所示的操作选择页面中,先选中了Erase单选按钮将Flash中的相关数据擦除掉,则这里可以选择No Erase。 最后,选中Jump to the user program复选框,会使程序在下载完成后,不需要从开发板的J4端子拿下跳线帽并且再按下RESET按键就可以直接在开发板中运行,在程序下载完成后还可以直接返回如图357所示的串口参数下载界面重新开始下一次的程序下载。 (6) 如果一切正常,会出现程序下载成功的界面,如图363所示。 图363程序下载成功界面 然后,程序开始在开发板中运行。对于在3.4节中建立的工程,其程序的运行结果是: LED灯D2、D3、D4和D5大约以200ms的间隔不停地闪烁。 如果单击图363中的Back按钮,则会出现如图357所示的串口参数设置的界面,可以重新开始下一次的程序下载; 若单击Close按钮,则关闭软件。 2. USB下载 通过USB下载程序需要使用ST官方提供的DfuSe Demonstration软件,首先需要安装此软件,安装文件在um0412_DfuSe_Demo_V3.0文件夹下面。 安装步骤非常简单,只需要保留默认设置进行操作,安装完成后,在“开始”→“所有程序”→STMicroelectronics→DfuSe中可以看到该软件,如图364所示。 图364DfuSe Demonstration软件 下面介绍怎样用DfuSe Demonstration软件通过USB给开发板下载程序,具体操作步骤如下: (1) 完成硬件方面的连接。先通过Mini USB线(接开发板的Mini USB接口)将开发板和PC连接起来,再通过跳线帽将开发板的串口下载跳线端子J4短接,最后通过5V电源适配器(或USB线)给开发板供电,如果一切正常,开发板电源指示灯D6会亮,PC的Windows Update会自动给开发板的STM主控芯片安装DFU模式下的驱动,安装好后,可以在设备管理器的“通用串行总线控制器”下看到相关选项,如图365所示。 图365STM芯片的USB驱动选项 如果PC没有自动安装此驱动,则可以通过手动的方式对其进行安装,驱动文件在安装DfuSe Demonstration软件的根目录下的其中一个名为Driver的子文件夹下,具体路径为: C:\Program Files (x86)\STMicroelectronics\Software\DfuSe\Driver(选择默认路径安装),如图366所示,其中,32位机选择x86文件夹,64位机选择x64文件夹。 图366STM芯片在DFU模式下驱动的安装文件的目录 (2) 通过“开始”→“所有程序”→STMicroelectronics→DfuSe→DfuSe Demonstration菜单命令,打开DfuSe Demonstration软件,软件界面如图367所示。 图367DfuSe Demonstration软件界面 通过这个软件,可以将一个工程的.dfu类型的目标文件下载到开发板中,但通过MDK生成的一般都是.hex类型的目标文件,怎样将.hex类型的文件转化为.dfu类型的文件呢?其实,在安装DfuSe Demonstration软件的时候,ST公司已经给大家提供了相关的软件,就是如图364所示的DFU File Manager。 (3) 通过“开始”→“所有程序”→STMicroelectronics→DfuSe→DFU File Manager菜单命令,打开DFU File Manager软件,因为要通过一个.hex文件生成一个.dfu文件,所以在弹出的对话框中选择“I want to GENERATE a DFU file from S19, HEX or Binary”,然后单击OK按钮,如图368所示。 图368DFU File ManagerWant to do对话框 在弹出的对话框中,单击“S19 or Hex...”按钮,如图369所示。 图369DFU File ManagerGeneration对话框 在弹出的对话框中,“文件类型”选择hex Files,然后找到3.4节新建工程目录下的OBJ子文件夹,选择Template.hex文件,单击“打开”按钮,如图370所示。 图370查找文件对话框 然后在图369中单击Generate按钮,在弹出的对话框中选择要生成的.dfu文件的名字和要存放的位置,选择文件名为Generate.dfu,存放在OBJ文件夹下,然后单击“保存”按钮,如图371所示。 图371选择生成的.dfu文件的名字和存放路径 如果弹出如图372所示的对话框,则表明相关的.dfu文件成功生成。 图372.dfu文件成功生成 (4) 现在再回到如图367 所示的DfuSe Demonstration软件界面,单击下面的Choose按钮,在弹出的对话框中选择刚才生成的.dfu文件,然后单击Upgrade按钮,并在弹出的对话框中单击“是”按钮,如图373所示。如果一切顺利,会显示如图374所示的Upgrade successful的界面。 图373Upgrade界面 图374Upgrade successful界面 现在,将开发板J4端子的跳线帽取下,并按下开发板的RESET按键,可以看到,程序开始在开发板中运行,LED灯D2、D3、D4和D5大约以200ms 的间隔不停地闪烁。 3. JLINK下载 前面分别介绍了如何通过串口和USB来给开发板下载程序。除了这两种下载方式外,还可以通过JLINK仿真器来给开发板下载程序。下面以JLINK V8仿真器为例,介绍怎样通过JLINK仿真器来给开发板下载程序,JLINK V8仿真器及其相关数据连接线如图375所示。 图375JLINK V8仿真器及其相关数据连接线 首先,需要安装JLINK仿真器的驱动程序。将JLINK仿真器通过其USB端的数据连接线连接到PC,如果PC连接到Internet,那么PC会自动给JLINK仿真器安装相关的驱动程序,安装好后,在设备管理器的通用串行总线控制器下可以看到JLINK仿真器的驱动选项,如图376所示。 图376JLINK仿真器的驱动图标 操作步骤如下: (1) 通过JLINK仿真器及其相关数据连接线将开发板和PC连接起来(JLINK仿真器的JTAG一端的数据连接线连接到开发板的JTAG接口,即J16),通过5V电源适配器给开发板供电,如果一切正常,那么开发板的电源指示灯D6会亮。 (2) 用MDK打开相关的工程文件,单击工具栏上的图标,打开Options for Target对话框,选择Debug选项卡,然后选中Use单选按钮,并在其对应的下拉列表框中选择JLINK/JTRACE Cortex,如图377所示。 图377Debug选项卡设置 (3) 在弹出的对话框中,选择Debug选项卡(默认选项),可以看到JLINK仿真器的相关信息,然后在下面的“ort:”下拉列表框中选择SW,在Max下拉列表框中选择10MHz,并单击“确定”按钮,如图378所示。“ort:”对应的是JLINK的下载模式。注意,JLINK V8仿真器支持JTAG和SWD两种下载/调试模式,同时STM32也支持这两种模式,但因为SWD只需要占用两根I/O口线,JTAG模式则需要占用太多的I/O口线,所以,这里选择用SWD模式。Max对应的是下载/调试的最大时钟频率,可以通过单击它下面的Auto Clk按钮来对其自动进行设置,这里一般设置为10MHz即可。注意,如果USB数据线性能比较差,那么这里可能会出问题,可以尝试通过设置更低的最大时钟频率来解决此问题。 图378JLINK模式设置 (4) 回到Options for Target 'Template'对话框中,选择Utilities选项卡,并在它下面选中Use Debug Driver复选框,表示选择JLINK来给开发板的Flash编程,然后单击Settings按钮,如图379所示。 图379Utilities选项卡设置 在弹出的如图380所示的Flash编程算法设置对话框中,MDK在一般情况下会根据新建工程时选择的器件类型,自动设置Flash的编程算法,因为选择的是STM32F107VCT6,Flash容量是256KB,所以在Programming Algorithm下面的列表中,默认会出现容量为256K的STM32F10x Connectivity Line Flash的算法,如果没有出现,则需要单击下面的Add按钮,在弹出的对话框中选择合适的算法手动进行添加。然后,选中Reset and Run复选框,这样通过JLINK下载完程序后,程序会自动在开发板中运行。最后,单击“确定”按钮,回到Options for Target对话框中,再单击OK按钮,就完成了JLINK下载需要的所有设置。 图380Flash编程算法设置 (5) 在MDK的工具栏中单击Download图标,如图381所示,经过一段下载过程后,在MDK的Build Output窗口中会显示下载成功,如图382所示。 图381Download图标 图382通过JLINK下载成功 需要注意的是,用JLINK下载程序时,开发板的串口跳线端子J4无须用跳线帽连接,如果用跳线帽连接了,则在下载完成后,程序不会自动在开发板中运行,这时,只需取下跳线帽,然后按下RESET按键即可。 视频 3.5.2程序的调试 在将程序下载到开发板后,程序开始在开发板中运行。但其运行结果不一定会像我们期望的那样,这可能是因为编写的程序有问题,要想快速找到问题所在,尤其是在大型程序中,就需要对程序进行调试。调试方法有两种: 通过MDK的软件仿真调试和通过JLINK的硬件实际调试。 MDK的一个强大之处就在于它为程序提供了强大的软件仿真调试功能,通过软件仿真调试,可以观察程序模拟运行的整个过程,并在此过程中观察硬件相关的许多寄存器中的值的变化,通过这种方式,不必频繁地向开发板下载程序就能发现程序的问题,这在一定程度上延长了开发板主控芯片Flash的使用寿命(STM32芯片Flash的使用寿命一般在10000次读写操作左右)。但是,软件仿真调试毕竟不是万能的,许多问题必须通过硬件实际调试才能够发现。 但MDK目前只支持对STM32F103系列芯片的软件仿真调试,对其他系列的芯片,则不支持或只是部分支持,主要存在的问题是: PC和SP不能被自动装载,存储器不能被访问,中断服务程序不能被执行或触发,外设寄存器不能被读或写等。要解决上述问题,需要进行相应的设置和操作,这里不对其进行详述。 下面介绍怎样用JLINK对程序进行硬件的实际调试。 用MDK打开3.4节建立的工程文件,在进行调试之前,还需要进行相关的设置。在工具栏上单击图标,打开Options for Target 'Template'对话框,选择Target选项卡,确认芯片类型是否正确,如图383所示。 图383Target选项卡 然后在Options for Target 'Template'对话框中选择Debug选项卡,在它的下面选中Use单选按钮,并在其对应的下拉列表框中选择JLINK/JTRACE Cortex,这里与用JLINK下载时的设置相同,接着选中Run to main()复选框,然后在下方的两个Dialog DLL文本框中分别输入DARMSTM.DLL和TARMSTM.DLL,在两个Parameter文本框中都输入pSTM32F107VC,最后单击OK按钮,如图384所示。选中Run to main()复选框,则在对程序进行调试时,程序指针开始会跳过startup_stm 32f10x_cl.s启动文件中的相关代码而直接指向main()函数的起始处,否则,程序指针会指向startup_stm32f10x_cl.s启动文件的Reset_Handler处。两个Dialog DLL和两个Parameter的设置,则用于支持STM32F107VC的软硬件仿真,即可以通过单击MDK菜单栏的Peripherals图标,在弹出的相关外设的对话框中观察程序运行的结果。 图384Debug选项卡 接下来,单击MDK工具栏上的调试图标,对程序进行调试(在对程序进行调试前不要忘记先编译工程),如图385所示。 图385调试图标 可以看到,MDK的工具栏中出现了一行新的用于调试操作的图标,将鼠标指针置于这些图标之上,可以看到对这些图标所对应操作的简单说明,程序指针指向main()函数的起始处,如图386所示。 图386进入调试模式 接着将这行用于调试操作的图标单独提取出来,如图387所示。 图387Debug工具条 下面对这些图标进行详细介绍: 图标表示Reset(Reset the CPU),即复位,单击该图标将使程序指针指向整个程序的起始处,即startup_stm32f10x_cl.s启动文件的Reset_Handler处(进入如图376所示的调试模式时,程序指针指向main()函数的起始处,是由于之前在如图374所示的Options for Target 'Template'对话框中选中了Run to main()复选框)。这相当于按下开发板上的RESET按键,实现了一次硬件复位操作。 图标表示Run(Start code execution),即运行,单击该图标将使程序在开发板中全速运行。 图标表示Stop(Stop code execution),即停止运行,单击该图标将使程序停止运行,程序指针指向下一条将要执行的语句。 图标表示Step(Step one line),即执行一行,单击该图标,如果程序指针当前指向的行没有函数调用语句,那么将一次性执行完这一行的所有语句,然后程序指针会指向下一行的第一条语句; 如果程序指针当前指向的行有函数调用语句,那么程序指针将会进入该行第一个被调用的函数中,并指向该函数的第一条语句,对于一行有多个函数调用语句的情况,持续单击该图标,将会在执行完第一个被调用函数的所有语句之后,再进入后面被调用的函数。注意,以上描述考虑了一行有多条语句的情况,对于一行只有一条语句的情况当然也是适用的。在一般情况下,程序中一行只有一条语句,尤其是对于函数调用语句。 图标表示Step Over(Step over the current line),即执行过当前这一行,单击该图标,不管程序指针当前指向的行有没有函数调用语句,都将一次性执行完该行的所有语句,然后程序指针指向下一行的第一条语句。对于当前行没有函数调用语句的情况,它与图标作用相同。对于当前行有函数调用语句的情况,它会将所有函数调用的过程都分别当作一条语句来执行,而不会分别进入各个被调用的函数中,并且会一次性执行完当前行的所有语句。注意,程序中一行一般只有一条语句。 图标表示Step Out(Step out of the current function),即执行出去,它与图标相对应,它们往往结合使用。单击图标使程序指针进入某个被调用的函数中,单击图标将使程序从该函数中程序指针当前指向的语句处一次性一直执行到函数结尾处,然后程序指针会指向调用该函数语句的下一条语句。 图标表示Run to Cursor Line(Run to the current cursor line),即执行到光标当前所在的行,单击该图标,将使程序从程序指针当前指向的语句处一直执行到光标当前所在行的上一条语句,程序指针会指向光标当前所在的行的第一条语句。 图标表示Dissemble Window(Show or hide the Dissemble Window),即汇编窗口,单击该图标,可以打开(或关闭)汇编窗口,查看相应的汇编程序。 图标表示Call Stack Window(Show or hide the Call Stack Window),即调用堆栈窗口,单击该图标,可以打开(或关闭)调用堆栈窗口,查看被调用的堆栈。 图标表示Watch Window(Show or hide the Watch Window),即观察窗口,单击该图标,可以打开(或关闭)观察窗口,通过该窗口可以观察到需要观察的程序中的变量。 图标表示Memory Window(Show or hide the Memory Window),即内存窗口,单击该图标,可以打开(或关闭)内存窗口,通过该窗口可以观察到需要观察的内存中的数据。 图标表示Serial Window(Show or hide the Serial Window),即串口输出窗口,单击该图标,可以打开(或关闭)串口输出窗口,通过该窗口可以观察到需要观察的串口输出的数据。 图标表示Logic Analysis Window(Show or hide the Logic Analysis Window),即逻辑分析窗口,单击该图标,可以打开(或关闭)逻辑分析窗口,通过在该窗口中单击Setup按钮,可加入一些需要观察的I/O口,在程序调试的过程中,可以非常直观地观察这些I/O口的电平状态。 图标表示System Viewer Window(Show or hide the System Viewer Window),即系统监视器窗口,单击该图标,可以打开(或关闭)系统监视器窗口,通过该窗口可以观察系统的各种特殊功能寄存器中的值。 图388添加/删除断点图标 此外,还可以通过在程序中设置断点的方式,来帮助我们调试程序,这需要通过单击工具栏上的图标,如图388所示。添加断点后,当程序运行到断点处时,就会停止运行。 下面结合程序来具体介绍对这些操作的应用。 首先,单击Debug工具条中的图标,打开观察窗口Watch1,然后在Name一列输入GPIO_InitStructure,它是程序中的一个变量的名称,也可以直接右击程序中的该变量,选择Add ‘GPIO_InitStructure’ to…→Watch1命令,可以看到,在窗口中会显示出该变量的值和类型,因为GPIO_InitStructure是一个结构体类型的变量,所以可以在窗口中单击它左边的小加号,查看其成员变量,如图389所示。 图389观察窗口 然后,将光标置于程序的第16行,然后通过单击工具栏上的图标给程序在这一行添加一个断点(也可以通过右击该行或在该行最左边的灰色区域单击的方式来添加),如图390所示。 图390添加断点 注意,显示行号可以通过以下操作: 单击MDK工具栏的Edit→Configuration菜单命令,在弹出的对话框中选择Edit选项卡(默认选项),然后在对话框中左下方的C/C++ Files区域中,选中Show Line Numbers复选框,如图391所示。 图391Configuration对话框 通过该对话框可以设置程序中文本的字体、大小、颜色等,还可以设置文本的编码格式、Tab键的空格数、关键字等,这样可以方便大家更好地编写程序。 在图390中,程序第16行最左边的灰色区域会出现一个红色的实心圆点,表示该行已添加了一个断点,如果再次单击该行最左边的灰色区域,则该实心圆点会消失,表明删除了该断点。注意,红色实心圆点左边有一个浅蓝色的小三角,表示光标位于该行。 单击Debug工具栏中的图标,程序开始运行,并停止在我们添加的断点处,如图392所示。 图392程序停止在断点处 注意,这时在观察窗口Watch1中,可以看到变量GPIO_InitStructure的3个成员变量的值发生了变化,它们的区域底色也变为深绿色以作为提示,如图393所示。 图393观察窗口 现在,大略浏览如图392所示的main()函数中的第11~15行的代码。初学者可能现在还不能理解这几行代码的具体含义,但是有一定C语言基础的读者应该能大体看出,这几行代码的作用是: 定义了一个GPIO_InitTypeDef结构体类型的变量GPIO_InitStructure,然后给它的3个成员变量GPIO_Pin、GPIO_Mode和GPIO_Speed赋值,所以在图393中,这3个成员变量的值分别由如图389所示的3个0变为了赋值后的结果。 通过这种方法,可以观察程序中各个变量的值的变化,如果想将某个变量从观察窗口的列表中删除,可以右击该变量,选择Remove Watch命令。 在Debug工具栏中单击图标,选择GPIO→GPIOE选项,如图394所示。 图394选择GPIO→GPIOE选项 在MDK的右侧出现了一个名为GPIOE的窗口,其中列出了与GPIOE相关的7个寄存器,如图395所示。 图395GPIOE相关寄存器窗口(1) 单击Debug工具栏中的图标,单步执行图392中的第16行语句,可以发现,GPIOE窗口中有些寄存器的值发生了变化,如图396所示。 图396GPIOE相关寄存器窗口(2) 再次单击Debug工具栏中的图标,单步执行图392中的第17行语句,可以发现,GPIOE窗口中的值又有改变,如图397所示。 图397GPIOE相关寄存器窗口(3) 然后,继续不断地单击Debug工具栏中的图标,可以发现,程序在图392中程序的第19~25行之间循环反复地执行,而GPIOE相关寄存器中的值也在图396和图397之间不断地变化,这实际上也对应了程序的运行结果——4个LED灯不停地闪烁。当大家学习完本书第3篇中的5.4.1节后,再来看以上的程序调试过程,应该会有更深刻的理解。 本章小结 本章对软件开发环境——MDK5做了讲解,对开发环境的安装、新建工程、下载调试做了详细的说明。首先介绍ST官方固件库; 接着介绍MDK5软件及其安装和注册的过程; 然后介绍怎样基于ST官方固件库来新建一个工程模板; 最后介绍针对开发板下载程序的3种方式,以及在MDK5中对程序进行调试的方法。