2.1 Keil C51软件的基本使用
2.1.1 认识Keil C51软件
单片机开发中除必要的硬件外,同样离不开软件,我们写的汇编语言源程序要变为CPU可以执行的机器码有两种方法,一种是手工汇编,另一种是机器汇编。机器汇编是通过汇编软件将源程序变为机器码,用于MCS-51单片机的汇编软件有早期的A51,随着单片机开发技术的不断发展,从普遍使用汇编语言到逐渐使用高级语言开发,单片机的开发软件也在不断发展,Keil软件是目前最流行开发MCS-51系列单片机的软件。
Keil C51 μVision4是美国Keil Software公司出品的51系列兼容单芯片C语言整合发展环境(Integrated Development Environment,IDE),与汇编语言相比,C语言在功能上、架构性、可读性、可维护性上有明显的优势,因而易学易用。
Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(μVision)将这些部分组合在一起。该软件提供丰富的函数库和功能强大的除错工具,以及全窗口界面,编译后生成的汇编语言代码效率非常高,多数语句生成的汇编语言代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的便利与优势。
下面我们来学习Keil C51软件的基本操作方法。
2.1.2 Keil C51操作步骤
1.启动Keil C51软件
当正确安装了该软件后,就会在桌面上建立名为“Keil μVision4”的一个快捷图标,我们只需双击这个快捷图标就可以启动该软件,打开如图2-1所示窗口。

图2-1 Keil C51启动后窗口
2.建立工程文件
(1)在如图2-1所示的工作窗口中,单击“Project”→“New μVision Project”菜单命令,打开“Create New Project”对话框,如图2-2所示。

图2-2 建立工程文件
(2)在“保存在”下拉列表框中,选择工程保存目录(如F:\Mytest\test1),并在“文件名”文本框中输入工程名字(如test1),不需要加扩展名,然后单击“保存”按钮,出现如图2-3所示的选择目标器件“Select Device for Target”对话框。

图2-3 选择目标器件窗口
(3)在图2-3中,这个对话框要求选择目标CPU(即所用芯片的型号),Keil支持的CPU很多,我们选择Atmel公司的AT89C51芯片。单击左侧列表框中“Atmel”项前面的“+”号,展开该层,单击其中的“AT89C51”,如图2-4所示,然后再单击“OK”按钮,完成选择MCU型号。

图2-4 选择目标CPU
(4)在完成选择MCU型号后,软件会打开如图2-5所示窗口,提示我们是否要复制标准的8051启动代码到这个工程中,单击“是(Y)”按钮回到主界面,如图2-6所示。

图2-5 复制标准8051启动代码选择窗口

图2-6 建立工程后的主界面
(5)在执行上一步后,就能在工程窗口的文件页中,出现“Target 1”工程,前面有“+”号,单击“+”号展开,可以看到下一层的“Source Group 1”,这时的工程是一个空的工程,但有一个“STARTUP.A51”文件。
STARTUP.A51文件的主要作用是:上电时初始化单片机的硬件堆栈、初始化RAM、初始化模拟堆栈和跳转到主函数即main函数。硬件堆栈是用来存放函数调用地址、变量和寄存器值的;模拟堆栈是用来存放可重入函数的,可重入函数就是同时给多个任务调用,而不必担心数据的丢失,可重入函数一般在嵌入式系统中有所体现。
如果不加载STARTUP.A51文件,编译的代码可能会使单片机工作异常。
3.建立并添加源文件
(1)单击“File”→“New”菜单命令,出现如图2-7所示的文本编辑窗口,在该窗口中输入源程序。

图2-7 文本编辑窗口
(2)对输入的程序检查后,单击“File”→“Save As…”菜单命令,打开文件另存为对话框,如图2-8所示。在“文件名”右边的文本框中输入源文件的名字和后缀名,源文件名的后面必须加扩展名“.c”,如test.c,用于区别其他源文件,例如汇编语言源文件的扩展名为“.asm”,头文件的扩展名为“.h”等。
(3)在如图2-9所示的工程管理窗口中“Source Group 1”项上单击鼠标右键,打开快捷菜单,选择“Add Files to Group ‘Source Group 1’…”菜单命令,出现如图2-10所示窗口。在“文件类型”下拉列表框中选择“C Source file(*.c)”项,找到前面新建的“test.c”文件并选择后,单击“Add”按钮把源文件加入工程中。

图2-8 源程序保存界面

