范文一:proteus与keil仿真
proteus 与 keil 联调仿真
一 . 仿真的必要性
在具体的工程实践中,单片机试验硬件投入较大,如果方案有误会浪费较多的时间和经费。 Proteus 软件可以仿真 解决了方案可行性问题,和 Protel 一样绘制硬件原理图并实现硬件调试,再与 Keil 编程软件进行联调,实现对控制方 案的验证。
二 .Keil 和 proteus 简介
Keil 是德国 Keil 公司开发的单片机编译器,是目前最好的 51单片机开发工具之一,可以用来编译 C 源代码和汇编 源程序、连接和重定位目标文件和库文件、创建 HEX 文件、调试目标程序等,是一种集成化的文件管理编译环境。在 Proteus 中,可以直接与 Keil 编程软件进行联调,进而实现对所设计电路的验证。
Proteus VSM提供了简单的文本编辑器,用它作为源程序的编辑环境。对于不同系列的单片机, VSM 均提供了相应 的编译器,使用时可根据单片机的型号和语言要求来选取。
编译器有以下几种:
lASEM51(51系列单片机编译器 ) ;
lASM11(Motorola单片机编译器 ) ;
lAVRASM(Atmel AVR系列单片机编译器 ) ;
lAVRASM32(Atmel AVR系列单片机编译器 ) ;
lMPASM(PIC单片机编译器 ) ;
lMPASMSWIN(PIC单片机编译器 ) 。
三 .Keil 和 proteus 仿真前的准备
1. Keil安装与设置
第一步:
第二步:
第三步
安装完后把这两个文件放到 \Keil\C51\LIB下面,这个文件有浮点运算
第四步:
第五步:
第六步:
第七步:这一步是关键,
第八步:新建工程
第九步:Atmel 公司的 89C51
第十步:新建一个 Text1文本文件,保存,保存为 *.c型的 c 语言文件
第十一步:
第十二步:
第十三步:这样 *.c源文件就加到了工件里了。
到此完成了 Keil 安装与设置
2. proteus安装与设置
第一步:
安装 /破解 /汉化 说明
1). 安装 Proteus 7.5 SP3 Setup.exe,若提示 No LICENCE 选择压缩包中
2). 安装完毕后运行
3). 如需汉化 , 将压缩包中
4).Protues 与 Keil 联调方法见压缩包中
第二步:
第四步:画原理图
第五步:
第六步:这样就可以仿真了。注意 R1的大小决定 LED-RED 的亮度。
范文二:keil uvision4教程
第 4章 keil uvision4教程
本章主要内容:
●Keil C51的简介
●Keil uvision4的安装
●Keil uvision4的创建应用程序
本章主要从简单介绍了 Keil C51,以及 Keil uvision4的安装和如何在 Keil 中创建应用 程序。
4.1 Keil C51的简介
Keil C51是美国 Keil Software公司出品的 51系列兼容单片机 C 语言软件开发系统,与 汇编相比, C 语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。 Keil 提供了包括 C 编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内 的完整开发方案,通过一个集成开发环境(μVision )将这些部分组合在一起。运行 Keil 软件需要 WIN98、 NT 、 WIN2000、 WINXP 等操作系统。 如果你使用 C 语言编程, 那么 Keil 几乎就是你的不二之选, 即使不使用 C 语言而仅用汇编语言编程, 其方便易用的集成环境、 强大的软件仿真调试工具也会令你事半功倍。
使用汇编语言或 C 语言要使用编译器,以便把写好的程序编译为机器码,才能把 HEX 可执行文件写入单片机内。 KEIL uVISION是众多单片机应用开发软件中最优秀的软件之一, 它支持众多不同公司的 MCS51架构的芯片, 甚至 ARM , 它集编辑, 编译, 仿真等于一体, 它的界面和常用的微软 VC++的界面相似,界面友好,易学易用,在调试程序,软件仿真方 面也有很强大的功能。因此很多开发 51应用的工程师或普通的单片机爱好者,都对它十分 喜欢。
2009年 2月发布 Keil μVision4, Keil μVision4引入灵活的窗口管理系统,使开发 人员能够使用多台监视器,并提供了视觉上的表面对窗口位置的完全控制的任何地方。 新的用户界面可以更好地利用屏幕空间和更有效地组织多个窗口,提供一个整洁, 高效 的环境来开发应用程序。 新版本支持更多最新的 ARM 芯片, 还添加了一些其他新功能。 2011年 3月 ARM 公司发布最新集成开发环境 RealView MDK 开发工具中集成了 最新版本的 Keil μVision4,其 编译器 、调试工具实现与 ARM 器件的最完美匹配。
μVision4在 μVision3的成功经验的基础上增加了:
●System Viewer (系统查看程序 ) 窗口, 提供了设备外围寄存器信息, 这些信 息可以在 System Viewer窗口内部直接更改。
●Debug Restore Views (调试恢复视图 ) 允许保存多个窗口布局,为程序分析 迅速选择最适合的调试视图。
●Multi-Project Workspace(多项目工作空间 ) 为处理多个并存的项目提供了 简化的方法,如引导加载程序和应用程序。
●扩展了 Device Simulation(设备仿真 ) 功能以支持许多新设备, 如 Luminary 、
NXP 和东芝生产的基于 ARM Cortex-M3处理器的 MCU ; Atmel SAM7/9;及新的 8051衍生品,如 Infineon XC88x和 SiLABS 8051Fxx。
支持许多 debug adapter interfaces(调试适配器接口 ) , 包括 ADI miDAS Link、 Atmel SAM-ICE、 Infineon DAS和 ST-Link 。
3.2 Keil uvision4的安装
第 1步:运行安装程序
第 2步:完成安装过程
第 3步:双击运行刚安装完毕的 Keil uVision4,进入 Keil uVision4的集成编 辑环境
第 4步:单击选择菜单“Debug” -->
第 5步:(破解开始)单击选择菜单“File” -->
第 6步:运行破解软件, 将出现下面一张图的界面, 把上步复制的 CID 号黏贴到 相应位置, 其他选项如图, 然后点击“Generate”按钮, 然后复制产生的序列号, 黏贴到第 5步的下面一张图的 LIC 输入框中,然后点击右侧的 Add LIC ,即可完 成破解
3.1.1 创建应用程序
μVision 包含一个工程管理器, 它使得设计 ARM 微控制器的嵌入式应用程序更加方便。 创建应用程序,必须先创建对应的工程。为了创建一个新的工程,必须按如下步骤实现: 1.
双击图标 ,运行 μVision 。 2. 创建一个工程文件,从设备数据库中选择一个 CPU 芯片。下面以名为 test 的工程
为例创建工程文件。
单击 Project ->New...->μVision Project菜单项, μVision 4将打开一个标准对话框,输入希望 新建工程的名字即可创建一个新的工程, 建议对每个新建工程使用独立的文件夹。 例如, 这 里先建立一个新的文件夹, 然后选择这个文件夹作为新建工程的目录,
输入新建工程的名字
test , μVision 将会创建一个以 test.uvproj 为名字的新工程文件。
创建完了工程文件之后,从设备数据库中选择一个 CPU 芯片。例如,选择 AT89C52微 控制器 , 如图所示:
图 4-1选择 CPU 芯片
当创建一个新的工程时, μVision 会自动为所选择的 CPU 添加合适的启动代码,如图 9-3。
图 4-2添加启动代码
对于一些设备而言, μVision 需要用户手动地输入额外的参数。请仔细阅读这个对话框 右边的信息,因为它可能包含所选设备的额外配置要求。
3. 创建一个新的源文件,将这个源文件加载到工程中。
通过 File ->New菜单项可创建一个新的源文件。这时将打开一个空文件编辑窗口,在 这里可以输入源文件代码。当通过 File->Save As 对话框以扩展名 .C 的形式保存了这个源文 件以后, μVision 可以用彩色高亮度显示 C 语言的语法。例如,保存下面的代码到 MAIN.C 文件中。
#include #include void main(void) { SCON=0x50;//串口方式 1,允许接收 TMOD=0x20;//定时器 1 定时方式 2 TCON=0x40;//设定时器 1 开始计数 TH1=0xE8;//11.0592MHz 1200波特率 TL1=0xE8;// TI=1; TR1=1;//启动定时器 while(1) { printf( } }创建源文件以后, 就可以将这个文件添加到工程中。 μVision 提供了几种方法将源文件 添加到工程中。例如,在 Project Workspace ->Files页的文件组上点击鼠标右键,然后在弹 出的菜单中选择 Add Files菜单项, 这时将打开标准的文件对话框, 选择刚才创建的 MAIN.C 文件即完成源文件的添加。 图 3-3添加文件 4. 增加和配置 ARM 设备的启动代码。 一般来说, ARM 程序需要与目标硬件的设计配置相匹配的 CPU 初始化代码。 当创建工 程的时候, μVision 要求添加与选定的 CPU 相匹配的启动代码。 根据所使用的工具链的不同, 启 动 代 码 文 件 所 在 的 文 件 夹 分 别 为 ..\ARM\Startup (针 对 Keil 开 发 工 具 链 ) , ..\ARM\GNU\Startup(针对 GNU 开发工具链 ) 和 ..\ARM\ADS\Startup(针对 ADS 开发工 具链 ) 。对于不同的微控制器来说,这些文件夹包含不同的启动代码。 Philips LPC2106的启 动代码文件为 ...\Startup\Philips\Startup.s 。为了和目标硬件相匹配,用户可能会修改这个启 动代码文件,所以工程中的启动代码文件是 Startup.s 的一个副本。 文件组 (file group)可以组织更大的工程。对于 CPU 的启动代码和其他的系统配置文件, 可以通过 Project->Manage ->Components,Environment, Books对话框创建一个单独的文件组。 使用 New (Insert)按钮创建名为 System Files的文件组。在工程窗口中,可以将 Starup.s 文件 拖放到这个新建的文件组中。 图 4-5 Components, Environment, Books 如图 4-5, 在工程中添加文件后, μVision 的工程空间窗口中将会出现所有的文件。 这个 窗口中的文件以在窗口中的排列顺序进行编译和链接。 可以通过拖放的方式移动文件的位置, 同时也可以单击目标和组改变它们的名字。 在本窗口内单击鼠标右键, 在弹出的菜单中可以 进行如下的操作: ● 设置工具选项 ● 删除文件或组 ● 将文件添加到组中 ● 打开文件 图 4-5工程空间中的文件 在工程空间中,不同的图标显示了文件和文件夹(文件组)的不同属性。如: 带箭头的文件图标表示编译和链接工程文件。 链接运行时不包含的文件不带箭头。 对于一般的文档文件这是很常见的。 然而, 在属性对话框中取消 Include in Target Build的选择,同样也可以不包含源文件。 只读文件被标志为一个钥匙。在软件版本控制系统中这样的文件是很常见的, 因为 SVCS 使这样文件的拷贝只读。 , 带有特殊选项的文件和文件夹被圆点标记。 5. 设置目标硬件的工具选项。 μVision 可以设置目标硬件的选项。 通过工具栏按钮或 Project - Options for Target菜单项 打开 Options for Target对话框,在 Target 页中设置目标硬件及所选 CPU 片上组件的参数。 下图是 LPC2106的一些参数设置。 图 4-6 Target对话框 ● Xtal ,设备的晶振 (XTAL)频率。大多数基于 ARM 的微控制器都使用片上 PLL 产生 CPU 时钟。 所以, 一般情况下 CPU 的时钟与 XTAL 的频率是不同的。 仔 细查阅硬件手册以确定合适的 XTAL 的值。 ● Use On-Chip ROM/RAM,仅针对 Keil ARM 工具。选择这两个多选框以 后, 将设置 Keil LA链接器 /装载器。 对于 GNU 和 ADS , 是通过链接器控制文件实 现的。 ● External Memory 仅针对 Keil ARM工具。 指定目标硬件的外部存储区域。 RAM 用于存取变量,而 ROM 用于存储常量和程序代码 (一般为 EPROM 或 Flash 存储器 ) 。这些信息用于配置 Keil LA 链接器 /装载器。对于 GNU 和 ADS ,是通过 链接器控制文件实现的。 对于 GNU 和 ARM ADS/RealView工具链来说, 链接器的配置是通过链接器控制文件实 现的。这个文件指定了 ARM 目标硬件的存储配置。预配置的链接器控制文件在文件 夹 ..\ARM\GNU或 ..\ARM\ADS 中。为了与目标硬件相匹配,用户可能会修改链接器控制文 件, 所以工程中的那个文件是预配置的连接控制文件的一个副本。 这个文件可以通过 Project - Options for Target对话框的 Linker 页添加到工程中。 图 4-7Linker 对话框 ● Enable Garbage Collection, 允许未使用输入段的垃圾回收。 在不支持这个选项的目 标中,它会被忽略。这个选项和 '-r' 不一样,也不能在动态链接时使用。 ● Do not use Standard System Startup Files,链接时不使用标准的系统启动文件。如果 不选中这个选项时标准的系统库会被正常使用。 ● Do not use StandardSystem Libraries ,链接时不使用标准的系统库文件。仅使用 C 和 GCC 库。 ● Text Start ,指定输出文件代码段的起始地址。必须是一个单精度的十六进制整数。 为了保持和其他链接器的兼容性,必须忽略这个十六进制值前面的 0X 。 ● Data Start,指定输出文件数据段的起始地址。必须是一个单精度的十六进制整数。 为了保持和其他链接器的兼容性,必须忽略这个十六进制值前面的 0X 。 ● BSS Start, 指定输出文件 BSS 段的起始地址。 必须是一个单精度的十六进制整数。 为了保持和其他链接器的兼容性,必须忽略这个十六进制值前面的 0X 。 ● Linker Script File Include Libraries,指定在编译时导入的库。 ● Include Paths,向路径列表中添加路径,在这些路径中 LD 将搜索库文件和 ld 控制 脚本。 在任何时候都可以使用这个选项。 这些文件夹是按照它们在列表中的顺序搜 索,且是在默认文件之前搜索的。 ● Misc controls ,使用 Misc 控制框指定链接器需要的命令,这些命令没有单独的对 话框控制。 ● Linker control string,这个文本框显示了当前链接器的命令行。 6. 编译工程,创建能烧写到 PROM 中的十六进制文件。 一般来说,在新建一个应用程序的时候 Options ->Target 页中的所有的工具和属性都要 配置。单击 Build Target 工具栏 按钮将编译所有的源文件,链接应用程序。当编译有语 法错误的应用程序时, μVision 将在 Output Window ->Build窗口中显示错误和警告信息。单 击这些信息行, μVision 将会定位到相应的源代码处。 图 4-8编译错误提示 如果编译成功的话, 源文件编译成功产生应用程序以后就可开始调试了, 然后创建可下 载到 EPROM 或软件仿真器中运行的 Intel 十六进制文件。 当 Options for Target ->Output页中 的 Create HEX file多选框被选中后, μVision 每次编译后都会生成十六进制文件。 FLASH Fill Byte 、 Start 和 End 文本框中的值被 OH166使用工具用来产生十六进制文件。在 Run User Program #1文本框中指定程序时,当编译过程完成后就可以启动 PROM 编程器了。 图 4-9编译生成十六进制文件选项 现在,可以修改工程中已存在的代码或向工程中添加代码了。 Build Target 工具按钮仅 编译已修改过或新建的源文件,产生可执行的文件。 μVision 有一个文件的依赖列表,它记 录了每一个源文件所包含的头文件。 甚至工具选项都保存在文件依赖列表中, 所以只有在需 要的时候 μVision 才会重新编译这些源文件。 通过使用不同的工程目标 (project target), μVision 可以使单个工程生成几个不同的程序。 开发者可能需要一个目标 (target)作为测试, 另一个目标作为应用程序的发布版。 在同一个工 程文件中, 每一个目标都具有各自的工具设置, 通过快捷键 Alt+F7, 即可调出图 9-7 进行多 目标工具设置。 文件组 (file group)可以将工程中相关的的文件组织在一起。这样有利于将一组文件组织 到一个功能块中或区分一个开发团队中的工程师。 在以前的一些例程中, 已经以文件组的形 式将 CPU 相关文件同其他源文件隔离开。在 μVision 中,使用这种技术很容易管理具有几 百个文件的工程。 在 Project ->Manage->Components, Enviroment and books->Project Components 对话框中 可以创建工程目标和文件组。 在以前的一些例程中, 已经使用了这个对话框添加系统配置文 件。下图显示了一个例程的工程结构。 图 4-10设定多个工程目标 在编译工具栏可以快速的改变当前编译的工程目标。 图 4-11快速改变编译目标 在编译工具栏中, 按钮可以弹出工程选项,其中包含多个标签页,如图 9-10。 各个标签页简要介绍如下: 9.3.2 测试应用程序 μVision 调试器可以测试用 GNU 或 ARM ADS/RealView工具链开发的应用程序。 μVision 调试器提供了两种操作模式,这两种模式可以在 Options for Target ->Debug 对话框中选择。 图 4-12 Debug设定 ●单选框 Use Simulator用于选择 μVision 的软件仿真器作为调试器, 它可以 在没有目标硬件的情况下仿真 ARM7微控制器的大部分功能。在目标硬件设计好 之前,可以用这个软件仿真器调试嵌入式应用程序。 μVision 可以仿真许多片上外 设, 例如串口, 外部 I/O和定时器。 当为目标 (target)从设备数据库中选择一个 CPU 时,可仿真的片上外围就已经确定了。 ●? 使用高级 GDI 驱动器,例如 Keil ULINK2 ARM调试器提供了一个与目 标硬件相连接的接口。 使用高级 GDI 接口可以直接将 μVision 调试器与硬件仿真器、 嵌入式 ICE(片上调试系统 ) 相连,例如带 USB-JTAG 接口的 Keil ULINK2仿真器。 μVision 调试器可以仿真高达 4GB 的存储空间, 这些存储空间可以被映射为读、 写或可 执行等访问权限。 μVision 软件仿真器可以捕获和报告非法的存储访问。 除了存储映射以外, 软件仿真器同时可以仿真各种基于 ARM 微控制器的片上外围设备。在创建工程时,从设备 数据库中选择的 CPU 就决定了可以用软件仿真器仿真的片上外围设备。关于从设备数据库 中选择设备的信息请参考运行 μVision 及创建工程文件。 可以调试菜单选择和显示片上外围 设备,同时通过相应的对话框改变这些外围设备的特征。 图 4-12中,对话框选项解释如下: Use Simulator 选择 μVision 的软件仿真器作为调试工具。 Use ULINK2 ARM7 Debugger 选择高级的 GDI 驱动器和调试硬件相连。 Keil ULINK2 ARM7调试器可以用带 USB-JTAG 接口的 Keil ULINK2仿真器和目标板相 连。同时也有现存的第三方 μVision 驱动器。 Settings 打开已选的高级 GDI 驱动器的配置对话框。 Other dialog options 对软件仿真器和高级 GDI 会话可用。 Load Application atStartup 选中该选项以后,在启动 μVision 调试器时自动加载目标应用程 序。 Go till main () 当启动调试器时开始执行程序,直到 main()函数处停止。 Initialization File 调试程序时作为命令行输入的指定文件。 Breakpoints 从前一个调试会话中恢复断点设置。 Toolbox 从前一个调试会话中恢复工具框按钮。 Watchpoints & PA 从前一个调试会话中恢复观察点和性能分析仪的设置。 Memory Display 从前一个调试会话中恢复内存显示设置。 CPU DLL , Driver DLL , Parameter 配置内部 μVision 调试 DLL 。 这些设置来源于设备数据库。 用户 能修改 DLL 或 DLL 的参数。 在工具栏上,点击按钮 可以启动调试模式。或者可以通过 Debug ->Start/Stop Debug Session 菜单项启动 μVision 的调试模式。根据 Options for Target -> Debug 页配置的不同, μVision 将加载应用程序、运行启动代码。关于 μVision 调试器配置的详细信息请参考设置 调试选项。 μVision 可以保存编辑窗口的布局以及回复最后调试时的窗口布局。如果程序停 止执行, μVision 将打开一个显示源代码文本的编辑窗口或在反汇编窗口中显示相应的 CPU 指令。下一个可执行的语句被标记为黄色箭头。 在调试的时, 大多数编辑器的功能都是可用的。 例如, 可以使用查找命令或纠正程序错 误。应用程序的源代码文本在同一窗口中显示。 μVision 的调试模式和编辑模式有如下的不 同: ●调试菜单和调试命令是可用的。调试窗口将在以后讨论。 ●工程结构和工具参数是不能被修改的。所有的编译命令不可用。 在 Debug 模式下, 按钮表示执行应用程序, 按钮表示重置 CPU , 按钮表示 停止代码执行, 按钮表示设置断点, 按钮可以使断点生效或失效, 按钮表示关闭 所有断点, 和 按钮表示调试下一行代码,调试状态的界面如图 9-13。 图 4-13 Debug模式界面 下面以 HELLO 工程为例介绍 μVision 调试器的使用简要过程。 HELLO 例程可在 \Keil\C51\Examples\Hello中找到,这个例程用来通过串口打印出字符 串“ Hello World” 。在 HELLO.C 中包含整个程序的源代码。 这个小程序可以用来验证应用程序的编译、 链接、 以及调试。 可以使用工程文件在 DOS 命令行、或使用批处理文件、或 μVision 环境中执行这些操作。 μVision 还可以为此例程仿 真目标硬件而不需要实际上的 CPU 。 在编译链接完成后,就可使用 μVision 的调试器进行调试了。选择 Debug 菜单里的选 项 Start/Stop Debug Session 或者点击工具栏里的对应图标进入调试模式。 μVision 将会初始 化调试器并启动程序运行到主函数。如图 4-14。 图 4-14 Hello.c运行结果 Keil 单片机开发中除必要的硬件外,同样离不开软件,我们写的汇编语言源程序要变为 CPU 可以执行的机器码有两种方法,一种是手工汇编,另一种是机器汇编,目前已极少使用手工 汇编的方法了。机器汇编是通过汇编软件将源程序变为机器码,用于 MCS-51单片机的汇编 软件有早期的 A51,随着单片机开发技术的不断发展,从普遍使用汇编语言到逐渐使用高级 语言开发,单片机的开发软件也在不断发展, Keil 软件是目前最流行开发 MCS-51系列单片 机的软件,这从近年来各仿真机厂商纷纷宣布全面支持 Keil 即可看出。 Keil 提供了包括 C 编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通 过一个集成开发环境(uVision )将这些部份组合在一起。运行 Keil 软件需要 Pentium 或以 上的 CPU , 16MB 或更多 RAM 、 20M 以上空闲的硬盘空间、 WIN98、 NT 、 WIN2000、 WINXP 等操作系统。掌握这一软件的使用对于使用 51系列单片机的爱好者来说是十分必要的,如 果你使用 C 语言编程,那么 Keil 几乎就是你的不二之选(目前在国内你只能买到该软件、 而你买的仿真机也很可能只支持该软件) ,即使不使用 C 语言而仅用汇编语言编程,其方便 易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。 我们将通过一些实例来学习 Keil 软件的使用,在这一部份我们将学习如何输入源程序, 建立工程、对工程进行详细的设置,以及如何将源程序变为目标代码。图 1所示电路图使用 89C51单片机作为主芯片,这种单片机性属于 MCS-51系列,其内部有 4K 的 FLASH ROM,可以反复擦写,非常适于做实验。 89C51的 P1引脚上接 8个发光二极管, P3.2~P3.4引脚上 接 4个按钮开关,我们的第一个任务是让接在 P1引脚上的发光二极管依次循环点亮。 Keil 首先启动 Keil 软件的集成开发环境,这里假设读者已正确安装了该软件,可以从桌面 上直接双击 uVision 的图标以启动该软件。 UVison 启动后, 程序窗口的左边有一个工程管理窗口, 该窗口有 3个标签, 分别是 Files 、 Regs 、和 Books ,这三个标签页分别显示当前项目的文件结构、 CPU 的寄存器及部份特殊 功能寄存器的值(调试时才出现)和所选 CPU 的附加说明文件,如果是第一次启动 Keil , 那么这三个标签页全是空的。 使用菜单“ File->New”或者点击工具栏的新建文件按 钮,即可在项目窗口的右侧打开一个新的文本编缉窗口, 在该窗口中输入以下汇编语言源程序,例 1: MOV A , #0FEH MAIN:MOV P1, A RL A LCALL DELAY AJMP MAIN DELAY:MOV R7,#255 D1:MOV R6,#255 DJNZ R6,$图 1简单的键盘、显示板 DJNZ R7,D1 RET END 保存该文件,注意必须加上扩展名(汇编语言源程序一般用 asm 或 a51为扩展名) ,这 里假定将文件保存为 exam1.asm 。 需要说明的是,源文件就是一般的文本文件,不一定使用 Keil 软件编写,可以使用任意 文本编缉器编写,而且, Keil 的编缉器对汉字的支持不好,建议使用 UltraEdit 之类的编缉 软件进行源程序的输入。 在项目开发中,并不是仅有一个源程序就行了,还要为这个项目选择 CPU (Keil 支持数 百种 CPU ,而这些 CPU 的特性并不完全相同) ,确定编译、汇编、连接的参数,指定调试 的方式,有一些项目还会有多个文件组成等,为管理和使用方便, Keil 使用工程(Project ) 这一概念,将这些参数设置和所需的所有文件都加在一个工程中, 只能对工程而不能对单一 的源程序进行编译(汇编)和连接等操作,下面我们就一步一步地来建立工程。 点击“ Project->New Project… ”菜单,出现一个对话框,要求给将要建立的工程起一个 名字,你可以在编缉框中输入一个名字 (设为 exam1) , 不需要扩展名。 点击 “保 存”按钮,出现第二个对话框,如图 2 所示, 这个对话框要求选择目标 CPU (即 你所用芯片的型号) , Keil 支持的 CPU 很多,我们选择 Atmel 公司的 89C51芯 片。点击 ATMEL 前面的“ +”号,展开 该层,点击其中的 89C51,然后再点击 “确定”按钮,回到主界面,此时,在 工程窗口的文件页中,出现了“ Target 1” ,前面有“ +”号,点击“ +”号展开, 可以看到下一层的“ Source Group1” , 这 时的工程还是一个空的工程,里面什么 文件也没有,需要手动把刚才编写好的 源程序加入,点击“ Source Group1”使 其反白显示,然后,点击鼠标右键,出现一个下 拉菜单,如图 3所示。选中其中的“ Add file to Group”Source Group1” ,出现一个对话框,要求 寻找源文件,注意,该对话框下面的“文件类型” 默认为 C source file(*.c),也就是以 C 为扩展名 的文件,而我们的文件是以 asm 为扩展名的, 所以在列表框中找不到 exam1.asm ,要将文件类 型改掉,点击对话框中“文件类型”后的下拉列 表,找到并选中“ Asm Source File(*.a51,*.asm), 这样,在列表框中就可以找到 exam1.asm 文件 了。 双击 exam1.asm 文件,将文件加入项目,注 图 2选择目标 CPU 图 3加入文件 意,在文件加入项目后,该对话框并不消 失,等待继续加入其它文件,但初学时常 会误认为操作没有成功而再次双击同一文 件,这时会出现如图 4所示的对话框,提 示你所选文件已在列表中, 此时应点击 “确 定” ,返回前一对话框,然后点击“ Close ” 即可返回主界面,返回后,点击“ Source Group 1” 前的加号,会发现 exam1.asm 文 件已在其中。双击文件名,即打开该源程 序。 工程建立好以后,还要对工程进行进一步的设置,以满足要求。 首先点击左边 Project 窗口的 Target 1, 然后使用菜单 “ Project->Option for target ‘target1’ ” 即出现对工程设置的对话框,这个对话框可谓非常复杂,共有 8个页面,要全部搞清可不容 易,好在绝大部份设置项取默认值就行了。 设置对话框中的 Target 页面,如 图 5所示, Xtal 后面的数值是晶振频 率值,默认值是所选目标 CPU 的最高 可 用 频 率 值 , 对 于 我 们 所 选 的 AT89C51而言是 24M ,该数值与最终 产生的目标代码无关,仅用于软件模 拟调试时显示程序执行时间。正确设 置该数值可使显示时间与实际所用时 间一致,一般将其设置成与你的硬件 所用晶振频率相同,如果没必要了解程序执行的时间,也可以不设,这里设置为 12。 Memory Model 用于设置 RAM 使用情况,有三个选择项, Small 是所有变量都在单片 机的内部 RAM 中; Compact 是可以使用一页外部扩展 RAM ,而 Larget 则是可以使用全部 外部的扩展 RAM 。 Code Model用于设置 ROM 空间的使用,同样也有三个选择项,即 Small 模式,只用低于 2K 的程序空间; Compact 模式,单个函数的代码量不能超过 2K ,整个程序 可以使用 64K 程序空间; Larget 模式,可用全部 64K 空间。 Use on-chip ROM选择项,确认 是否仅使用片内 ROM (注意:选中该项并不会影响最终生成的目标代码量) ; Operating 项 是操作系统选择, Keil 提供了两种操作系统:Rtx tiny和 Rtx full ,关于操作系统是另外一个 很大的话题了,通常我们不使用任何操作系统,即使用该项的默认值:None (不使用任何 操作系统) ; Off Chip Code memory 用以确定系统扩展 ROM 的地址范围, Off Chip xData memory 组用于确定系统扩展 RAM 的地址范围,这些选择项必须根据所用硬件来决定,由 于该例是单片应用,未进行任何扩展,所以均不重新选择,按默认值设置。 设置对话框中的 OutPut 页面,如图 6所示,这里面也有多个选择项,其中 Creat Hex file用于生成可执行代码文件(可以用编程器写入单片机芯片的 HEX 格式文件,文件的扩展名 为 .HEX ) ,默认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项,这一点是 初学者易疏忽的,在此特别提醒注意。选中 Debug information 将会产生调试信息,这些信 息用于调试,如果需要对程序进行调试,应当选中该项。 Browse information 是产生浏览信 息,该信息可以用菜单 view->Browse来查看,这里取默认值。按钮“ Select Folder for objects ” 图 4 重复加入文件的错误 图 5对目标进行设置 是用来选择最终的目标文件所在的 文件夹,默认是与工程文件在同一 个文件夹中。 Name of Executable用 于 指定 最终 生成 的 目标 文件 的名 字,默认与工程的名字相同,这两 项一般不需要更改。 工程设置对话框中的其它各页 面与 C51编译选项、 A51的汇编选 项、 BL51连接器的连接选项等用法 有关,这里均取默认值,不作任何 修改。以下仅对一些有关页面中常用的选项作一个简单介绍。 Listing 标签页用于调整生成的列表文件选项。在汇编或编译完成后将产生(*.lst)的列 表文件,在连接完成后也将产生(*.m51)的列表文件,该页用于对列表文件的内容和形式 进行细致的调节,其中比较常用的选项是“ C Compile Listing”下的“ Assamble Code”项, 选中该项可以在列表文件中生成 C 语言源程序所对应的汇编代码。 C51标签页用于对 Keil 的 C51编译器的编译过程进行控制,其中比较常用的是“ Code Optimization ”组,如图 7所示,该组中 Level 是优化等级, C51在对源程序进行编译时,可 以对代码多至 9级优化, 默认使用 第 8级,一般不必修改,如果在编 译中出现一些问题, 可以降低优化 级别试一试。 Emphasis 是选择编 译优先方式, 第一项是代码量优化 (最终生成的代码量小) ;第二项 是速度优先 (最终生成的代码速度 快) ;第三项是缺省。默认的是速 度优先,可根据需要更改。 设置完成后按确认返回主界面,工程文件建立、设置完毕。 在设置好工程后,即可进行编译、连接。选择菜单 Project->Build target,对当前工程进 行连接,如果当前文件已修改,软件会先对该文件进行编译,然后再连接以产生目标代码; 如果选择 Rebuild All target files 将会 对当前工程中的所有文件重新进行编 译然后再连接,确保最终生产的目标 代码是最新的,而 Translate …. 项则仅 对该文件进行编译,不进行连接。 以上操作也可以通过工具栏按钮直 接进行。图 8是有关编译、设置的工具 栏按钮,从左到右分别是:编译、编译 连接、全部重建、停止编译和对工程进 行设置。 编译过程中的信息将出现在输出窗 口中的 Build 页中,如果源程序中有语 图 8 有关编译、连接、项目设置的工具条 图 7 代码生成控制 图 6 对输出进行控制 图 9正确编译、连接之后的结果 法错误,会有错误报告出现,双击该行,可以定位到出错的位置,对源程序反复修改之后, 最终会得到如图 9所示的结果,提示获得了名为 exam1.hex 的文件,该文件即可被编程器读 入并写到芯片中,同时还产生了一些其它相关的文件,可被用于 Keil 的仿真与调试,这时 可以进入下一步调试的工作。 Keil 上一讲中我们学习了如何建立工程、汇编、连接工程,并获得目标代码,但是做到这一 步仅仅代表你的源程序没有语法错误,至于源程序中存在着的其它错误,必须通过调试才能 发现并解决,事实上,除了极简单的程序以外,绝大部份的程序都要通过反复调试才能得到 正确的结果,因此,调试是软件开发中重要的一个环节,这一讲将介绍常用的调试命令、利 用在线汇编、各种设置断点进行程序调试的方法,并通过实例介绍这些方法的使用。 在对工程成功地进行汇编、 连接以后, 按 Ctrl+F5或者使用菜单 Debug->Start/Stop Debug Session 即可进入调试状态, Keil 内建了一个仿真 CPU 用来模拟执行程序,该仿真 CPU 功 能强大,可以在没有硬件和仿真机的情况下进行程序的调试,下面将要学的就是该模拟调试 功能。不过在学习之前必须明确,模拟毕竟只是模拟,与真实的硬件执行程序肯定还是有区 别的,其中最明显的就是时序,软件模拟是不可能和真实的硬件具有相同的时序的,具体的 表现就是程序执行的速度和各人使用的计算机有关,计算机性能越好,运行速度越快。 进入调试状态后,界面与编缉状态相比有明显的变化, Debug 菜单项中原来不能用的命 令现在已可以使用了,工具栏会多出一个用于运行和调试的工具条,如图 1所示, Debug 菜 单上的大部份命令可以在此找到对应的快捷按钮,从左到右依次是复位、运行、暂停、单步、 过程单步、执行完当前子程序、运行到当前行、下一状态、打开跟踪、观察跟踪、反汇编窗 口、观察窗口、代码作用范围分析、 1#串行窗口、内存窗口、性能分析、工具按钮等命令。 学习程序调试,必须明 确两个重要的概念,即单步 执行与全速运行。全速执行 是指一行程序执行完以后紧 接着执行下一行程序,中间不停止,这样程序执行的速度很 快,并可以看到该段程序执行的总体效果,即最终结果正确 还是错误,但如果程序有错,则难以确认错误出现在哪些程 序行。单步执行是每次执行一行程序,执行完该行程序以后 即停止,等待命令执行下一行程序,此时可以观察该行程序 执行完以后得到的结果,是否与我们写该行程序所想要得到 的结果相同,借此可以找到程序中问题所在。程序调试中, 这两种运行方式都要用到。 使用菜单 STEP 或相应的命令按钮或使用快捷键 F11可 以单步执行程序,使用菜单 STEP OVER或功能键 F10可以 以过程单步形式执行命令,所谓过程单步,是指将汇编语言 中的子程序或高级语言中的函数作为一个语句来全速执行。 按下 F11键,可以看到源程序窗口的左边出现了一个黄色调试箭头,指向源程序的第一 行,如图 2所示。每按一次 F11,即执行该箭头所指程序行,然后箭头指向下一行,当箭头 指向 LCALL DELAY 行时,再次按下 F11,会发现,箭头指向了延时子程序 DELAY 的第 一行。不断按 F11键,即可逐步执行延时子程序。 通过单步执行程序,可以找出一些问题的所在,但是仅依靠单步执行来查错有时是困难 的,或虽能查出错误但效率很低,为此必须辅之以其它的方法,如本例中的延时程序是通过 图 1 调试工具条 图 2调试窗口 将 D2:DJNZ R6,D2这一行程序执行六万多次来达到延时的目的,如果用按 F11六万多 次的方法来执行完该程序行,显然不合适,为此,可以采取以下一些方法,第一,用鼠标在 子程序的最后一行(ret )点一下,把光标定位于该行,然后用菜单 Debug->Run to Cursor line (执行到光标所在行) ,即可全速执行完黄色箭头与光标之间的程序行。第二,在进入该子 程序后,使用菜单 Debug->Step Out of Current Function(单步执行到该函数外) ,使用该命令 后,即全速执行完调试光标所在的子程序或子函数并指向主程序中的下一行程序(这里是 JMP LOOP 行) 。第三种方法,在开始调试的,按 F10而非 F11,程序也将单步执行,不同 的是,执行到 lcall delay 行时,按下 F10键,调试光标不进入子程序的内部,而是全速 执行完该子程序,然后直接指向下一行“ JMP LOOP ” 。灵活应用这几种方法,可以大大提 高查错的效率。 在进入 Keil 的调试环境以后,如果发现程序有错,可以直接对源程序进行修改,但是 要使修改后的代码起作用,必须先退出调试环境,重新进行编译、连接后再次进入调试,如 果只是需要对某些程序行进行测试,或仅需对源程序进行临时的修改,这样的过程未免有些 麻烦,为此 Keil 软件提供了在线汇编的能力,将光标定位于需要修改的程序行上,用菜单 Debug->Inline Assambly… 即可出现如 图 3的对话框,在 Enter New 后面的 编缉框内直接输入需更改的程序语 句,输入完后键入回车将自动指向下 一条语句,可以继续修改,如果不再 需要修改,可以点击右上角的关闭按 钮关闭窗口。 程序调试时,一些程序行必须满足一定的条件才能被执行到(如程序中某变量达到一定 的值、按键被按下、串口接收到数据、有中断产生等) ,这些条件往往是异步发生或难以预 先设定的,这类问题使用单步执行的方法是很难调试的,这时就要使用到程序调试中的另一 种非常重要的方法——断点设置。 断点设置的方法有多种, 常用的是在某一程序行设置断点, 设置好断点后可以全速运行程序,一旦执行到该程序行即停止,可在此观察有关变量值,以 确定问题所在。在程序行设置 /移除断点的方法是将光标定位于需要设置断点的程序行,使 用菜单 Debug->Insert/Remove BreakPoint设置或移除断点(也可以用鼠标在该行双击实现同 样的功能) ; Debug->Enable/Disable Breakpoint 是开启或暂停光标所在行的断点功能; Debug->Disable All Breakpoint暂停所有断点; Debug->Kill All BreakPoint清除所有的断点设 置。这些功能也可以用工具条上的快捷按钮进行设置。 除了在某程序行设置断点这一基本方法以外, Keil 软件还提供了多种设置断点的方法, 按 Debug->Breakpoints… 即出现一个对话框,该对话框用于对断点进行详细的设置,如图 4所示。 图 4中 Expression 后的编缉框内用于输入表达式, 该表达式用于确定程序停止运行的条 件,这里表达式的定义功能非常强大,涉及到 Keil 内置的一套调试语法,这里不作详细说 明,仅举若干实例,希望读者可以举一反三。 1) 在 Experssion 中键入 a==0xf7,再点击 Define 即定义了一个断点, 注意, a 后有两 个等号,意即相等。该表达式的含义是:如果 a 的值到达 0xf7 则停止程序运行。除 图 3在线汇编窗口 使用相等符号之外,还可以使用 >,>=,<><=,!=(不等于) ,&(两值按位与)="" ,&&(两="">=,!=(不等于)> 2) 在 Experssion 后中键入 Delay 再点击 Define ,其含义是如果执行标号为 Delay 的行 则中断。 3) 在 Experssion 后中键入 Delay , 按 Count 后的微调按钮,将值调到 3,其意义是 当第三次执行到 Delay 时才停止程序运 行。 4) 在 Experssion 后 键 入 Delay , 在 Command 后 键 入 printf(“SubRoutine ‘Delay’ has been Called\n”) 主程序每次 调用 Delay 程序时并不停止运行,但会 在输出窗口 Command 页输出一行字 符 , 即 SubRoutine ‘Delay’ has been Called 。其中“ \n”的用途是回车换行, 使窗口输出的字符整齐。 5) 设置断点前先在输出窗口的 Command 页中键入 DEFINE int I,然后在断点设 置时同 4) ,但是 Command 后键入 printf(“SubRoutine ‘Delay’ has been Called %d times\n”,++I),则主程序每次调用 Delay 时将会在 Command 窗口输出该字符及被调 用的次数,如 SubRoutine ‘Delay’ has been Called 10 times。 对于使用 C 源程序语言的调试,表达式中可以直接使用变量名,但必须要注意,设置 时只能使用全局变量名和调试箭头所指模块中的局部变量名。 为进行程序的调试,我们首先给源程序制造一个错误,将延时子程序的第三行“ DJNZ R6,$”后的 $改为 D1,然后重新编译,由于程序中并无语法错误,所以编译时不会有任何出 错提示,但由于转移目的地出错,所以子程序将陷入无限循环中。 进入调试状态后,按 F10以过程单步的形式执行程序,当执行到 LCALL DELAY行时, 程序不能继续往下执行,同时发现调试工具条上的 Halt 按钮变成了红色,说明程序在此不 断地执行着,而我们预期这一行程序执行完后将停止,这个结果与预期不同,可以看出所调 用的子程序出了差错。为查明出错原因,按 Halt 按钮使程序停止执行,然后按 RST 按钮使 程序复位,再次按下 F10单步执行,但在执行到 LCALL DELAY 行时,改按 F11键跟踪到 子程序内部(如果按下 F11键没有反应,请在源程序窗口中用鼠标点一下) ,单步执行程序, 可以发现在执行到“ DJNZ R6,D1”行时,程序不断地从这一行转移到上一行,同时观察 左侧的寄存器的值,会发现 R6的值始终在 FFH 和 FEH 之间变化,不会减小,而我们的预 期是 R6的值不断减小,减到 0后往下执行,因此这个结果与预期不符,通过这样的观察, 不难发现问题是因为标号写错而产生的,发现问题即可以修改,为了验证即将进行的修改是 否正确,可以先使用在线汇编功能测试一下。把光标定位于程序行“ DJNZ R6,D1” ,打开 在线汇编的对话框,将程序改为“ DJNZ R7,0EH ” ,即转回本条指令所在行继续执行,其中 0EH 是本条指令在程序存储器中的位置,这个值可以通过在线汇编窗口看到,如图 3所示。 然后关闭窗口,再进行调试,发现程序能够正确地执行了,这说明修改是正确的。注意,这 时候的源程序并没有修改,此时应该退出调试程序,将源程序更改过来,并重新编译连接, 以获得正确的目标代码。 图 4断点设置对话框 Keil 程序调试窗口 上一讲中我们学习了几种常用的程序调试方法,这一讲中将介绍 Keil 提供各种窗口如 输出窗口、观察窗口、存储器窗口、反汇编窗口、串行窗口等的用途,以及这些窗口的使用 方法,并通过实例介绍这些窗口在调试中的使用。 一、程序调试时的常用窗口 Keil 软件在调试程序时提供了多个窗口,主要包括输出窗口(Output Windows) 、观察 窗口 (Watch&Call Statck Windows) 、 存储器窗口 (Memory Window) 、 反汇编窗口 (Dissambly Window )串行窗口(Serial Window)等。进入调试模式后,可以通过菜单 View 下的相应命 令打开或关闭这些窗口。 图 1是输出窗口、 观察窗口和存储器窗口, 各窗口的大小可以使用鼠标调整。 进入调试 程序后,输出窗口自动切换到 Command 页。该页用于输入调试命令和输出调试信息。对于 初学者,可以暂不学习调试命令的使用方法。 1、存储器窗口 存储器窗口中可以显示系统中各种内存中的值,通过在 Address 后的编缉框内输入“字 母:数字”即可显示相应内存值,其中字母可以是 C 、 D 、 I 、 X ,分别代表代码存储空间、 直接寻址的片内存储空间、间接寻址的片内存储空间、扩展的外部 RAM 空间,数字代表想 要查看的地址。例如输入 D :0即可观察到地址 0开始的片内 RAM 单元值、键入 C :0即 可显示从 0开始的 ROM 单元中的值,即查看程序的二进制代码。该窗口的显示值可以以各 种形式显示,如十进制、十六进制、字符型等,改变显示方式的方法是点鼠标右键,在弹出 的快捷菜单中选择, 该菜单用分隔条分成三部份, 其中第一部份与第二部份的三个选项为同 一级别,选中第一部份的任一选项,内 容将以整数形式显示,而选中第二部份 的 Ascii 项则将以字符型式显示,选中 Float 项将相邻四字节组成的浮点数形 式显示、 选中 Double 项则将相邻 8字节 组成双精度形式显示。第一部份又有多 个选择项, 其中 Decimal 项是一个开关, 如果选中该项,则窗口中的值将以十进 制的形式显示,否则按默认的十六进制 方式显示。 Unsigned 和 Signed 后分别有 三个选项:Char 、 Int 、 Long ,分别代表以单字节方式显示、将相邻双字节组成整型数方式 图 1 调试窗口(命令窗口、存储器窗口、观察窗口) 图 2 存储器数值各种方式显示选择 显示、将相邻四字节组成长整型方式显示,而 Unsigned 和 Signed 则分别代表无符号形式和 有符号形式, 究竟从哪一个单元开始的相邻单元则与你的设置有关, 以整型为例, 如果你输 入的是 I:0, 那么 00H 和 01H 单元的内容将会组成一个整型数, 而如果你输入的是 I :1, 01H 和 02H 单元的内容全组成一个整型数,以此类推。有关数据格式与 C 语言规定相同,请参 考 C 语言书籍,默认以无符号单字节方式显 示。第三部份的 Modify Memory at X:xx用于 更改鼠标处的内存单元值, 选中该项即出现如 图 3所示的对话框, 可以在对话框内输入要修 改的内容。 2、工程窗口寄存器页 图 4是工程窗口寄存器页的内容,寄存器页包括了当前的工作寄存器组和系统寄存器, 系统寄存器组有一些是实际存在的寄存器如 A 、 B 、 DPTR 、 SP 、 PSW 等,有一些是实际中 并不存在或虽然存在却不能对其操作的如 PC 、 Status 等。每当程序中执行到对某寄存器的 操作时,该寄存器会以反色(蓝底白字)显示,用鼠标单击然后按下 F2键,即可修改该值。 3、观察窗口 观察窗口是很重要的一个窗口, 工程窗口中仅可以观察到 工作寄存器和有限的寄存器如 A 、 B 、 DPTR 等,如果需要观 察其它的寄存器的值或者在高级语言编程时需要直接观察变 量,就要借助于观察窗口了。 其它窗口将在以下的实例中介绍。 一般情况下, 我们仅在单步执行时才对变量的值的变化感 兴趣, 全速运行时, 变量的值是不变的, 只有在程序停下来之 后, 才会将这些值最新的变化反映出来, 但是, 在一些特殊场 合下我们也可能需要在全速运行时观察变量的变化, 此时可以 点击 View->Periodic Window Updata(周期更新窗口) , 确认该 项处于被选中状态, 即可在全速运行时动态地观察有关值的变 化。但是,选中该项,将会使程序模拟执行的速度变慢。 二、各种窗口在程序调试中的用途 以下通过一个高级语言程序来说明这些窗口的使用。例 2: #include sbit P1_0=P1^0; //定义 P1.0 void mDelay(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;}="">125;j++)> } void main() { unsigned int i; for(;;){ mDelay(10); //延 时 10毫秒 i++; if(i==10) { P1_0=!P1_0; i=0; } } } 这个程序的工作过程是:不断调用延时程序, 每次延时 10毫秒, 然后将变量 I 加 1, 随 后对变量 I 进行判断,如果 I 的值等于 10,那么将 P1.0取反,并将 I 清 0 ,最终的执行效果 图 4 工程窗口寄存器页 图 3存储器的值的修改 是 P1.0每 0.1S 取反一次。 输入源程序并以 exam2.c 为文件名存盘, 建立名为 exam2的项目, 将 exam2.c 加入项目, 编译、连接后按 Ctrl+F5进入调试,按 F10单步执行。注意观察窗口,其中有一个标签页为 Locals , 这一页会自动显示当前模块中的变量名及变量值。 可以看到窗口中有名为 I 的变量, 其值随着执行的次数而逐渐加大, 如果在执行到 mDelay(10)行时按 F11跟踪到 mDelay 函数 内部, 该窗口的变量自动变为 DelayTime 和 j 。 另外两个标签页 Watch #1和 Watch #2可以加 入自定义的观察变量,点击“ type F2 to edit”然后再按 F2即可输入变量,试着在 Watch #1中输入 I ,观察它的变化。在程序较复杂,变量很多的场合,这两个自定义观察窗口可以筛 选出我们自己感兴趣的变量加以观察。 观察窗口中变量的值不仅可以观察, 还可以修改, 以 该程序为例, I 须加 10次才能到 10,为快速验证是否可以正确执行到 P1_0=!P1_0行,点击 I 后面的值,再按 F2,该值即可修改,将 I 的值改到 9,再次按 F10单步执行,即可以很快 执行到 P1_0=!P1_0程序行。该窗口显示的变量值可以以十进制或十六进制形式显示,方法 是在显示窗口点右键,在快捷菜单中选择如图 5所示。 点击 View->Dissambly Window可 以打开反汇编窗口,该窗口可以显示反 汇编后的代码、源程序和相应反汇编代 码的混合代码,可以在该窗口进行在线 汇编、利用该窗口跟踪已找行的代码、 在该窗口按汇编代码的方式单步执行, 这也是一个重要的窗口。打开反汇编窗口,点击 鼠标右键, 出现快捷菜单, 如图 6所示, 其中 Mixed Mode 是以混合方式显示, Assembly Mode是以反 汇编码方式显示。 程序调试中常使用设置断点然后全速运行的 方式,在断点处可以获得各变量值,但却无法知 道程序到达断点以前究竟执行了哪些代码,而这 往往是需要了解的,为此, Keil 提供了跟踪功能, 在运行程序之前打开调试工具条上的允许跟踪代 码开关,然后全速运行程序,当程序停止运行后, 点击查看跟踪代码按钮,自动切换到反汇编窗口, 如图 6所示,其中前面标有“ -”号的行就是中断以前执行的代码,可以按窗口边的上卷按 钮向上翻查看代码执行记录。 利用工程窗口可以观察程序执行的时间, 下面我们观察一下该例中延时程序的延时时间 是否满足我们的要求,即是否确实延时 10毫秒,展开工程窗口 Regs 页中的 Sys 目录树,其 中的 Sec 项记录了从程序开始执行到当前程序流逝的秒数。点击 RST 按钮以复位程序, Sec 的值回零, 按下 F10键, 程序窗口中的黄色箭头指向 mDelay(10)行, 此时, 记录下 Sec 值为 0.00038900,然后再按 F10执行完该段程序,再次查看 Sec 的值为 0.01051200,两者相减大 约是 0.01秒,所以延时时间大致是正确的。读者可以试着将延时程序中的 unsigned int改为 unsigned char试试看时间是否仍正确。 注意, 使用这一功能的前提是在项目设置中正确设置 晶振的数值。 Keil 提供了串行窗口, 我们可以直接在串行窗口中键入字符, 该字符虽不会被显示出来, 但却能传递到仿真 CPU 中, 如果仿真 CPU 通过串行口发送字符, 那么这些字符会在串行窗 口显示出来, 用该窗口可以在没有硬件的情况下用键盘模拟串口通讯。 下面通过一个例子说 明 Keil 串行窗口的应用。该程序实现一个行编缉功能,每键入一个字母,会立即回显到窗 图 5 设定观察窗的显示方式 图 6 反汇编窗口 口中。编程的方法是通过检测 RI 是否等于 1来判断串行口是否有字符输入,如果有字符输 入,则将其送到 SBUF ,这个字符就会在串行窗口中显示出来。其中 ser_init是串行口初始 化程序,要使用串行口,必须首先对串行口进行初始化。例 3: MOV SP,#5FH ;堆栈初始化 CALL SER_INIT ; 串行口初始化 LOOP: JBC RI,NEXT ;如果串口接收到字 符,转 JMP LOOP ; 否则等待接收字符 NEXT: MOV A,SBUF ;从 SBUF 中取字符 MOV SBUF,A ; 回送到发送 SBUF 中 SEND: JBC TI,LOOP ;发送完成,转 LOOP JMP SEND ; 否则等待发送完 SER_INIT: ;中断初始化 MOV SCON,#50H ORL TMOD,#20H ORL PCON,#80H MOV TH1,#0FDH ;设定波特率 SETB TR1 ; 定时器 1开始运行 SETB REN ; 允许接收 SETB SM2 RET END 输入源程序,并建立项目,正确编译、连接,进入调试后,全速运行,点击串行窗口 1按钮,即在原源程序窗口位置出现一个空白窗口,击键,相应的字母就会出现在该窗口中。 在窗口中击鼠标右键,出现一个弹出式菜单,选择“ Ascii Mode”即以 Ascii 码的方式显示 接收到的数据; 选择 “ Hex Mode” 以十六进制码方式显示接收到的数据; 选择 “ Clear Window” 可以清除窗口中显示的内容。 由于部份 CPU 具有双串口, 故 Keil 提供了两个串行窗口, 我们选用的 89C51芯片只有 一个串行口,所以 Serial 2串行窗口不起作用。 小技巧:凡是鼠标单击然后按 F2的地方都可以用鼠标连续单击两次 (注意:不是双击) 来替代。 Keil 的辅助工具和部份高级技巧 在前面的几讲中我们介绍了工程的建立方法, 常用的调试方法, 除此之外, Keil 还提供 了一些辅助工具如外围接口、性能分析、变量来源分析、代码作用分析等,帮助我们了解程 的性能、 查找程序中的隐藏错误, 快速查看程序变量名信息等, 这一讲中将对这些功工具作 一介绍,另外还将介绍 Keil 的部份高级调试技巧。 一、 辅助工具 这部份功能并不是直接用来进行程序调试的, 但可以帮助我们进行程序的调试、 程序性 能的分析,同样是一些很有用的工具。 1、外围接口 为了能够比较直观地了解单片机中定时器、 中断、 并行端口、串行端口等常用外设的使用情况, Keil 提 供了一些外围接口对话框, 通过 Peripherals 菜单选择, 该菜单的下拉菜单内容与你建立项目时所选的 CPU 有关,如果是选择的 89C51这一类“标准”的 51机, 那么将会有 Interrupt (中断) 、 I/O Ports(并行 I/O口) 、 Serial (串行口) 、 Timer (定时 /计数器)这四个外围设 备菜单。打开这些对话框,列出了外围设备的当前使用情况,各标志位的情况等,可以在这 些对话框中直观地观察和更改各外围设备的运行情况。 下面我们通过一个简单例子看一看并行端口的外围设备对话框的使用。例 4: MOV A,#0FEH LOOP: MOV P1,A RL A CALL DELAY ; 延时 100毫秒 JMP LOOP 其中延时 100毫秒的子程序请自行编写。 编 译 、 连 接 进 入 调 试 后 , 点 击 Peripherals->I/O-Ports->Port 1打开,如图 1所示,全速运 行, 可以看到代表各位的勾在不断变化 (如果看不到变化, 请点击 View->Periodic Window Updata) ,这样可以形象地 看出程序执行的结果。 注:如果你看到的变化极快,甚至看不太清楚,那么 说明你的计算机性能好,模拟执行的速度快,你可以试着 将加长延时程序的时间以放慢速度。 模拟运行速度与实际 运行的速度无法相同是软件模拟的一个固有弱点。 点击 Peripherals->I/O-Ports->Timer0即出现图 2所示 定时 /计数器 0的外围接口界面, 可以直接选择 Mode 组中 的下拉列表以确定定时 /计数工作方式, 0-3 四种工作方式, 图 1 外围设备之并行端口 图 2 外围设备之定时器 设定定时初值等,点击选中 TR0, status 后的 stop 就变成了 run ,如果全速运行程序,此时 th0,tl0后的值也快速地开始变化 (同样要求 Periodic Window Updata处于选中状态) , 直观地 演示了定时 /计数器的工作情况(当然,由于你的程序未对此写任何代码,所以程序不会对 此定时 /计数器的工作进行处理) 。 2、性能分析 Keil 提供了一个性能分析工具, 利用该工具, 我们可以了解程序中哪些部份的执行时间 最长, 调用次数最多, 从而了解影响整个程序中执行速度的瓶颈。 下面通过一个实例来看一 看这个工具如何使用,例 5: #include sbit P1_0=P1^0; //定义 P1.0 void mDelay(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;}="" }="">125;j++)> void mDelay1(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;}="">125;j++)> } void main() { unsigned int i; for(;;){ mDelay(10); //延 时 10毫秒 i++; if(i==10) { P1_0=!P1_0; i=0; mDelay1(10);} } } 编译连接。 进入调试状态后使用菜单 View->Performance Analyzer Window, 打开性能分 析对话框, 进入该对话框后, 只有一项 unspecified , 点鼠标右键, 在快捷菜单中选择 Setup PA即打开性能分析设置对话框,对于 C 语言程序,该对话框右侧的“ Function Symbol”下的 列表框给出函数符号,双击某一符号,该符号即出现在 Define Performance Analyzer下的编 缉框中,每输入一个符号名字,点击 Define 按钮,即将该函数加入其上的分析列表框。对 于汇编语言源程序, Function Symbol下的列表框中不会出现子程序名,可以直接在编缉框 中输入子程序名,点击 Close 关闭窗口,回到性能分析窗口,此时窗口共有 4个选项。全速 执行程序, 可以看到 mDelay 和 mDelay1后出现一个蓝色指示条, 配合上面的标尺可以直观 地看出每个函数占整个执行时间的比例, 点击相应的函数名, 可以在该窗口的状态栏看到更 详细的数据,其中各项的含义如下: Min :该段程序执行所需的最短时间; Max :该段程序执行所需的最长时间; Avg :该 段程序执行所花平均时间; Total :该段程序到目前为目总共执行的时间; %:占整个执行时 间的百分比; count :被调用的次数。 本程序中, 函数 mDelay 和 mDelay1每次被调用都花费同样的时间, 看不出 Min 、 Max 、 和 Avg 的意义,实际上,由于条件的变化,某些函数执行的时间不一定是一个固定的值, 借助于这些信息,可以对程序有更详细的了解。下面将 mDelay1函数略作修改作一演示。 void mDelay1(unsigned char DelayTime) { static unsigned char k; unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(;j<> {;} } k++; } 程序中定义了一个静态变量 K , 每次调用该变量加 1, 而 j 的循环条件与 k 的大小有关, 这使每次执行该程序所花的时间不一样。编译、执行该程序,再次观察性能分析窗口,可以 看出 Min 、 Max 、 Avg 的意义。 3、变量来源浏览 该窗口用于观察程序中变量名的有关信息, 如该变量名在那一个函数中被定义、 在哪里 被调用,共出现多少次等。在 Source Browse窗口中提供了完善的管理方法,如过滤器可以 分门别类地列出各种类别的变量名,可以对这些变量按 Class (组) 、 Type (类型) 、 Space (所在空间) 、 Use (调用次数)排序,点击变量名,可以在窗口的右侧看到该变量名的更 详细的信息。 4、代码作用范围分析 在你写的程序中,有些代码可能永远不会被执行到(这是无效的代码) ,也有一些代码 必须在满足一定条件后才能被执行到, 借助于代码范围分析工具, 可以快速地了解代码的执 行情况。 进入调试后,全速运行,然后按停止按钮,停下来后,可以看到在源程序的左列有三种 颜色,灰、淡灰和绿,其中淡灰所指的行并不是可执行代码,如变量或函数定义、注释行等 等, 而灰色行是可执行但从未执行过的代码, 而绿色则是已执行过的程序行。 使用调试工具 条上的 Code Coverage Window可打开代码作用范围分析的对话框,里面有各个模块代码执 行情况的更详细的分析。 如果你发现全速运行后有一些未被执行到的代码, 那么就要仔细分 析,这些代码究竟是无效的代码还是因为条件没有满足而没有被执行到。 二、部份高级调试技巧 Keil 内置了一套调试语言, 很多高级调试技巧与此有关, 但是全面学习这套语言并不现 实, 这不是这么几期连载可以胜任的, 这里仅介绍部份较为实用的功能, 如要获得更详细的 信息,请参考 Keil 自带的帮助文件 GS51.PDF 。 1、串行窗口与实际硬件相连 Keil 的串行窗口除可以模拟串行口的输入和输出功能外还可以与 PC 机上实际的串口相 连,接受串口输入的内容,并将输出送到串口。这需要在 Keil 中进行设置。方法是首先在 输出窗口的 Command 页用 MODE 命令设置串口的工作方式,然后用 ASSIGN 命令将串行 窗口与实际的串口相关联,下面我们通过一个实例来说明如何操作。例 6: ORG 0000H JMP START ORG 3+4*8 ; 串行中断入口 JMP SER_INT START: MOV SP,#5FH ;堆栈初始化 CALL SER_INIT ; 串行口初始化 A SETB EA ; SETB ES ; JMP $ ; 主程序到此结束 SER_INT: JBC RI,NEXT ;如果串口接收到字 符,转 JMP SEND ; 否则转发送处理 NEXT: MOV A,SBUF ;从 SBUF 中取字符 MOV SBUF,A ; 回送到发送 SBUF 中 JMP OVER SEND: clr ti OVER: reti SER_INIT: ;中断初始化 MOV SCON,#50H ORL TMOD,#20H ORL PCON,#80H MOV TH1,#0FDH ;设定波特率 SETB TR1 ; 定时器 1开始运行 SETB REN ; 允许接收 SETB SM2 RET END 这个程序使用了中断方式编写串行口输入 /输出程序,它的功能是将接串行口收到的字 符回送,即再通过串行口发送出去。 正确输入源文件、建立工程、编译连接没有错后,可进行调试,使用 Keil 自带的串行 窗口测试功能是否正确,如果正确,可以进行下一步的连机试验。 为简单实用, 我们不借助于其它的硬件, 而是让 PC 机上的两个串口互换数据, 即 COM1发送 COM2接收,而 COM2发送则由 COM1接收,为此,需要做一根连接线将这两个串口 连起来,做法很简单,找两个可以插入 PC 机串口的 DIN9插座(母) ,然后用一根 3芯线将 它们连起来,连线的方法是: 2—— 3 3—— 2 5—— 5 接好线把两个插头分别插入 PC 机上的串口 1与串口 2。找一个 PC 机上的串口终端调 试软件,如串口精灵之类,运行该软件,设置好串口参数,其中串口选择 2,串口参数设置 为: 19200, n , 8, 1其含义是波特率为 19200,无奇偶校验, 8位数据, 1位停止位。 在 Keil 调试窗口的 command 页中输入: >mode com1 19200,0,8,1 >assign com1 注意两行最前面的“ >”是提示符,不要输入,第二行中的“ <”和“>”即“小于”和 “大于”符号,中间的是字母“ s ”和“ input ”的前两个字母,最后是字母“ s ”和“ output ” 的前三个字母。 第一行命令定义串口 1的波特率为 19200,无奇偶校验, 8位数据, 1位停止位。第二 行是将串口 1(com1)分配给串行窗口。 全速运行程序, 然后切换串口精灵, 开始发送, 会看到发送后的数据会立即回显到窗口 中,说明已接收到了发送过来的数据。切换到 uVison ,查看串行窗口 1,会看到这里的确接 收到了串口精灵送来的内容。 2、从端口送入信号 程序调试中如果需要有信号输入,比如数据采集类程序,需要从外界获得数据,由于 Keil 的调试完全是一个软件调试工具, 没有硬件与之相连, 所以不可能直接获得数据, 为此 必须采用一些替代的方法,例如,某电路用 P1口作为数据采集口,那么可以使用的一种方 法是利用外围接口,打开 PORT 1,用鼠标在点击相应端口位,使其变为高电平或低电平, 就能输入数据。 显然, 这种方法对于要输获得数据而不是作位处理来说太麻烦了, 另一种方 法是直接在 command 页输入 port1=数值,以下是一个小小的验证程序。例 7: LOOP: MOV A,P1 JZ NEXT MOV R0,#55H JMP LOOP NEXT: MOV R0,#0AAH JMP LOOP END 该程序从 P1口获得数据,如果 P1口的值是 0,那么就让 R0的值为 0AAH ,否则让 R0的值为 55H 。输入源程序并建立工程,进入调试后,在观察窗口加入 R0,然后全速运行程 序,注意确保 View->Periodic Window Updata处于选中状态,然后在 Command 后输入 PORT1=0回车后可以发现观察窗口中的 R0的值变成了 0AAH ,然后再输入 PORT1=1或其 它非零值,则 R0的值会变为 55H 。 同样的道理,可以用 port0、 port2、 port3分别向端口 0、 2、 3输入信号。 3、直接更改内存值 在程序运行中, 另一种输入数据的方法是直接更改相应的内存单元的值, 例如, 某数据 采集程序,使用 30H 和 31H 作为存储单元,采入的数据由这两个单元保存,那么我们更改 了 30H 和 31H 单元的值就相当于这个数据采集程序采集到了数据,这可以在内存窗口中直 接修改(参考上一讲) ,也可以通过命令进行修改,命令的形式是: _WBYTE (地址 , 数据 ) , 其 中 地 址 是 指 待 写 入 内 存 单 元 的 地 址 , 而 数 据 则 是 待 写 入 该 地 址 的 数 据 。 例 如 _WBYTE(0x30,11)会将值 11写入内存地址十六进制 30H 单元中。 Keil μVision4使用详解 zxmh6 前言 单片机开发中除必要的硬件外,同样离不开软件,我们写的汇编语言源程序要变为 CPU可以执行的机器码有两种方法,一种是手工汇编,另一种是机器汇编,目前已极少使用手工 汇编的方法了。机器汇编是通过汇编软件将源程序变为机器码,用于 MCS-51 单片机的汇编 软件有早期的 A51,随着单片机开发技术的不断发展,从普遍使用汇编语言到逐渐使用高级 语言开发,单片机的开发软件也在不断发展, Keil 软件是目前最流行开发 MCS-51系列单片 机的软件, 这从近年来各仿真机厂商纷纷宣布全面支持 Keil 即可看出。 Keil 提供了包括 C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通 过一个集成开发环境(uVision )将这些部份组合在一起。运行 Keil 软件需要 Pentium 或 以上的 CPU, 16MB或更多 RAM、 20M 以上空闲的硬盘空间、 WIN98、 NT、 WIN2000、 WINXP等操作系统。掌握这一软件的使用对于使用 51 系列单片机的爱好者来说是十分必要的,如 果你使用 C 语言编程,那么 Keil几乎就是你的不二之选(目前在国内你只能买到该软件、 而你买的仿真机也很可能只支持该软件) ,即使不使用 C 语言而仅用汇编语言编程,其方 便易用的集成环境、 强大的软件仿真调试工具也会令你事半功倍。 我们将通过一些实例来学 习 Keil软件的使用,在这一部份我们将学习如何输入源程序,建立工程、对工程进行详细 的设置,以及如何将源程序变为目标代码。图 1 所示电路图使用 AT89C51 单片机作为主芯 片,这种单片机性属于 MCS-51 系列,其内部有 4K的 FLASH ROM,可以反复擦写,非常适于 做实验。 AT89C51的 P1引脚上接 8个发光二极管, P3.2~P3.4 引脚上接 4 个按钮开关,我 们的第一个任务是让接在 P1 引脚上的发光二极管依次循环点亮。 目 录 前言 .......................................................................... 1 第一章 Keil 的配置设置 ........................................................ 3 第二章 Keil 工程文件的建立、设置与目标文件的获得 .............................. 7 第一节 Keil 工程的建立 ........................................................ 7 第二节 源文件的建立 .......................................................... 12 第三节 将源文件加到工程中并输入源程序 ........................................ 13 第四节 工程的详细设置 ........................................................ 18 第五节 编译、连接、生成目标文件 .............................................. 23 第三章 Keil的调试命令、在线汇编与断点设置 .................................... 25 第一节 常用调试命令 .......................................................... 25 第二节 在线汇编 .............................................................. 27 第三节断点设置 ............................................................... 27 第四节 实例调试 .............................................................. 29 第四章 Keil 程序调试窗口 ..................................................... 30 第一节 程序调试时的常用窗口 .................................................. 30 第二节 各种窗口在程序调试中的用途 ............................................ 32 第五章 Keil 的辅助工具和部份高级技巧 ......................................... 36 第一节 辅助工具 .............................................................. 36 第二节 部份高级调试技巧 ...................................................... 39 第一章 Keil 的配置设置 在建立工程和编写程序之前最好将系统字体和关键字的颜色等信息进行设置一番,来使 软件更适合使用,下面我们就来对这些配置进行简单的设置。 有多种方式可以打开配置对话框,常用的有两种,既通过菜单的方式打开配置对话框和 点击快捷图标的方式打开配置对话框。菜单打开配置对话框的方法是依次单击 “ Edit->Configuration...”如图 1.1.1所示;单击快捷图标打开配置对话框是单击图标 来完成的。 图 1.1.1 打开配置对话框的步骤 利用上面的方法就可以打开如图 1.1.2所示的配置对话框,其中有六个选项卡,分别为 Editor(编辑 ) 、 Colors & Fonts(颜色和字体 ) 、 User Keywords(用户关键字 ) 、 Shortcut keys(快 捷键 ) 、 Templates(模板 ) 、 Other(其他 ) ,看似复杂其实这六个选项卡中大部分是我们不需要 改变的,我们只需要对“ Colors & Fonts(颜色和字体 ) ”选项卡进行更改就可以了。 图 1.1.2 配置对话框 在上面的对话框的最上面单击一下“ Colors & Fonts”就可以切换到颜色和字体对话框 了,如图 1.1.2所示。 从上面的对话框中我们可以看到“ Window ”下面有许多的选项,其中我们需要关心的只 有两个, 既 8051:Editor Asm Feiles (8051汇编语言的编辑) 和 8051:Editor C Feiles (8051 C 语言的编辑),在我们单击这两行字体时“ Element ”下的信息有变化,这里就以汇编语言 文件为例,来将系统字体改为 Courier New 字号为 14(四号) ,关键字设为:蓝色加粗。操 作步骤为在“ Window ”下面的选项中单击“ 8051:Editor Asm F eiles ”然后在“ Element ”下 面的选项中选择“ Text ”在单击“ Font ”选项卡下面的“ Font ”右边凸起的那个按钮,如图 1.1.3,这时就会弹出图 1.1.4所示的字体设置窗口,然后在该窗口的左边“ Font ”下面的字 体中选择“ Courier New ”在右边“ Size ”下面的字号中选择“ 14”单击“ OK ”按钮回到颜色 和字体配置对话框,这样就把系统字体设置成了 Courier New 字体字号为 14(四号) 。 图 1.1.3 汇编语言字体设置 设置关键字和设置系统字体的方法类似,操作步骤为在“ Window ”下面的选项中单击 “ 8051:Editor Asm Feiles ”然后在“ Element ”下面的选项中选择 “ Keyword ”在单击“ Font ” 选项卡下面的“ Font ” 右边凸起的那个按钮来选择关键字的大小, 改变颜色即是单击 “ Colors ” 选项卡下面的“ Foreground ”项下的 ,来选择对应的颜色,如图 1.1.5所示,这里选择蓝 色,默认是黑色。 图 1.1.5 关键字颜色设置 将自己想要设置的项设置完,单击“ OK ”键返回软件界面。 如果是为了教学方便,要将程序编辑框铺满整个电脑铺满,可以依次单击“ View->Full Screen ”来达到目的,如图 1.1.6, 要从满屏页面恢复到一般页面也是非常简单的,只要在满 屏界面窗口中单击悬浮的 图标就可以了。 图 1.1.6 满屏操作步骤 第二章 Keil 工程文件的建立、设置与目标文件的获得 第一节 Keil 工程的建立 当用户正确安装了该软件后, 就会在桌面上建立名为 “ Keil uVision4” 的一个快捷图标, 我们只需双击这个快捷图就可以启动该软件了。 Keil 软件启动后,程序窗口的左边有一个工程管理窗口, 该窗口有 4个标签, 分别是 Project 、 Books 、 Functions 和 Templates ,这四个标签页分别显示当前项目的文件结构、 CPU 的寄存器及部份特殊功能寄存器的值(调试时才出现)和所选 CPU的附加说明文件,如果是 第一次启动 Keil,那么这三个标签页全是空的,如图 2.1.1所示。 图 2.1.1 第一次打开 keil uVision4软件出现的界面 1、建立工程文件 在项目开发中,并不是仅有一个源程序就行了,还要为这个项目选择 CPU(Keil 支持数 百种 CPU,而这些 CPU 的特性并不完全相同) ,确定编译、汇编、连接的参数,指定调试 的方式,有一些项目还会有多个文件组成等,为管理和使用方便, Keil 使用工程(Project ) 这一概念,将这些参数设置和所需的所有文件都加在一个工程中,只能对工程而不能对单一 的源程序进行编译(汇编)和连接等操作,下面我们就一步一步地来建立工程。 点击“ Project -> New μVision Project, ”菜单,如图 2.1.2所示。 图 2.1.2 创建工程选项 执行上面的操作就会出现一个对话框,为了管理方便最好新建一个文件夹,因为一个工 程里面会包含多个文件,一般以工程名为文件夹名来对该新建的文件夹取名,如图 2.1.3所 示,在选择刚才建立的文件夹然后单击“打开”按钮,然后给将要建立的工程起一个名字, 你可以在编缉框中输入一个名字(这里设为 exam1) , 不需要扩展名,如图 2.1.4所示。 图 2.1.3 给新建的工程建立一个文件夹 图 2.1.4 保存新建的工程 在图 1-4的界面里点击 “保存”按钮,出现一个对话框,如图 2.1.5所示, 这个对话 框要求选择目标 CPU (即你所用芯片的型号) , Keil 支持的 CPU很多,我们选择 Atmel公 司的 89C51 芯片。点击 ATMEL前面的“ +”号,展开该层, 点击其中的 AT89C51,如图 2.1.6所示,然后再点击“ OK ”按钮,完成选择 MCU 型号。 图 2.1.5 选择 MCU 的型号 图 2.1.6 选择 AT89C51单片机 在完成选择 MCU 型号后,软件会提示我们是否要复制一个源文件到这个工程中,这里我 们选择“否”,因为我要自己添加一个 C 语言或者汇编语言源文件,如图 2.1.7所示。 图 2.1.7是否复制源文件到工程中 在执行上一步后,就能在工程窗口的文件页中,出现了“ Target 1” ,前面有“ +”号, 点击“ +”号展开,可以看到下一层的“ Source Group1” ,这时的工程还是一个空的工程,里 面什么文件也没有,到这里我们就完整的把一个工程建立好了。 第二节 源文件的建立 使用菜单 “ File->New”如图 2-1所示或者点击工具栏的新建文件快捷按钮, 就可以在项 目窗口的右侧打开一个新的文本编缉窗口,如图 2-2所示。 图 2-1 以菜单方式建立文本框 图 2-2 将文本框建立好后的窗口 在建立好文本框后一定要先保存,如果你是先将程序输入到文本框中在保存的话,有时 由于特殊原因导致电脑断电或者死机,那么你所花费的时间和精力就相当于白费了,因此我 们一定要养成先保存在输入程序的好习惯。而且在先保存在输入程序,在文本框中关键字就 会变成其他颜色,有利于我们在写程序时检查所写关键字是否写错。 保存文件很简单,也有很多种方法,这里以最常用的三种来讲。第一种方法是直接单击 工具条上的保存图标 ;第二种方法是点击菜单栏的“ Feil->Save”;第三种方法是点击菜 单栏的“ Feil->Save As...”;其中第三种方法是最好的,因为软件每次都会提示你将这个 文件保存到那个路径里面,一定要选择保存在建立工程时建立的文件夹下,这样有利于设计 者查找该文件,也有利于管理。在第一次执行上面三种方法的其中一种后都会弹出文件保存 窗口,在“文件名(N ) ”右面的文本框中输入源文件的名字和后缀名,为了好管理文件一般 源文件和工程名一致,文件后缀名为“ .asm 或 .c ” ,其中“ .asm ”代表建立的是汇编语言源 文件, “ .c ”代表建立的是 C 语言源文件,由于我们是使用汇编语言编程,因此这里的后缀名 为 asm ,如图 2-3所示的。 图 2-3 源文件保存对话框 在上图所示的窗口中单击“保存”按钮,就将源文件保存好了,这时也回到了软件界面。 这时就可以将源文件中输入自己的程序了,这时注意经常保存,以免特殊情况导致电脑断电 或者死机导致没有保存所写的程序。 第三节 将源文件加到工程中并输入源程序 建立好的工程和建立好的程序源文件其实是两个相互独立,一个单片机工程是要将源文 件和工程联系到一起的。这时就需要手动把源程序加入,点击软件界面左上角的“ Source Group1”使其反白显示, 然后,点击鼠标右键, 出现一个下拉菜单, 选中其中的 “ Add file to Group ” Source Group1”如图 3-1 所示。 图 3-1 添加源文件步骤 在执行上面的步骤后会出现一个对话框,如图 3-2所示,要求寻找源文件,注意,该对 话框下面的“文件类型”默认为 C source file(*.c),也就是以 C 为扩展名的文件。 图 3-2 添加源文件窗口 由于我们是以汇编语言来编写程序, 因此源文件是以 asm 为扩展名的, 所以在列表框中 找不到 exam1.asm,要将文件类型改掉,点击对话框中“文件类型”后的下拉列表,找到并 选中“ Asm Source File(*.a51,*.asm),如图 3-3所示,这样,在列表框中就可以找到 exam1.asm 文件了,如图 3-4。 图 3-3 选择源文件的类型 图 3-4 添加汇编语言源文件 在上面的窗口中双击 exam1.asm 文件,将文件加入项目,注意,在文件加入项目后,该 对话框并不消失,等待继续加入其它文件,但初学时常会误认为操作没有成功而再次双击同 一文件,这时会出现如图 4-5 所示的对话框,提示你所选文件已在列表中。 图 4-5 提醒文件已在工程中 此时应点击“确定” ,返回前一对话框,然后点击“ Close ”即可返回主界面,返回后, 点击“ SourceGroup 1”前的加号, 会发现 exam1.asm 文件已在其中。 双击文件名 exam1.asm , 即打开该源程序,如图 3-6所示。 图 3-6 打开源程序文件后的主界面 需要说明的是,源文件就是一般的文本文件,不一定使用 Keil软件编写,可以使用任 意文本编缉器编写。到这里我们就将一个源文件添加到工程中了,接下来的事就是编写源程 序和编译程序生产目标文件了。 下面就将实例一的程序输入到该源程序中。 实例一的程序如下,实例一的硬件图如图 2-4。 实例一的程序: MOV A, #0FEH MAIN: MOV P1, A RL A LCALL DELAY AJMP MAIN DELAY: MOV R7,#255 D1: MOV R6,#255 DJNZ R6,$ DJNZ R7,D1 RET END 图 3-7 实例一的硬件原理图 将实例一的源文件输入到软件后的主界面如图 3-8所示。 图 3-8 输入程序后的主界面 第四节 工程的详细设置 工程建立好以后,还要对工程进行进一步的设置,以满足要求。 首先点击左上边的 Project 窗口的 Target 1, 然后使用菜单“ Project->Option for target‘ target1’ ”如图 4-1所示,也可以按快捷键“ Alt+F7”来完成,还可以单击快捷图标 来完 成。 图 4-1 打开设置对话框的步骤 在进行上面的操作后就会出现对工程设置的对话框,这个对话框可谓非常复杂,共有 8 个页面,要全部搞清可不容易,好在绝大部份设置项取默认值就行了,如图 4-2所示。 图 4-2 设置对话框的 Target 页面 设置对话框中默认的就是 Target 页面,如图 4-2 所示, Xtal 后面的数值是晶振频率值, 默认值是所选目标 CPU 的最高可用频率值,对于我们所选的 AT89C51 而言是 24M ,该数 值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值 可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同,如果没 必要了解程序执行的时间,也可以不设,这里设置为 12.0,如图 4-3所示。 图 4-3 设置晶振频率 Memory Mode用于设置 RAM 使用情况,有三个选择项, Small:variables in DATA 是所 有变量都在单片机的内部 RAM 中; Compact:variables i n PDATA 是可以使用一页外部扩展 RAM ,而 Larget:variables in XDATA则是可以使用全部外部的扩展 RAM ,如图 4-4所示。 一般都是采用默认方式,也就是 Small:variables in DATA方式。 图 4-4 Memory Mode设置项 Code Rom Size:用 于设置 ROM 空间的使用, 同样也有三个选择项, 即 Small:program 2k or less模式,只用低于 2K 的程序空间; Compact:2k functions,64k program 模式,单个函数 的代码量不能超过 2K ,整个程序可以使用 64K 程序空间; Larget:64k program 模式,可用 全部 64K 空间,如图 4-5所示。一般都是采用默认方式,也就是 Larget:64k program 模式。 图 4-5 Code Rom Size设置项 Operating system: 项是操作系统选择, Keil 提供了两种操作系统:RTX-51 Tiny 和 RTR-51 Full,关于操作系统是另外一个很大的话题了,通常我们不使用任何操作系统,即使 用该项的默认值:None (不使用任何操作系统) ,如图 4-6所示。 图 4-6 Operating system 设置项 Use on-chip ROM 选择项,确认是否仅使用片内 ROM (注意:选中该项并不会影响最 终生成的目标代码量) ; Off-Chip Code memory 用以确定系统扩展 ROM 的地址范围, Off-Chip Xdata memory 组用于确定系统扩展 RAM 的地址范围,这些选择项必须根据所用硬 件来决定,由于该例是单片应用,未进行任何扩展,所以均不重新选择,按默认值设置,如 图 4-7所示。 图 4-7 Target选项卡剩下项的设置 OutPut 页面设置对话框,如图 4-8所示,这里面也有多个选择项,其中 Creat Hex file用 于生成可执行代码文件(可以用编程器写入单片机芯片的 HEX 格式文件,文件的扩展名 为 .HEX ) ,默认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项,这一点是 初学者易疏忽的,在此特别提醒注意。选中 Debug Information 将会产生调试信息,这些信 息用于调试,如果需要对程序进行调试, 应当选中该项。 Browse Information 是产生浏览信息, 该信息可以用菜单 view->Browse来查看,这里取默认值。按钮“ Select Folder for Objects…” 是用来选择最终的目标文件所在的文件夹,默认是与工程文件在同一个文件夹中。 Name of Executable:用于指定最终生成的目标文件的名字,默认与工程的名字相同,这两项一般不需 要更改。 图 4-8 OutPut页面设置对话框 工程设置对话框中的其它各页面与 C51 编译选项、 A51 的汇编选项、 BL51 连接器的 连接选项等用法有关,这里均取默认值,不作任何修改。以下仅对一些有关页面中常用的选 项作一个简单介绍。 Listing 标签页用于调整生成的列表文件选项,如图 4-9所示。在汇编或编译完成后将产 生(*.lst)的列表文件,在连接完成后也将产生(*.m51)的列表文件,该页用于对列表文件 的内容和形式进行细致的调节,其中比较常用的选项是“ C Compile Listing”下的“ Assamble Code ”项,选中该项可以在列表文件中生成 C 语言源程序所对应的汇编代码。 图 4-8 Listing 标签页 C51 标签页用于对 Keil 的 C51 编译器的编译过程进行控制, 其中比较常用的是 “ Code Optimization ”组,如图 4-9所示,该组中 Level 是优化等级, C51 在对源程序进行编译时, 可以对代码多至 9 级优化, 默认使用第 8 级,一般不必修改, 如果在编译中出现一些问题, 可以降低优化级别试一试。 Emphasis 是选择编译优先方式, 第一项是代码量优化(最终生 成的代码量小);第二项是速度优先 (最终生成的代码速度快) ;第三项是缺省。默认的是 速度优先,可根据需要更改。 图 4-9 C51 标签页 设置完成后按“ OK ”返回主界面,工程文件建立、设置完毕。 第五节 编译、连接、生成目标文件 在设置好工程后,即可进行编译、连接。选择菜单 Project->Build target, 对当前工程进 行连接,如果当前文件已修改,软件会先对该文件进行编译,然后再连接以产生目标代码; 如果选择 Rebuild All target files 将会对当前工程中的所有文件重新进行编译然后再连接,确 保最终生产的目标代码是最新的,而 Translate ,. 项则仅对该文件进行编译,不进行连接, 如图 5-1所示。 图 5-1 编译操作选项 以上操作也可以通过工具栏按钮直接进行。图 5-2是有关编译、设置的工具栏按钮,从 左到右分别是:编译、编译连接、全部重建、停止编译和对工程进行设置。 图 5-2 编译快捷图标 编译过程中的信息将出现在输出窗口中的 Build 页中,如果源程序中有语法错误,会有 错误报告出现,双击该行,可以定位到出错的位置,对源程序反复修改之后,最终会得到如 图 5-3所示的结果,提示获得了名为 exam1.hex 的文件,该文件即可被编程器读入并写到芯 片中,同时还产生了一些其它相关的文件,可被用于 Keil 的仿真与调试,这时可以进入下 一步调试的工作。 图 5-3 编译成功并生成 hex 文件成功后的软件界面 第三章 Keil的调试命令、在线汇编与断点设置 在上一章中我们学习了如何建立工程、汇编、连接工程,并获得目标代码,但是做到这 一步仅仅代表你的源程序没有语法错误,至于源程序中存在着的其它错误,必须通过调试才 能发现并解决。事实上,除了极简单的程序以外,绝大部份的程序都要通过反复调试才能得 到正确的结果,因此,调试是软件开发中重要的一个环节,这一章将介绍常用的调试命令、 利用在线汇编、各种设置断点进行程序调试的方法,并通过实例介绍这些方法的使用。 第一节 常用调试命令 在对工程成功地进行汇编、 连接以后, 按 Ctrl+F5 或者使用菜单 “ Debug->Start/Stop Debug Session”如图 2.1.1所示,也可以单击软件菜单栏下面的快捷图标 ,即可进入调 试状态。 Keil 软件内建了一个仿真 CPU用来模拟执行程序,该仿真 CPU功能强大,可以在 没有硬件和仿真机的情况下进行程序的调试,下面将要学的就是该模拟调试功能。不过在学 习之前必须明确,模拟毕竟只是模拟,与真实的硬件执行程序肯定还是有区别的,其中最明 显的就是时序,软件模拟是不可能和真实的硬件具有相同的时序的,具体的表现就是程序执 行的速度和各人使用的计算机有关,计算机性能越好,运行速度越快。 图 2.1.1 进入调试模式操作步骤 进入调试状态后,界面与编缉状态相比有明显的变化, Debug 菜单项中原来不能用的命 现在已可以使用了, 工具栏会多出一个用于运行和调试的工具条, 如图 2.1.2 所示, Debug 菜 上的大部份命令可以在此找到对应的快捷按钮,从左到右依次是复位、运行、暂停、单步、 过程单步、执行完当前子程序、运行到当前行、下一状态、打开跟踪、观察跟踪、反汇编窗 口、观察窗口、代码作用范围分析、 1#串行窗口、内存窗口、性能分析、工具按钮等命令。 图 2.1.2 调试工具条 学习程序调试,必须明确两个重要的概念,即单步执行与全速运行。全速执行是指一行 程序执行完以后紧接着执行下一行程序,中间不停止,这样程序执行的速度很快,并可以看 到该段程序执行的总体效果,即最终结果正确还是错误,但如果程序有错,则难以确认错误 出现在哪些程序行。单步执行是每次执行一行程序,执行完该行程序以后即停止,等待命令 执行下一行程序,此时可以观察该行程序执行完以后得到的结果,是否与我们写该行程序所 想要得到的结果相同,借此可以找到程序中问题所在。程序调试中,这两种运行方式都要用 到。 使用菜单 STEP 或 相应的命令按钮或使用快捷键 F11可以单步执行程序,使用菜单 STEP OVER 或功能键 F10 可以以过程单步形式执行命令,所谓过程单步,是指将汇编语言中的子 程序或高级语言中的函数作为一个语句来全速执行。 按下 F11 键,可以看到源程序窗口的左边出现了一个黄色调试箭头, 指向源程序的第一 行,如图图 2.1.3所示。每按一次 F11,即执行该箭头所指程序行,然后箭头指向下一行, 当箭头指向 LCALL DELAY 行时,再次按下 F11, 会发现,箭头指向了延时子程序 DELAY 的 第一行。不断按 F11 键,即可逐步执行延时子程序。 图 2.1.3 调试窗口 通过单步执行程序,可以找出一些问题的所在,但是仅依靠单步执行来查错有时是困难 的,或虽能查出错误但效率很低,为此必须辅之以其它的方法,如本例中的延时程序是通过 将 D2: DJNZ R6,D2 这一行程序执行六万多次来达到延时的目的, 如果用按 F1 六万多次 的方法来执行完该程序行,显然不合适,为此,可以采取以下一些方法,第一,用鼠标在子 程序的最后一行 (ret )点一下, 把光标定位于该行, 然后用菜单 Debug->Run to Cursor line (执行到光标所在行) ,即可全速执行完黄色箭头与光标之间的程序行。第二,在进入该子 程序后,使用菜单 Debug->Step Out of Current Function(单步执行到该函数外) ,使用 该命令后,即全速执行完调试光标所在的子程序或子函数并指向主程序中的下一行程序(这 里是 JMP LOOP 行 ) 。第三种方法, 在开始调试的, 按 F10 而非 F11,程序也将单步执行, 不同的是,执行到 lcall delay 行时,按下 F10 键,调试光标不进入子程序的内部,而是 全速执行完该子程序,然后直接指向下一行“ JMP LOOP” 。灵活应用这几种方法,可以大 大提高查错的效率。 第二节 在线汇编 在进入 Keil 的调试环境以后,如果发现程序有错,可以直接对源程序进行修改,但是 要使修改后的代码起作用,必须先退出调试环境,重新进行编译、连接后再次进入调试,如 果只是需要对某些程序行进行测试,或仅需对源程序进行临时的修改,这样的过程未免有些 麻烦,为此 Keil 软件提供了在线汇编的能力,将光标定位于需要修改的程序行上,用菜单 Debug->Inline Assambly, 即可出现如图 3.2.1的对话框,在 Enter New 后面的编缉框内直 接输入需更改的程序语句,输入完后键入回车将自动指向下一条语句,可以继续修改,如果 不再需要修改,可以点击右上角的关闭按钮关闭窗口。 图 3.2.1在线汇编窗口 第三节断点设置 程序调试时,一些程序行必须满足一定的条件才能被执行到(如程序中某变量达到一定 的值、按键被按下、串口接收到数据、有中断产生等),这些条件往往是异步发生或难以预 先设定的,这类问题使用单步执行的方法是很难调试的,这时就要使用到程序调试中的另一 种非常重要的方法——断点设置。 断点设置的方法有多种, 常用的是在某一程序行设置断点, 设置好断点后可以全速运行程序,一旦执行到该程序行即停止,可在此观察有关变量值,以 确定问题所在。 在程序行设置 /移除断点的方法是将光标定位于需要设置断点的程序行, 使用 菜单 Debug->Insert/Remove BreakPoint 设置或移除断点(也可以用鼠标在该行双击实现同 样的功能); Debug->Enable/Disable Breakpoint 是开启或暂停光标所在行的断点功能; Debug->Disable All Breakpoint 暂停所有断点; Debug->Kill All BreakPoint 清除所有的 断点设置。这些功能也可以用工具条上的快捷按钮进行设置。 除了在某程序行设置断点这一基本方法以外, Keil 软件还提供了多种设置断点的方法, 按 Debug->Breakpoints, 即出现一个对话框,该对话框用于对断点进行详细的设置,如图 3.3.1所示。 图 3.3.1 断点设置对话框 图 3.3.1中 Expression 后的编缉框内用于输入表达式,该表达式用于确定程序停止运行 的条件, 这里表达式的定义功能非常强大, 涉及到 Keil 内置的一套调试语法, 这里不作详细 说明,仅举若干实例,希望读者可以举一反三。 1) 在 Experssion 中键入 a==0xf7,再点击 Define 即定义了一个断点, 注意, a 后有两 个等号,意即相等。该表达式的含义是:如果 a 的值到达 0xf7 则停止程序运行。除使用 相等符号之外,还可以使用 >,>=,<><=,!=(不等于) ,&(两值按位与)="">=,!=(不等于)> 值相与)等运算符号。 2) 在 Experssion 后中键入 Delay 再点击 Define ,其含义是如果执行标号为 Delay 的行则 中断。 3) 在 Experssion 后中键入 Delay ,按 Count 后的微调按钮,将值调到 3,其意义是当第三次 执行到 Delay 时才停止程序运行。 4) 在 Experssion 后键入 Delay , 在 Command 后键入 printf(“ SubRoutine ‘ Delay ’ has been n ” ) 主程序每次调用 Delay 程序时并不停止运行,但会在输出窗口 Command 页输出一行字符,即 SubRoutine ‘ Delay ’ has been Called。其中“ \n”的用途是回 车换行,使窗口输出的字符整齐。 5) 设置断点前先在输出窗口的 Command页 中键入 DEFINE int I,然后在断点设置时同 4), 但是 Command 后键入 printf(“ SubRoutine ‘ Delay ’ has been Called n ” ,++I),则主程序每次调用 Delay 时将会在 Command 窗口输出该字符 及被调用的次数,如 SubRoutine ‘ Delay ’ has been Called 10 times。 对于使用 C 源程序语言的调试, 表达式中可以直接使用变量名, 但必须要注意, 设置时 只能使用全局变量名和调试箭头所指模块中的局部变量名。 第四节 实例调试 为进行程序的调试,我们首先给源程序制造一个错误,将延时子程序的第三行“ DJNZR6,$” 后的 $改为 D1,然后重新编译,由于程序中并无语法错误,所以编译时不会有任何出错提示, 但由于转移目的地出错,所以子程序将陷入无限循环中。 进入调试状态后,按 F10 以过程单步的形式执行程序,当执行到 LCALL D ELAY 行 时,程序 不能继续往下执行, 同时发现调试工具条上的 Halt 按钮变成了红色, 说明程序在此不断地执 行着,而我们预期这一行程序执行完后将停止,这个结果与预期不同,可以看出所调用的子 程序出了差错。 为查明出错原因, 按 Halt 按钮使程序停止执行, 然后按 RST 按钮使程序复位, 再次按下 F10 单步执行,但在执行到 LCALL DELAY 行时,改按 F11 键跟踪到子程序内部(如 果按下 F11 键没有反应,请在源程序窗口中用鼠标点一下),单步执行程序,可以发现在执 行到“ DJNZ R6,D1”行时,程序不断地从这一行转移到上一行,同时观察左侧的寄存器的值, 会发现 R6 的值始终在 FFH 和 FEH 之间变化,不会减小,而我们的预期是 R6 的值不断减小, 减到 0 后往下执行,因此这个结果与预期不符,通过这样的观察,不难发现问题是因为标号 写错而产生的,发现问题即可以修改,为了验证即将进行的修改是否正确,可以先使用在线 汇编功能测试一下。把光标定位于程序行“ DJNZ R6,D1”,打开在线汇编的对话框,将程序 改为“ DJNZ R7,0EH ”,即转回本条指令所在行继续执行,其中 0EH 是本条指令在程序存储器 中的位置,这个值可以通过在线汇编窗口看到,如图 3 所示。然后关闭窗口,再进行调试, 发现程序能够正确地执行了,这说明修改是正确的。注意,这时候的源程序并没有修改,此 时应该退出调试程序,将源程序更改过来,并重新编译连接,以获得正确的目标代码。 第四章 Keil 程序调试窗口 上一章中我们学习了几种常用的程序调试方法,这一讲中将介绍 Keil 提供各种窗口如 输出窗口、观察窗口、存储器窗口、反汇编窗口、串行窗口等的用途,以及这些窗口的使用 方法,并通过实例介绍这些窗口在调试中的使用。 第一节 程序调试时的常用窗口 Keil 软件在调试程序时提供了多个窗口,主要包括输出窗口(Output Windows )、观察 窗口(Watch&Call Statck Windows)、存储器窗口(Memory Window)、反汇编窗口 (DissamblyWindow )串行窗口(Serial Window )等。进入调试模式后, 可以通过菜单 View 下 的相应命令打开或关闭这些窗口。 图 4.1.1是输出窗口、 观察窗口和存储器窗口, 各窗口的大小可以使用鼠标调整。 进入调 试程序后,输出窗口自动切换到 Command 页。该页用于输入调试命令和输出调试信息。对于 初学者,可以暂不学习调试命令的使用方法。 图 4.1.1 调试窗口(命令窗口、存储器窗口、观察窗口) 一、存储器窗口 存储器窗口中可以显示系统中各种内存中的值,通过在 Address 后的编缉框内输入“字 母:数字”即可显示相应内存值,其中字母可以是 C 、 D 、 I 、 X ,分别代表代码存储空间、直 接寻址的片内存储空间、间接寻址的片内存储空间、扩展的外部 RAM 空 间,数字代表想要查 看的地址。例如输入 D :0 即可观察到地址 0 开始的片内 RAM 单元值、键入 C :0 即可显示从 0 开始的 ROM 单元中的值,即查看程序的二进制代码。该窗口的显示值可以以各种形式显示, 如十进制、十六进制、字符型等,改变显示方式的方法是点鼠标右键,在弹出的快捷菜单中 选择,该菜单用分隔条分成三部份,其中第一部份与第二部份的三个选项为同一级别,选中 第一部份的任一选项,内容将以整数形式显示,而选中第二部份的 Ascii 项则将以字符型式 显示,选中 Float 项将相邻四字节组成的浮点数形式显示、 选中 Double 项则将相邻 8 字节组 成双精度形式显示,如图图 4.1.2所示。 图 4.1.2 存储器数值各种方式显示选择 第一部份又有多个选择项,其中 Decimal 项是一个开关,如果选中该项,则窗口中的值 将以十进制的形式显示,否则按默认的十六进制方式显示。 Unsigned 和 Signed 后分别有三 个选项:Char 、 Int 、 Long ,分别代表以单字节方式显示、 将相邻双字节组成整型数方式显示、 将相邻四字节组成长整型方式显示,而 Unsigned 和 Signed 则分别代表无符号形式和有符号 形式,究竟从哪一个单元开始的相邻单元则与你的设置有关,以整型为例,如果你输入的是 I:0,那么 00H 和 01H 单元的内容将会组成一个整型数, 而如果你输入的是 I :1, 01H 和 02H 单 元的内容全组成一个整型数,以此类推。有关数据格式与 C 语言规定相同,请参考 C 语言书 籍,默认以无符号单字节方式显示。第三部份的 Modify Memory at X:xx 用于更改鼠标处的 内存单元值,选中该项即出现如图 4.1.3所示的对话框,可以在对话框内输入要修改的内容。 图 4.1.3 存储器的值的修改 二、工程窗口寄存器页 图 4.1.4是工程窗口寄存器页的内容,寄存器页包括了当前的工作寄存器组和系统寄存 器,系统寄存器组有一些是实际存在的寄存器如 A 、 B 、 DPTR 、 SP 、 PSW 等,有一些是实际中 并不存在或虽然存在却不能对其操作的如 PC 、 Status 等。每当程序中执行到对某寄存器的操 作时,该寄存器会以反色(蓝底白字)显示,用鼠标单击然后按下 F2 键,即可修改该值。 图 4.1.4 工程窗口寄存器页 三、观察窗口 观察窗口是很重要的一个窗口,工程窗口中仅可以观察到工作寄存器和有限的寄存器如 A 、 B 、 DPTR 等 ,如果需要观察其它的寄存器的值或者在高级语言编程时需要直接观察变量, 就要借助于观察窗口了。 其它窗口将在以下的实例中介绍。 一般情况下,我们仅在单步执行时才对变量的值的变化感兴趣,全速运行时,变量的值 是不变的,只有在程序停下来之后,才会将这些值最新的变化反映出来,但是,在一些特殊 场合下我们也可能需要在全速运行时观察变量的变化,此时可以点击 View->Periodic Window Updata (周期更新窗口),确认该项处于被选中状态,即可在全速运行时动态地观察有关值 的变化。但是,选中该项,将会使程序模拟执行的速度变慢。 第二节 各种窗口在程序调试中的用途 以下通过一个高级语言程序来说明这些窗口的使用。例 2: #include sbit P1_0=P1^0; //定义 P1.0 void mDelay(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) for(j=0;j<> } void main() { unsigned int i; for(;;) { mDelay(10); // 延时 10毫秒 i++; if(i==10) { P1_0=!P1_0; i=0; } } } 这个程序的工作过程是:不断调用延时程序,每次延时 10 毫秒,然后将变量 I 加 1,随 后对变量 I 进行判断,如果 I 的值等于 10,那么将 P1.0 取反,并将 I 清 0,最终的执行效果 是 P1.0 每 0.1S 取反一次。 输入源程序并以 exam2.c 为文件名存盘,建立名为 exam2 的项目, 将 exam2.c 加入项目, 编译、连接后按 Ctrl+F5 进入调试,按 F10 单步执行。注意观察窗口,其中有一个标签页为 Locals ,这一页会自动显示当前模块中的变量名及变量值。 可以看到窗口中有名为 I 的变量, 其值随着执行的次数而逐渐加大, 如果在执行到 mDelay(10)行时按 F11 跟踪到 mDelay 函数内 部,该窗口的变量自动变为 DelayTime 和 j 。另外两个标签页 Watch #1 和 Watch #2 可以加入 自定义的观察变量,点击“ type F2 to edit”然后再按 F2 即可输入变量,试着在 Watch #1中输入 I ,观察它的变化。在程序较复杂,变量很多的场合,这两个自定义观察窗口可以筛选 出我们自己感兴趣的变量加以观察。观察窗口中变量的值不仅可以观察,还可以修改,以该 程序为例, I 须加 10 次才能到 10, 为快速验证是否可以正确执行到 P1_0=!P1_0 行, 点击 I 后 面的值,再按 F2,该值即可修改,将 I 的值改到 9,再次按 F10 单步执行,即可以很快执行到 P1_0=!P1_0 程序行。该窗口显示的变量值可以以十进制或十六进制形式显示, 方法是在显示 窗口点右键,在快捷菜单中选择如图 4.2.1 所示。 图 4.2.1设定观察窗的显示方式 点击 View->Dissambly Window 可以打开反汇编窗口,该窗口可以显示反汇编后的代码、 源程序和相应反汇编代码的混合代码,可以在该窗口进行在线汇编、利用该窗口跟踪已找行 的代码、在该窗口按汇编代码的方式单步执行,这也是一个重要的窗口。打开反汇编窗口, 点击鼠标右键,出现快捷菜单,如图 4.2.2 所示,其中 Mixed Mode 是以混合方式显示, Assembly Mode 是以反汇编码方式显示。 图 4.2.2反汇编窗口 程序调试中常使用设置断点然后全速运行的方式,在断点处可以获得各变量值,但却无 法知道程序到达断点以前究竟执行了哪些代码, 而这往往是需要了解的, 为此, Keil 提供了 跟踪功能,在运行程序之前打开调试工具条上的允许跟踪代码开关,然后全速运行程序,当 程序停止运行后,点击查看跟踪代码按钮,自动切换到反汇编窗口,如图 6 所示,其中前面 标有“ -”号的行就是中断以前执行的代码, 可以按窗口边的上卷按钮向上翻查看代码执行记 录。 利用工程窗口可以观察程序执行的时间,下面我们观察一下该例中延时程序的延时时间 是否满足我们的要求,即是否确实延时 10 毫秒,展开工程窗口 Regs 页中的 Sys 目录树,其 中的 Sec 项记录了从程序开始执行到当前程序流逝的秒数。点击 RST 按钮以复位程序, Sec 的值回零,按下 F10 键,程序窗口中的黄色箭头指向 mDelay(10)行,此时,记录下 Sec 值为 0.00038900,然后再按 F10 执行完该段程序,再次查看 Sec 的值为 0.01051200,两者相减大 约是 0.01 秒,所以延时时间大致是正确的。读者可以试着将延时程序中的 unsigned int 改 为 unsigned char 试试看时间是否仍正确。注意,使用这一功能的前提是在项目设置中正确 设置晶振的数值。 Keil 提供了串行窗口, 我们可以直接在串行窗口中键入字符, 该字符虽不会被显示出来, 但却能传递到仿真 CPU 中 ,如果仿真 CPU 通 过串行口发送字符,那么这些字符会在串行窗口 显示出来,用该窗口可以在没有硬件的情况下用键盘模拟串口通讯。下面通过一个例子说明 Keil 串行窗口的应用。 该程序实现一个行编缉功能, 每键入一个字母, 会立即回显到窗口中。 编程的方法是通过检测 RI 是否等于 1 来判断串行口是否有字符输入,如果有字符输入,则 将其送到 SBUF ,这个字符就会在串行窗口中显示出来。其中 ser_init 是串行口初始化程序, 要使用串行口,必须首先对串行口进行初始化。例 3: MOV SP,#5FH ;堆栈初始化 CALL SER_INIT ;串行口初始化 LOOP:JBC RI,NEXT ;如果串口接收到字符, 转 JMP LOOP ;否则等待接收字符 NEXT:MOV A,SBUF ; 从 SBUF 中取字符 MOV SBUF,A ; 回送到发送 SBUF 中 SEND: JBC TI,LOOP ;发送完成,转 LOOP JMP SEND ;否则等待发送完 SER_INIT: MOV SCON,#50H;中断初始化 ORL TMOD,#20H ORL PCON,#80H MOV TH1,#0FDH ;设定波特率 SETB TR1 ;定时器 1 开始运行 SETB REN ;允许接收 SETB SM2 RET END 输入源程序,并建立项目,正确编译、连接,进入调试后,全速运行,点击串行窗口 1按钮,即在原源程序窗口位置出现一个空白窗口,击键,相应的字母就会出现在该窗口中。 在窗口中击鼠标右键,出现一个弹出式菜单,选择“ Ascii Mode”即以 Ascii 码的方式显示 接收到的数据; 选择“ Hex Mode ”以十六进制码方式显示接收到的数据; 选择“ Clear Window ” 可以清除窗口中显示的内容。 由于部份 CPU 具有双串口,故 Keil 提供了两个串行窗口,我们选用的 89C51 芯片只有 一个串行口,所以 Serial 2 串行窗口不起作用。 小技巧:凡是鼠标单击然后按 F2 的地方都可以用鼠标连续单击两次(注意:不是双击) 来替代。 第五章 Keil 的辅助工具和部份高级技巧 在前面的几讲中我们介绍了工程的建立方法, 常用的调试方法, 除此之外, Keil 还提供 了一些辅助工具如外围接口、性能分析、变量来源分析、代码作用分析等,帮助我们了解程 的性能、查找程序中的隐藏错误,快速查看程序变量名信息等,这一讲中将对这些功工具作 一介绍,另外还将介绍 Keil 的部份高级调试技巧。 第一节 辅助工具 这部份功能并不是直接用来进行程序调试的,但可以帮助我们进行程序的调试、程序性 能的分析,同样是一些很有用的工具。 一、外围接口 为了能够比较直观地了解单片机中定时器、中断、并行端口、串行端口等常用外设的使 用情况, Keil 提供了一些外围接口对话框, 通过 Peripherals 菜单选择, 该菜单的下拉菜单 内容与你建立项目时所选的 CPU 有关,如果是选择的 89C51 这一类“标准”的 51 机,那么将 会有 Interrupt (中断)、 I/O Ports(并行 I/O 口)、 Serial (串行口)、 Timer (定时 /计 数器)这四个外围设备菜单。打开这些对话框,列出了外围设备的当前使用情况,各标志位 的情况等,可以在这些对话框中直观地观察和更改各外围设备的运行情况。 下面我们通过一个简单例子看一看并行端口的外围设备对话框的使用。例 4: MOV A,#0FEH LOOP: MOV P1,A RL A CALL DELAY ; 延时 100 毫秒 JMP LOOP 编译、连接进入调试后,点击 Peripherals->I/O-Ports->Port 1 打开,如图 5.1.1所示, 全速运行,可以看到代表各位的勾在不断变化(如果看不到变化,请点击 View->Periodic Window Updata),这样可以形象地看出程序执行的结果。 图 5.1.1 外围设备之并行端口 注:如果你看到的变化极快,甚至看不太清楚,那么说明你的计算机性能好,模拟执行 的速度快,你可以试着将加长延时程序的时间以放慢速度。模拟运行速度与实际运行的速度 无法相同是软件模拟的一个固有弱点。 点击 Peripherals->I/O-Ports->Timer0 即出现图 5.1.2所示定时 /计数器 0 的外围接口 界面,可以直接选择 Mode 组中的下拉列表以确定定时 /计数工作方式, 0-3 四种工作方式, 设定定时初值等,点击选中 TR0, status 后的 stop 就变成了 run ,如果全速运行程序,此时 th0,tl0 后的值也快速地开始变化(同样要求 Periodic Window U pdata 处于选中状态),直 观地演示了定时 /计数器的工作情况 (当然, 由于你的程序未对此写任何代码, 所以程序不会 对此定时 /计数器的工作进行处理)。 图 5.1.2 外围设备之定时器 二、性能分析 Keil 提供了一个性能分析工具, 利用该工具, 我们可以了解程序中哪些部份的执行时间 最长,调用次数最多,从而了解影响整个程序中执行速度的瓶颈。下面通过一个实例来看一 看这个工具如何使用,例 5: #include sbit P1_0=P1^0; //定义 P1.0 void mDelay(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;}="">125;j++)> } void mDelay1(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) for(j=0;j<125;j++);>125;j++);> void main() { unsigned int i; for(;;){ mDelay(10); // 延时 10毫秒 i++; if(i==10) { P1_0=!P1_0; i=0; mDelay1(10);} } } 编译连接。进入调试状态后使用菜单 View->Performance Analyzer Window ,打开性能分 析对话框,进入该对话框后, 只有一项 unspecified , 点鼠标右键, 在快捷菜单中选择 Setup PA即打开性能分析设置对话框,对于 C 语言程序,该对话框右侧的“ Function Symbol ”下的列 表框给出函数符号,双击某一符号,该符号即出现在 Define Performance Analyzer 下的编 缉框中,每输入一个符号名字,点击 Define 按钮,即将该函数加入其上的分析列表框。对于 汇编语言源程序, Function Symbol 下的列表框中不会出现子程序名,可以直接在编缉框中 输入子程序名,点击 Close 关闭窗口,回到性能分析窗口,此时窗口共有 4 个选项。全速执 行程序,可以看到 mDelay 和 mDelay1 后出现一个蓝色指示条, 配合上面的标尺可以直观地看 出每个函数占整个执行时间的比例,点击相应的函数名,可以在该窗口的状态栏看到更详细 的数据,其中各项的含义如下: Min :该段程序执行所需的最短时间; Max :该段程序执行所需的最长时间; Avg :该段程 序执行所花平均时间; Total :该段程序到目前为目总共执行的时间; %:占整个执行时间的 百分比; count :被调用的次数。 本程序中,函数 mDelay 和 mDelay1 每次被调用都花费同样的时间,看不出 Min 、 Max 、和 Avg 的意义,实际上,由于条件的变化,某些函数执行的时间不一定是一个固定的值,借助 于这些信息,可以对程序有更详细的了解。下面将 mDelay1 函数略作修改作一演示。 void mDelay1(unsigned char DelayTime) { static unsigned char k; unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(;j<> {;} } k++; } 程序中定义了一个静态变量 K ,每次调用该变量加 1,而 j 的循环条件与 k 的大小有关, 这使每次执行该程序所花的时间不一样。编译、执行该程序,再次观察性能分析窗口,可以 看出 Min 、 Max 、 Avg 的意义。 三、变量来源浏览 该窗口用于观察程序中变量名的有关信息,如该变量名在那一个函数中被定义、在哪里 被调用,共出现多少次等。在 Source Browse 窗口中提供了完善的管理方法,如过滤器可以 分门别类地列出各种类别的变量名,可以对这些变量按 Class (组)、 Type (类型)、 Space (所在空间)、 Use (调用次数)排序,点击变量名,可以在窗口的右侧看到该变量名的更详 细的信息。 四、代码作用范围分析 在你写的程序中,有些代码可能永远不会被执行到(这是无效的代码),也有一些代码 必须在满足一定条件后才能被执行到,借助于代码范围分析工具,可以快速地了解代码的执 行情况。 进入调试后,全速运行,然后按停止按钮,停下来后,可以看到在源程序的左列有三种 颜色,灰、淡灰和绿,其中淡灰所指的行并不是可执行代码,如变量或函数定义、注释行等 等,而灰色行是可执行但从未执行过的代码,而绿色则是已执行过的程序行。使用调试工具 条上的 Code Coverage Window 可打开代码作用范围分析的对话框,里面有各个模块代码执行 情况的更详细的分析。 如果你发现全速运行后有一些未被执行到的代码, 那么就要仔细分析, 这些代码究竟是无效的代码还是因为条件没有满足而没有被执行到。 第二节 部份高级调试技巧 Keil 内置了一套调试语言, 很多高级调试技巧与此有关, 但是全面学习这套语言并不现 实,这不是这么几期连载可以胜任的,这里仅介绍部份较为实用的功能,如要获得更详细的 信息,请参考 Keil 自带的帮助文件 GS51.PDF 。 一、串行窗口与实际硬件相连 Keil 的串行窗口除可以模拟串行口的输入和输出功能外还可以与 PC 机上实际的串口相 连,接受串口输入的内容,并将输出送到串口。这需要在 Keil 中进行设置。方法是首先在输 出窗口的 Command 页用 MODE 命令设置串口的工作方式,然后用 ASSIGN 命 令将串行窗口与实 际的串口相关联,下面我们通过一个实例来说明如何操作。例 6: ORG 0000H JMP START ORG 3+4*8 ;串行中断入口 JMP SER_INT START: MOV SP,#5FH ;堆栈初始化 CALL SER_INIT ;串行口初始化 A SETB EA ; SETB ES ; JMP $ ;主程序到此结束 SER_INT: JBC RI,NEXT ;如果串口接收到字 JMP SEND ;否 则转发送处理 NEXT: MOV A,SBUF ;从 SBUF 中 取字符 MOV SBUF,A ;回 送到发送 SBUF 中 JMP OVER SEND: clr ti OVER: reti SER_INIT: ;中断初始化 MOV SCON,#50H ORL TMOD,#20H ORL PCON,#80H MOV TH1,#0FDH ;设定波特率 SETB TR1 ;定时器 1 开始运行 SETB REN ;允 许接收 SETB SM2 RET END 这个程序使用了中断方式编写串行口输入 /输出程序,它的功能是将接串行口收到的字符 回送,即再通过串行口发送出去。 正确输入源文件、建立工程、编译连接没有错后,可进行调试,使用 Keil 自带的串行 窗口测试功能是否正确,如果正确,可以进行下一步的连机试验。 为简单实用,我们不借助于其它的硬件,而是让 PC 机上的两个串口互换数据,即 COM1发送 COM2 接收,而 COM2 发送则由 COM1 接收,为此,需要做一根连接线将这两个串口连起来, 做法很简单,找两个可以插入 PC 机串口的 DIN9 插座(母),然后用一根 3 芯线将它们连起 来,连线的方法是: 2—— 3 3—— 2 5—— 5 接好线把两个插头分别插入 PC 机上的串口 1 与串口 2。找一个 PC 机上的串口终端调试软件,如串口 精灵 之类,运行该软件,设置好串口参数,其中串口选择 2,串口参数设置为: 19200, n , 8, 1 其含义是波特率为 19200,无奇偶校验, 8 位数据, 1 位停止位。 在 Keil 调试窗口的 command 页中输入: >mode com1 19200,0,8,1 >assign com1 注意两行最前面的 “ >”是提示符, 不要输入, 第二行中的 “ <”和“>”即“小于”和“大 于”符号,中间的是字母“ s ”和“ input ”的前两个字母,最后是字母“ s ”和“ output ”的 前三个字母。 第一行命令定义串口 1 的波特率为 19200,无奇偶校验, 8 位数据, 1 位停止位。第二 行是将串口 1(com1)分配给串行窗口。 全速运行程序,然后切换串口精灵,开始发送,会看到发送后的数据会立即回显到窗口 中,说明已接收到了发送过来的数据。切换到 uVison ,查看串行窗口 1,会看到这里的确接收 到了串口精灵送来的内容。 二、从端口送入信号 程序调试中如果需要有信号输入, 比如数据采集类程序, 需要从外界获得数据, 由于 Keil 的调试完全是一个软件调试工具,没有硬件与之相连,所以不可能直接获得数据,为此必须 采用一些替代的方法, 例如,某电路用 P1 口作为数据采集口, 那么可以使用的一种方法是利 用外围接口,打开 PORT 1,用鼠标在点击相应端口位,使其变为高电平或低电平,就能输入 数据。显然,这种方法对于要输获得数据而不是作位处理来说太麻烦了,另一种方法是直接 在 command 页输入 port1=数值,以下是一个小小的验证程序。例 7: LOOP: MOV A,P1 JZ NEXT MOV R0,#55H JMP LOOP NEXT: MOV R0,#0AAH JMP LOOP END 该程序从 P1 口获得数据,如果 P1 口的值是 0,那么就让 R0 的值为 0AAH ,否则让 R0的值 为 55H 。输入源程序并建立工程,进入调试后,在观察窗口加入 R0,然后全速运行程序,注意 确保 View->Periodic Window U pdata 处于选中状态,然后在 Command 后输入 PORT1=0 回车后 可以发现观察窗口中的 R0 的值变成了 0AAH ,然后再输入 PORT1=1 或其它非零值,则 R0 的值 会变为 55H 。 同样的道理,可以用 port0、 port2、 port3 分别向端口 0、 2、 3 输入信号。 三、直接更改内存值 在程序运行中, 另一种输入数据的方法是直接更改相应的内存单元的值, 例如, 某数据采集程序, 使用 30H 和 31H 作为存储单元,采入的数据由这两个单元保存,那么我们更改了 30H 和 31H 单元的值就相当于这 个数据采集程序采集到了数据, 这可以在内存窗口中直接修改 (参考上一讲) ,也可以通过命令进行修改, 命令的形式是:_WBYTE (地址 , 数据 ) ,其中地址是指待写入内存单元的地址, 而数据则是待写入该地址 的数据。例如 _WBYTE(0x30,11)会将值 11 写入内存地址十六进制 30H 单元中。 Keil 程序调试窗口 上一讲中我们学习了几种常用的程序调试方法,这一讲中将介绍 Keil 提供各种窗口如 输出窗口、观察窗口、存储器窗口、反汇编窗口、串行窗口等的用途,以及这些窗口的使用 方法,并通过实例介绍这些窗口在调试中的使用。 Keil 软件在调试程序时提供了多个窗口,主要包括输出窗口(Output Windows) 、观察 窗口 (Watch&Call Statck Windows) 、 存储器窗口 (Memory Window) 、 反汇编窗口 (Dissambly Window )串行窗口(Serial Window)等。进入调试模式后,可以通过菜单 View 下的相应命 令打开或关闭这些窗口。 图 1是输出窗口、 观察窗口和存储器窗口, 各窗口的大小可以使用鼠标调整。 进入调试 程序后,输出窗口自动切换到 Command 页。该页用于输入调试命令和输出调试信息。对于 初学者,可以暂不学习调试命令的使用方法。 1、存储器窗口 存储器窗口中可以显示系统中各种内存中的值,通过在 Address 后的编缉框内输入“字 母:数字”即可显示相应内存值,其中字母可以是 C 、 D 、 I 、 X ,分别代表代码存储空间、 直接寻址的片内存储空间、间接寻址的片内存储空间、扩展的外部 RAM 空间,数字代表想 要查看的地址。例如输入 D :0即可观察到地址 0开始的片内 RAM 单元值、键入 C :0即 可显示从 0开始的 ROM 单元中的值,即查看程序的二进制代码。该窗口的显示值可以以各 种形式显示,如十进制、十六进制、字符型等,改变显示方式的方法是点鼠标右键,在弹出 的快捷菜单中选择, 该菜单用分隔条分成三部份, 其中第一部份与第二部份的三个选项为同 一级别,选中第一部份的任一选项,内 容将以整数形式显示,而选中第二部份 的 Ascii 项则将以字符型式显示,选中 Float 项将相邻四字节组成的浮点数形 式显示、 选中 Double 项则将相邻 8字节 组成双精度形式显示。第一部份又有多 个选择项, 其中 Decimal 项是一个开关, 如果选中该项,则窗口中的值将以十进 制的形式显示,否则按默认的十六进制 方式显示。 Unsigned 和 Signed 后分别有 三个选项:Char 、 Int 、 Long ,分别代表以单字节方式显示、将相邻双字节组成整型数方式 图 1 调试窗口(命令窗口、存储器窗口、观察窗口) 图 2 存储器数值各种方式显示选择 显示、将相邻四字节组成长整型方式显示,而 Unsigned 和 Signed 则分别代表无符号形式和 有符号形式, 究竟从哪一个单元开始的相邻单元则与你的设置有关, 以整型为例, 如果你输 入的是 I:0, 那么 00H 和 01H 单元的内容将会组成一个整型数, 而如果你输入的是 I :1, 01H 和 02H 单元的内容全组成一个整型数,以此类推。有关数据格式与 C 语言规定相同,请参 考 C 语言书籍,默认以无符号单字节方式显 示。第三部份的 Modify Memory at X:xx用于 更改鼠标处的内存单元值, 选中该项即出现如 图 3所示的对话框, 可以在对话框内输入要修 改的内容。 2、工程窗口寄存器页 图 4是工程窗口寄存器页的内容,寄存器页包括了当前的工作寄存器组和系统寄存器, 系统寄存器组有一些是实际存在的寄存器如 A 、 B 、 DPTR 、 SP 、 PSW 等,有一些是实际中 并不存在或虽然存在却不能对其操作的如 PC 、 Status 等。每当程序中执行到对某寄存器的 操作时,该寄存器会以反色(蓝底白字)显示,用鼠标单击然后按下 F2键,即可修改该值。 3、观察窗口 观察窗口是很重要的一个窗口, 工程窗口中仅可以观察到 工作寄存器和有限的寄存器如 A 、 B 、 DPTR 等,如果需要观 察其它的寄存器的值或者在高级语言编程时需要直接观察变 量,就要借助于观察窗口了。 其它窗口将在以下的实例中介绍。 一般情况下, 我们仅在单步执行时才对变量的值的变化感 兴趣, 全速运行时, 变量的值是不变的, 只有在程序停下来之 后, 才会将这些值最新的变化反映出来, 但是, 在一些特殊场 合下我们也可能需要在全速运行时观察变量的变化, 此时可以 点击 View->Periodic Window Updata(周期更新窗口) , 确认该 项处于被选中状态, 即可在全速运行时动态地观察有关值的变 化。但是,选中该项,将会使程序模拟执行的速度变慢。 二、各种窗口在程序调试中的用途 以下通过一个高级语言程序来说明这些窗口的使用。例 2: #include sbit P1_0=P1^0; //定义 P1.0 void mDelay(unsigned char DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;}="">125;j++)> } void main() { unsigned int i; for(;;){ mDelay(10); //延 时 10毫秒 i++; if(i==10) { P1_0=!P1_0; i=0; } } } 这个程序的工作过程是:不断调用延时程序, 每次延时 10毫秒, 然后将变量 I 加 1, 随 后对变量 I 进行判断,如果 I 的值等于 10,那么将 P1.0取反,并将 I 清 0,最终的执行效果 图 4 工程窗口寄存器页 是 P1.0每 0.1S 取反一次。 输入源程序并以 exam2.c 为文件名存盘, 建立名为 exam2的项目, 将 exam2.c 加入项目, 编译、连接后按 Ctrl+F5进入调试,按 F10单步执行。注意观察窗口,其中有一个标签页为 Locals , 这一页会自动显示当前模块中的变量名及变量值。 可以看到窗口中有名为 I 的变量, 其值随着执行的次数而逐渐加大, 如果在执行到 mDelay(10)行时按 F11跟踪到 mDelay 函数 内部, 该窗口的变量自动变为 DelayTime 和 j 。 另外两个标签页 Watch #1和 Watch #2可以加 入自定义的观察变量,点击“ type F2 to edit”然后再按 F2即可输入变量,试着在 Watch #1中输入 I ,观察它的变化。在程序较复杂,变量很多的场合,这两个自定义观察窗口可以筛 选出我们自己感兴趣的变量加以观察。 观察窗口中变量的值不仅可以观察, 还可以修改, 以 该程序为例, I 须加 10次才能到 10,为快速验证是否可以正确执行到 P1_0=!P1_0行,点击 I 后面的值,再按 F2,该值即可修改,将 I 的值改到 9,再次按 F10单步执行,即可以很快 执行到 P1_0=!P1_0程序行。该窗口显示的变量值可以以十进制或十六进制形式显示,方法 是在显示窗口点右键,在快捷菜单中选择如图 5所示。 点击 View->Dissambly Window可 以打开反汇编窗口,该窗口可以显示反 汇编后的代码、源程序和相应反汇编代 码的混合代码,可以在该窗口进行在线 汇编、利用该窗口跟踪已找行的代码、 在该窗口按汇编代码的方式单步执行, 这也是一个重要的窗口。打开反汇编窗口,点击 鼠标右键, 出现快捷菜单, 如图 6所示, 其中 Mixed Mode 是以混合方式显示, Assembly Mode是以反 汇编码方式显示。 程序调试中常使用设置断点然后全速运行的 方式,在断点处可以获得各变量值,但却无法知 道程序到达断点以前究竟执行了哪些代码,而这 往往是需要了解的,为此, Keil 提供了跟踪功能, 在运行程序之前打开调试工具条上的允许跟踪代 码开关,然后全速运行程序,当程序停止运行后, 点击查看跟踪代码按钮,自动切换到反汇编窗口, 如图 6所示,其中前面标有“ -”号的行就是中断以前执行的代码,可以按窗口边的上卷按 钮向上翻查看代码执行记录。 利用工程窗口可以观察程序执行的时间, 下面我们观察一下该例中延时程序的延时时间 是否满足我们的要求,即是否确实延时 10毫秒,展开工程窗口 Regs 页中的 Sys 目录树,其 中的 Sec 项记录了从程序开始执行到当前程序流逝的秒数。点击 RST 按钮以复位程序, Sec 的值回零, 按下 F10键, 程序窗口中的黄色箭头指向 mDelay(10)行, 此时, 记录下 Sec 值为 0.00038900,然后再按 F10执行完该段程序,再次查看 Sec 的值为 0.01051200,两者相减大 约是 0.01秒,所以延时时间大致是正确的。读者可以试着将延时程序中的 unsigned int改为 unsigned char试试看时间是否仍正确。 注意, 使用这一功能的前提是在项目设置中正确设置 晶振的数值。 Keil 提供了串行窗口, 我们可以直接在串行窗口中键入字符, 该字符虽不会被显示出来, 但却能传递到仿真 CPU 中, 如果仿真 CPU 通过串行口发送字符, 那么这些字符会在串行窗 口显示出来, 用该窗口可以在没有硬件的情况下用键盘模拟串口通讯。 下面通过一个例子说 明 Keil 串行窗口的应用。该程序实现一个行编缉功能,每键入一个字母,会立即回显到窗 图 5 设定观察窗的显示方式 图 6 反汇编窗口 口中。编程的方法是通过检测 RI 是否等于 1来判断串行口是否有字符输入,如果有字符输 入,则将其送到 SBUF ,这个字符就会在串行窗口中显示出来。其中 ser_init是串行口初始 化程序,要使用串行口,必须首先对串行口进行初始化。例 3: MOV SP,#5FH ;堆栈初始化 CALL SER_INIT ; 串行口初始化 LOOP: JBC RI,NEXT ;如果串口接收到字 符,转 JMP LOOP ; 否则等待接收字符 NEXT: MOV A,SBUF ;从 SBUF 中取字符 MOV SBUF,A ; 回送到发送 SBUF 中 SEND: JBC TI,LOOP ;发送完成,转 LOOP JMP SEND ; 否则等待发送完 SER_INIT: ;中断初始化 MOV SCON,#50H ORL TMOD,#20H ORL PCON,#80H MOV TH1,#0FDH ;设定波特率 SETB TR1 ; 定时器 1开始运行 SETB REN ; 允许接收 SETB SM2 RET END 输入源程序,并建立项目,正确编译、连接,进入调试后,全速运行,点击串行窗口 1按钮,即在原源程序窗口位置出现一个空白窗口,击键,相应的字母就会出现在该窗口中。 在窗口中击鼠标右键,出现一个弹出式菜单,选择“ Ascii Mode”即以 Ascii 码的方式显示 接收到的数据; 选择 “ Hex Mode” 以十六进制码方式显示接收到的数据; 选择 “ Clear Window” 可以清除窗口中显示的内容。 由于部份 CPU 具有双串口, 故 Keil 提供了两个串行窗口, 我们选用的 89C51芯片只有 一个串行口,所以 Serial 2串行窗口不起作用。 小技巧:凡是鼠标单击然后按 F2的地方都可以用鼠标连续单击两次 (注意:不是双击) 来替代。 转载请注明出处范文大全网 » proteus与keil仿真范文三:keil c51实例教程
范文四:keil_μVision4使用详解教程
范文五:keil调试各种窗口用途介绍