图2-9 添加源文件到工程中
(4)在文件加入项目后,该对话框并不消失,等待继续加入其他文件,但初学时常会误认为操作没有成功而再次双击同一文件,这时会出现如图2-11所示的对话框,提示你所选文件已在列表中。在工程管理窗口“Source Group 1”项中会出现名为“test.c”的文件,说明源文件的添加已经完成,如图2-12所示。

图2-10 选择文件类型及添加源文件

图2-11 提醒文件已在工程中

图2-12 源文件添加后窗口
4.配置工程属性
(1)如图2-13所示,在工程管理窗口的“Target 1”上,单击鼠标右键,再选择“Options for Target‘Target1’”菜单命令,如图2-13所示,也可以按快捷键“Alt”+“F7”来完成,还可以单击快捷图标
来完成,弹出如图2-14所示的目标属性窗口,这个对话框比较复杂,有多个选项卡,绝大部分设置项取默认值就可以。

图2-13 配置工程属性

图2-14 目标属性“Target”选项卡
(2)如图2-14所示,“Xtal(MHz)”后面的数值是晶振频率值,默认值是所选目标CPU的最高可用频率值,对于我们所选的AT89C51而言是24 MHz,该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同,如果没必要了解程序执行的时间,也可以不设。
(3)在如图2-15所示窗口中单击“Output”选项卡,打开“Output”选项设置页面,如图2-15所示,选中“Creat HEX File”复选框,再单击“OK”按钮。该选项用于生成可执行代码文件(可以用编程器写入单片机芯片的HEX格式文件,文件的扩展名为.HEX),默认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项,这一点是初学者易疏忽的,在此特别提醒注意。按钮“Select Folder for Objects...”是用来选择最终的HEX目标文件所在的文件夹,默认是与工程文件在同一个文件夹中。

图2-15 “Output”选项卡
5.编译工程
(1)在设置好工程后,即可进行编译、连接。选择“Project”→“Build target”命令,或者单击快捷图标“
”对当前工程进行连接,如果当前文件已修改,软件会先对该文件进行编译,然后再连接以产生目标代码;如果选择“Rebuild all target files”命令,或者单击快捷图标“
”,将会对当前工程中的所有文件重新进行编译然后再连接,确保最终生产的目标代码是最新的,而“Translate…”项则仅对该文件进行编译,不进行连接,如图2-16所示。
(2)编译完成后,在输出窗口中查看出现的编译结果信息,如图2-17所示。如果提示“creating hex file from 'test1'…”表示获得了HEX的文件,出现“0 Error(s),0 Warning(s)”表示编译成功。如果编译后又修改了源程序,一定要重新进行编译,产生新的HEX目标文件。

图2-16 编译工程

图2-17 编译结果
(3)当源程序有语法错误时,编译不会成功,会出现如图2-18所示的输出信息。

图2-18 编译不成功输出信息
编译不成功的原因有很多,在输出窗口信息中会给出错误或警告的行号、错误代码、错误原因等,并有“Target not created”的提示。例如对如图2-18所示的错误信息详细解释如下:(https://www.daowen.com)
TEST.C(9): error C202: 'P1_0':undefined identifier
源程序名(行号) 错误代码 P1_0是未定义的变量
在源程序修改错误,再次编译,经过多次修改后,直至编译成功生成HEX目标文件。生成的目标文件可以下载到硬件电路运行,或者下载到Proteus仿真软件的电路来进行仿真运行。
2.1.3 Keil C51的程序仿真调试
在前面我们学习了如何建立工程、汇编、连接工程,并获得目标代码,但是做到这一步仅仅代表你的源程序没有语法错误,至于源程序中存在着的其他错误,还需要把目标代码加载到单片机中运行才能看到程序的执行结果。如果手边没有硬件下载工具,可以直接采用软件进行仿真调试,发现问题并解决。事实上,除了极简单的程序以外,绝大部分的程序都要通过反复调试才能得到正确的结果,因此,调试是软件开发中的一个重要环节。Keil C51内建了一个仿真CPU可以模拟执行程序,利用在线汇编、各种设置断点进行程序调试。
1.打开工程,配置软件仿真器
在Keil C51主界面中,单击“Open”→“Open Project…”菜单命令,找到工程所在目录,打开工程。
将光标移到工程管理窗口的“Target 1”上,单击鼠标右键,选择“Options for Target‘Target1’”菜单命令,打开工程配置窗口,如图2-19所示,将“Xtal(MHz)”选项改为“12.0”,因为在本任务中,选用晶振频率为12 MHz。

图2-19 工程配置窗口
“Memory Model”用于设置RAM使用情况,有三个选择项,“Small:variables in DATA”是所有变量都在单片机的内部RAM中;“Compact:variables in PDATA”是可以使用一页(256 B)外部扩展RAM,而“Large:variables in XDATA”则是可以使用全部64 KB外部的扩展RAM。一般都是采用默认方式,也就是“Small:variables in DATA”方式。
“Code Rom Size”用于设置ROM空间的使用,同样也有三个选择项,即“Small:program 2K or less”模式,只用低于2 KB的程序空间;“Compact:2K functions,64K program”模式,表示单个函数的代码量不能超过2 KB,整个程序可以使用64 KB程序空间;“Larger:64K program”模式,表示可用全部64 KB空间。一般都是采用默认方式,也就是“Larger:64K program”模式。
“Operating system”项是操作系统选择,Keil提供了两种操作系统:RTX-51 Tiny 和RTR-51 Full,通常我们不使用任何操作系统,即使用该项的默认值:None(不使用任何操作系统)。
“Use on-chip ROM”选择项,确认是否仅使用片内ROM(注意:选中该项并不会影响最终生成的目标代码量);“Off-chip Code memory”用以确定系统扩展ROM的地址范围,“Off-chip Xdata memory”组用于确定系统扩展RAM的地址范围,这些选择项必须根据所用硬件来决定,一般按默认值设置。
在图2-19中单击“Debug”选项卡,打开如图2-20所示窗口,选中“Use Simulator”单选按钮,再单击“OK”按钮。该选项默认是已经选择的。

图2-20 选择仿真方式
2.编译工程
在主界面中,单击“Project”菜单命令,在下拉菜单中选择“Project”→“Build all target files”命令,或者单击快捷图标“
”对当前工程进行编译。
3.启动调试
在主界面中,单击“Debug”菜单命令,在下拉菜单中选择“Start/Stop Debug Session”命令或者单击快捷图标
或者按快捷键“Ctrl”+“F5”,如图2-21所示,进入调试主界面,如图2-22所示。

图2-21 调试开始/结束命令

图2-22 调试主界面
反汇编窗口提供了C语言源程序中的每条语句编译成汇编语言和机器语言的内容,例如:语句“P1_0=0;”反汇编后的结果如下:
C:0x0015 C290 CLR P1_0(0x90,0)
Code首地址 机器语言 汇编指令
该指令在程序存储器中的存放情况如下:
地址 代码
0x0015 C2
0x0016 90
4.程序执行
进入调试状态后,界面与编辑状态相比有明显的变化,“Debug”菜单项中原来不能用的命令现在已可以使用了,工具栏会多出一个用于运行和调试的工具条,如图2-23所示,“Debug”菜单上的大部分命令可以在此找到对应的快捷按钮,从左到右依次是复位(RST)、全速连续运行调试(Run,F5)、停止(Stop)、单步跟踪运行调试(Step,F11)、单步运行调试(Step Over,F10)、执行完当前子程序(Step Out,“Ctrl”+“F11”)、全速运行至光标处调试(Run to Cursor Line,“Ctrl”+“F10”)等命令,在工具栏上还有设置断点(Breakpoints)相关命令。
![]()
图2-23 调试工具条
学习程序调试,必须明确两个重要的概念,即单步运行与全速运行。全速运行是指一行程序执行完以后紧接着执行下一行程序,中间不停止,这样程序执行的速度很快,并可以看到该段程序执行的总体效果,即最终结果正确还是错误,但如果程序有错,则难以确认错误出现在哪些程序行。单步运行是每次执行一行程序,执行完该行程序以后即停止,等待命令执行下一行程序,此时可以观察该行程序执行完以后得到的结果,是否与我们写该行程序所想要得到的结果相同,借此可以找到程序中问题所在。程序调试中,这两种运行方式都要用到。
(1)全速连续运行调试(Run,F5):从当前地址PC开始全速运行用户程序(碰到断点,则停止运行)。这种方法可以完全模拟单片机应用的真实运行状态,硬件仿真时执行连续运行方式,便于观察程序连续运行状态下相关显示及控制过程的动态变化过程。但无法观察某条语句或某段语句的运行结果,只能根据系统运行中所完成的显示及控制过程的变化结果来判断程序运行的正确与否。因此,软件仿真时通常是将连续运行与设置断点二者一起结合起来使用。
(2)单步运行调试(Step Over,F10):每按一次“F10”键,黄色箭头向下移动一条语句,表示上一条语句已执行完毕。
(3)单步跟踪运行调试(Step,F11):每按一次“F11”键,黄色箭头向下移动一条语句,系统就执行一条语句。与单步运行“F10”不同的是:“F11”可以跟踪到函数内部执行,而“F10”只是把函数作为一个语句执行,分别用“F10”和“F11”键执行函数delay(10000)语句,就会发现二者的不同之处了。
(4)全速运行至光标处调试(Run to Cursor Line,“Ctrl”+“F10”):如果想有针对性地快速观察程序运行到某条语句处的结果,可预先将光标移到该条语句处,再按“Ctrl”+“F10”组合键,程序将从当前所指示的位置全速运行到光标处。
(5)执行完当前子程序(Step Out,“Ctrl”+“F11”):连续运行到子程序最后,退出子程序,返回调用的下一行。
(6)设置断点调试(Breakpoints):为了快速检查程序运行至某一关键位置处的结果,可以在指定语句前设置断点,该指令前将出现一个红色标记,表示此处已被设置为断点。再按“F5”键,从当前语句全速运行程序,至断点处就会停止。
与全速运行至光标处调试(“Ctrl”+“F10”)方法相比,断点调试时对断点有记忆功能,当再次重复调试程序时,每当程序运行到断点处都会停在该断点处。此方法特别适用于循环程序的调试。根据需要也可在程序的不同位置设置多个断点,当不需要断点运行时,删除断点即可。
5.观察单片机内部资源的当前状况
Keil C51软件在调试程序时提供了多个窗口,主要包括输出窗口(Output Windows)、观察窗口(Watch Windows)、调用堆栈窗口(Call Stack Window)、存储器窗口(Memory Window)、反汇编窗口(Disassembly Window)、串行窗口(Serial Window)等。进入调试模式后,可以通过“View”菜单下的相应命令打开或关闭这些窗口。在单步、跟踪、断点等运行方式下,都可以通过这些窗口查看单片机内部资源的当前状态,这些状态对用户调试程序非常有帮助。
(1)观察存储器内容。
在调试主界面下,单击“View”→“Memory Windows”→“Memory 1”菜单命令,打开显示存储器窗口。在下部的“Address”文本框中输入“字母:数字”格式的地址即可显示相应内存值,其中字母可以是C、D、I、X,分别代表代码存储空间、直接寻址的片内存储空间、间接寻址的片内存储空间、扩展的外部RAM空间,数字代表想要查看的地址。例如输入“D:0”即可观察到地址0开始的片内RAM单元值,键入“C:0”即可显示从0开始的ROM单元中的值,即查看程序的二进制代码,如图2-24所示。

图2-24 显示存储器窗口
(2)观察寄存器状态。
如图2-25所示是工程寄存器窗口的内容,寄存器页包括了当前的工作寄存器组和系统寄存器,系统寄存器组有一些是实际存在的寄存器,如A、B、DPTR、SP、PSW等,有一些是实际中并不存在或虽然存在却不能对其操作的如PC、States等。每当程序中执行到对某寄存器的操作时,该寄存器会以反色(蓝底白字)显示,用鼠标单击然后按下“F2”键,即可修改该值。

图2-25 寄存器窗口
还可以利用其中系统寄存器的“sec”项计算延时函数的延时时间。
在调试主界面单击“Debug”→“Reset CPU”命令,使系统复位。将源程序的光标定位在第一个“delay(10000);”语句上,按下“Ctrl”+“F10”组合键全速运行至光标处,运行结果如图2-26所示。

图2-26 运行到光标处的调试界面
主界面左侧窗口中的“sec”项自动记录程序的执行时间,单位为s。系统复位时,sec=0;执行到光标处所花的时间,sec=0.00039000 s。
在该界面按下“F10”键单步运行程序,此时再次记录sec=0.12044500 s。
两者之差即为延时函数delay(10000)执行所花的时间0.12005500 s。
(3)观察I/O端口当前的状态。
在调试主界面下,单击“Peripherals”→“I/O-Ports”→“Port 1”菜单命令,打开如图2-27所示的P1端口观察窗口。在图中,“√”表示该位为1,空白表示该位为0。当程序调试运行时,在图中可以随时观察、修改P1端口寄存器中的内容。

图2-27 P1端口观察窗口