【51单片机学习笔记】Keil软件使用方法

一、KeilμVision4的工作界面

        KeilμVision4运行在Windows操作系统上,其内部集成了Keil C51编译器,集项目管理、编译工具、代码编写工具、代码调试以及完全仿真于一体,提供了一个简单易用的开发平台。C51编译器将用户编写的51单片机C语言“翻译”为“机器语言(低级语言)”的程序。

二、KeilμVision4的菜单栏

1.File(文件)菜单:提供文件相关操作功能

New:新建一个文本文件,需要通过保存才能成为对应的.h或者.c文件.
Open:打开一个已经存在的文件.
Close:关闭一个当前打开的文件.
Save:保存当前文件.
SaveAs:把当前文件另存为另外一个文件.
SaveAll:保存当前已打开的所有文件.
DeviceDatabase:打开元器件的数据库.
LicenseManagement:许可证管理,用于对 KeilμVision4的使用许可证进行管理.
PrintSetup:设置打印机.
Print:打印当前的文件.
PrintPreview:预览打印效果.
1~9+文件名称:打开最近使用的文件.
Exit:退出.

2Edit(编辑)菜单:提供文本编辑和操作相关功能

Undo:撤销上一次的操作.
Redo:恢复上一次的操作.
Cut:剪切选定的内容到剪切板.
Copy:复制选定的内容到剪切板.
Paste:把剪切板中的内容粘贴到指定位置.
NavigateBackwards:向后导航.
NavigateForwards:向前导航.
Insert/RemoveBookmark:在光标当前行插入/移除书签标记.
GotoNextBookmark:跳转到下一个书签标记处.
GotoPreviousBookmark:跳转到前一个书签标记处.
ClearAllBookmarks:清除所有的书签标记.
Find:在当前编辑的文件中查找特定的内容.
Replace:用当前内容替换特定的内容.
FindinFiles:在几个文件中查找特定的内容.
IncrementalFind:增量查找.
Outlining:用于对代码中的函数标记(大括号等)进行配对.
Advanced:一些高级的操作命令,包括查找配对大括号等.
Configuration:对 KeilμVision4集成开发环境进行配置,按下时弹出如图所示设置对话框,在其中可以对缩进、字体大小和颜色、快捷键等基础属性进行配置.

3.View(视图)菜单:提供界面显示内容的设置相关操作

StatusBar:显示或者隐藏状态栏.
Toolbars:显示或者隐藏工具栏,包括文件工具栏和编译工具栏这两个子选项.
ProjectWindow:显示或者隐藏项目窗口.
BooksWindow:显示或者隐藏手册窗口.
FunctionsWindow:显示或者隐藏函数窗口.
TemplatesWindow:显示或者隐藏模板窗口.
SourceBrowserWindow:显示或者隐藏源文件浏览器窗口.
BuildOutputWindow:显示或者隐藏编译输出窗口.
ErrorListWindow:显示或者隐藏错误目录窗口.
FindinFilesWindow:显示或者隐藏在多个文件中查找窗口.

4.Project(项目)菜单:提供工程文件的配置管理以及目标代码的生成管理 相关操作功能

NewμVisionProject:建立一个新的工程文件.
New MultiGProjectWorkspace:新建一个多项目工作区.
OpenProject:打开一个工程文件.
SaveProjectinμVision4format:保存当前μVision4格式中的工程文件.
CloseProject:关闭当前工程文件.
Export:导出当前项目,可选择将当前项目导出为μVision3格式.
Manage:项目管理,在其中可以对组件和窗口进行管理,还可以设置各种文件类型 的扩展名,在项目窗口中添加书籍,以及设置工作目录环境.
SelectDeviceforTarget'Target1':从设备数据库中选出一款51单片机作为当前目 标器件.
RemoveItem:从当前的工程文件中删除一个文件.
OptionsforTarget 'Target1':更改当前目标的文件组或者文件的工具选项.
Cleantarget:清除当前目标.
Buildtarget:编译并且链接当前的工程文件.
Rebuildalltargetfiles:重新编译并且链接当前的工程文件.
BatchBuild:批处理编译并且链接.
Translate:只编译不链接当前工程文件.
Stopbuild:停止当前的编译链接.
1~3+项目名:打开最近使用过的3个项目.

5.Flash(Flash存储器)菜单:提供对51单片机的内部 Flash进行在线下载和擦除等相关操作功能

Download:下载程序到 Flash存储器中.
Erase:擦除 Flash存储器中内容.
ConfigureFlashTools:打开 Flash存储器的配置工具.

6.Debug(调试)菜单:提供在软件和硬件仿真环境下的调试相关功能

Start/StopDebugSession:开始或者结束调试模式.
ResetCPU:复位处理器.
Run:开始运行,如果有断点则停止.
Stop:停止运行.
Step:单步运行程序,包括子程序的内容.
StepOver:单步运行程序,遇到子程序则一步跳过.
StepOut:单步运行程序时,跳出当前所进入的子程序,进入该子程序的下一条 语句.
RuntoCursorLine:运行至光标行.
Show NextStatement:显示下一个可以执行的语句.
Breakpoints:打开断点对话框.
Insert/RemoveBreakpoint:在当前行设定或者去除断点.
Enable/DisableBreakpoint:使能或者去掉当前行的断点.
DisableAllBreakpoints:设定程序中所有的断点无效.
KillAllBreakpoints:去除程序中所有的断点.
OSSupport:操作系统支持,可以选择在当前项目中使用的嵌入式操作系统.
ExecutionProfiling:执行配置文件.
MemoryMap:打开内存对话框.
InlineAssembly:停止当前编译的进程.
FunctionEditor(OpenIniFile):编辑调试程序和调试用ini文件.

7.Peripherals(串行接口)菜单:主要用于在 Debug(调试)模式下打开其外围接口观察窗
8.Tools(工具)菜单:主要用于和第三方软件联合调试

Set-up PC-Lint:从 Gimpel软件中配置 PC.Lint.
Lint:在当前编辑的文件中使用 PC.Lint.
Lint All C-SourceFiles:在项目所包含的 C 文件中使用 PC.Lint.
Customize Tools Menu:在工具菜单中加入用户程序.

9.SVCS(版本控制)菜单:主要用于对工程项目进行版本挖掘

10.Window(窗口)菜单:主要用于提供窗口的视图管理

Reset View to Defaults:恢复默认设置.
Split:把当前窗口分割成2~4块.
CloseAll:关闭所有打开的窗口.
1~2+窗口名:显示所选择的窗口.

11.Help(帮助)菜单:主要用于给使用者提供包括库函数查询在内的帮助管理

μVision Help:打开 KeilμVision4的帮助主题.
Open Books Window:打开 KeilμVision4提供的参考书籍窗口.
Simulated Peripherals for 'AT89C51':为所选择的 51 单片机内部集成资源说明文档. 
Contact Support:联系 Keil公司技术支持.
Check for Update:查看版本更新.
About μVision:KeilμVision的版本号.

三、Keil工程的建立

        利用KeilμVision4进行单片机的软件开发,首先就要在该软件平台上建立一个工程。这里说的工程实际上是一个文件组,它包含了软件开发过程中产生的各种文件,针对每个程序都有一个工程,就是和这个程序相关的全部文件。

        建立一个新的工程,先要单击Project菜单中的NewμVision Project选项,此时会自动弹出一个创建新工程对话框。

        首先要在最上面的框里输入保存的路径,应该将一个工程单独放在一个文件夹下。再在下面的文件名处输入要保存的新工程名,然后按下保存按钮,就建立了一个新工程。

        此时会自动弹出如图所示选择单片机型号对话框。可以根据当前使用的单片机选择型号。

        完成后,窗口界面如图所示。

        单击File菜单中的New菜单项,或单击对应的快捷图标,会自动弹出新建文件窗口

        当程序输入完成后,单击保存按钮,弹出的界面如图所示。在下面的文件名框中输入想保存的文件名,注意扩展名一定要输入正确。这里是用C语言编写的程序,文件名的后缀一定是.c;如果输入的是汇编程序,文件名的后缀一定是.asm

        回到编辑界面,单击项目管理窗口Target1前面的“+”号,在下面出现的Source Group1选项上单击右键,弹出菜单。

        然后在其中选择Add Existing Files to Group ‘Source Group1’,弹出对话框

        我们刚才新建的文件名是cc.c,此时向工程添加文件时,选中cc.c并单击add按钮,再单击Close按钮退出添加。然后单击项目管理窗口Source Group1前面的“+”号,可以看到刚才添加的文件,此时项目管理窗口如图所示。

四、Keil程序的调试

        Keil软件给我们提供了一个软件模拟仿真器(dScope),它可对应用程序进行软件模拟调试。

1.启动执行菜单

        为了运行dScope,在Project(项目)菜单中,选择Options for Target ‘Target1’  选项,或快捷按钮进入页面。

        在Debug选项卡中选中Use Simulator,要选中下面的Load Application at Startup复选框。如果不选中此复选框而运行了dScope,则要手动装载应用程序。Run to main()选项用于选择在dScope开始后是否从 C 源程序的 main()函数开始执行,选中此复选框。

        在编译源程序代码时,对所有出现的警告可以不去理会,但不可以有错误。然后就可以执行dScope了。dScope一词是 Debug和Scope的合成词。Keil执行菜单如图所示, 其中带有红色“d”字的按钮就是启动dScope的快捷按钮。      

        进入调试状态后,界面与编辑状态时的相比有明显变化,Debug菜单项中原来不能使用的命令现在可以使用了,工具栏会多出一个用于运行和调试的工具条,如图所示。

2.调试步骤与事项

        调试能检查程序中不容易发现的错误,比起编写程序的过程,通过调试排除错误更加重要。

        程序调试中必须明确的两个重要概念是:单步执行与全速运行。全速运行是指一行程序执行完以后紧接着执行下一行程序,这样程序执行速度很快,并可以看到该段程序执行的总体效果。单步执行是每次执行一行程序,执行完该行程序即停止,等待命令执行下一行程序。此时可以观察该行程序执行完以后,所得到的结果是否与写该行程序所要得到的结果相同,借此可以找到程序中的问题所在。在程序调试中,这两种运行方式都要用到。

        在进入Keil的调试环境以后,如果发现程序有错,可以直接对源程序进行修改,但是要使修改后的代码起作用,必须先退出调试环境,重新进行编译,链接后再次进入调试。

        如果只是测试某些程序行,或仅需要对源程序进行临时修改,那么以上过程未免有些麻烦,而可以采用 Keil软件提供的在线汇编的方法。将光标定位于需要修改的程序行上,选择 Debug 中的InlineAssembly菜单项。在 Enter New Instruction文本框内直接输入需要修改的程序语句,输入完以后按 Enter键,光标将自动指向下一条语句,可以继续修改。如果不再需要修改,可以单击右上角的“关闭”按钮来关闭窗口。

3.调试窗口介绍

        在进入调试模式后,工程窗口的寄存器页面,会显示出当前模式状态下单片机寄存器的值。

        进入调试状态后,输出窗口会自动切换到命令窗口。

1.存储器窗口

        存储器窗口可以显示系统中各种内存的值,通过在Address文本框内输入“字母:数字”组合即可显示相应的内存值,其中字母可以是CDIX,分别代表代码存储空间、直接寻址的片内存储空间、间接寻址的片内存储空间和扩展的外部RAM空间,数字代表想要查看的地址。

2.观察窗口

        寄存器窗口仅可以观察到工作寄存器和有限的寄存器,如ABDPTR等的值,如果需要观察其他寄存器的值,或者在C语言编程时直接观察变量,就要借助观察窗口了。如果想要观察程序中的某个临时变量i在单步执行时的变化情况,就可以在观察窗口中双击添加变量名,然后输入变量名i,这样在程序运行时就会看到变量i的即时值。一般需要在单步执行时观察变量的变化,如果要在全速运行时观察变量的变化,可以在 View 菜单中选择 Periodic Window Updata选项,然后即可在全速运行状态下动态地观察有关变量值的变化。选中该项,会使程序模拟执行的速度变慢。

3.反汇编窗口

在调试状态下点击快捷按钮,或选择View菜单中的Disassembly Window选项可以打开反汇编窗口

        该窗口可以显示反汇编后的代码以及源程序与相应反汇编代码的混合代码,在该窗口中还可以进行在线汇编、跟踪已执行的代码,以及按汇编代码的方式单步执行。打开反汇编窗口,右击鼠标出现快捷菜单,其中,Mixed Mode是以混合方式显示的,Assmbly Mode是以反汇编码方式显示的。

五、点亮一个发光二极管

        我们采用的单片机学习板发光二极管(LED)的硬件接线如图所示。图中可见LED正端经过上拉电阻接高电平,另一端接单片机的P2.0口,当P2.0口输出低电平时,LED将被点亮。这是一个LED的硬件接法,学习板上共有8LED,其它7个的接法同此LED,不同的是它们分别接到了单片机的P2.1P2.7口。

【例:编程,点亮P2.0口的发光二极管

#include<reg51.h>		//51系列单片机头文件
sbit led=P2^0;			//声明程序中用到的单片机P2.0口
void main()			//主函数
{
    led=0;				//点亮P2.0口的LED
}

        输入程序后,先编译工程,以检查程序代码是否有错误。编辑过程为:先保存文件,再单击快捷工具栏中的编译图标,或Project菜单中的选项 Build target和 Rebuild all target files之一。编译后的结果如图所示,可以看到,主要是下面的信息 输出窗口有编译过程和结果输出。

以下逐步分析源程序的含义:

1#include<reg51.h>

        在程序的最开始首先引用头文件reg51.h,这就相当把这个头文件的全部内容放到引用的位置,省去了将头文件内容重复编写的工作量。

        该头文件定义了单片机内部所有的特殊功能寄存器,比如其中含有sfr TL0=0x8A这个语句,表示把单片机内部地址0x8A的寄存器起名为TL0,再对地址0x8A的寄存器操作,直接操作TL0即可。该文件对于位的定义,比如文件中的sbit RXD=P3^0,表示将P3口的最低位命名为RXD,以后要用到该位时,直接对RXD操作即可。

        该语句的后面还有以“//”开头的部分,斜扛后面的是注释语句。        

2. sbit led=P2^0;

        指令的功能是将P2口的最低位定义为led发光二极管(LED)接到单片机的P2口,要控制LED的亮灭就要控制P2口该位输出的电平。用到单片机硬件接口的某个位之前,C51一般先要声明这个位。

3void main( )

        表示一个主函数的开始。单片机的程序总是从一个main函数开始执行。其中main前面的void表示不返回值,main后面跟着一个空的括号,表示主函数不带参数。在语句的后面一定是两个花括号,主函数的所有代码和指令都写在这两个花括号之中,并且每条语句后面都加上分号。

4led=0;

        它是主函数中唯一的一条指令,功能是使声明中定义的led输出为0led在前面的指令中声明它为P2口的最低位,所以该指令的功能是使P2口最低位输出为0,即输出低电平。

        如果以上程序编译通过,下一步就可以硬件调试了。硬件调试首先要将程序生成可以下载到单片机实验板的代码,下载到实验板上通过现象再查看程序执行的效果。硬件调试的过程如下:选择Project菜单中的Options for Target ‘Target1’项,弹出界面

        在界面中单击Output,然后在Create HEX File项前面的方框中勾选,这时程序再编译时就会自动产生HEX文件,即可以直接下载到单片机中的程序文件。如果界面中同时勾选了 Browse Information项,在大程序中某处调用函数的地方右击可以选择直接打开被调用的函数,这就为调试大程序提供了方便。

        选择生成 HEX文件后,单击图中的 OK 按钮退出,此时如果再编译程序时,在信息输出窗口中会增加一行creating hex file from ‘gongcheng1’,此时生成的 HEX文件名和 工程名同名。然后将 HEX文件下载到实验板上。

        上例的方法是只操作了单片机中的一个位,叫做位操作法。如果要同时让多发光二极管点亮,位操作就比较麻烦,此时可以按字节操作。

【例】 编程,同时点亮多个数码管

#include<reg51.h>
void main( )
{
    P2=0x55;		//P2口二极管间隔点亮
}

        这个程序中没有声明语句,直接把十六进制数0x55送给了P2口输出,0x55展开成二进制数就是0101 0101B,对应状态为1的位二极管灭,状态为0的位二极管点亮,所以指令P2=0x55的功能就是让接在P2口的LED间隔点亮。

1.原地踏步指令的应用

        以上程序中,主函数只有一条指令,这条指令执行完,程序再执行什么工作状态不定,这不是我们希望的。解决办法是,在点亮二极管的指令后插入一条能让程序停在这里不动的指令,即原地踏步,它可以在C51中用指令while(1)实现。while( )是编程中常用的指令,它的格式如下:

while(表达式)
{内部语句,可以为空}     
   

        指令在执行时,先要判断表达式的值,如果表达式不为零,执行内部语句;如果表达式为零,跳过while语句,执行while后面的语句。

        如果我们想让程序在某个位置停住不动时,只需让while()语句判断表达式的值不为零,程序就会一直停在while()语句中,反复循环执行,不管该语句中是否有内部语句。

【例:编程,实现带原地踏步指令的点亮发光二极管程序。

#include<reg51.h>
void main( )
{
    P2=0x55;
    while(1);		//原地踏步指令
}
2. 延时程序设计

        一般要把延时写成一个子程序,在主程序里需要延时的地方就调用。延时常用while()for()函数实现。for语句的格式如下:

for(表达式1;表达式2;表达式3)
 {内部语句,可以为空}

        该语句执行过程为:

        ①求解表达式1;        
        ②求解表达式2,它的值若不为零(为真),执行内部语句,再执行表达式3
;值若为零(为假),跳出该for语句,执行它后面的语句。
        ③求解表达式3;
        ④重复执行第2步,直到表达式
2的值为假,跳出。

unsigned char i ;
for (i=2;i>0;i--);

        第一句定义了一个无符号字符型变量i。第二句的表达式1,定义i的初值为2;表达式2的意义是,当i >0成立时,执行内部语句,此时内部语句为空,直接去执行表达式3;表达式3的意义是,对i自减1,第一次执行时i=1,返回执行表达式2,此时表达式2仍成立;再执行表达式3,i的值再减一,得到i=0;返回执行表达式2时,表达式2不成立,跳出for语句。所以,执行for语句时,表达式1执行一次,其他都是在表达式2和表达 式3之间反复执行,直到表达式2不成立时,跳出for语句。也就是表达式1一般控制循环次数,表达式2控制跳出循环的条件。因为在单片机里每条指令执行都需要一定的时间,所以这种有限次的循环就可以实现延时的功能。

        上述的for语句,表达式构成的循环只执行了2次,延时时间有限;要想延长延时时间,需要给i赋一个大的初值,让i =200。

        循环被执行200次,延时时间变长了。但要注意,这里定义的i是无符号字符数,它的取值范围为0~255,所以给i赋值不能超过255;要想给它赋一个更大的值,必须先修改它的定义,如把它定义为整型数。要想实现更长时间的延时,还可以通过循环嵌套,即多重循环。

unsigned char i ;
for (i=200;i>0;i--)
    for (j=0;j<100;j++) ;

        第一个for语句没有分号,表示第二个for语句是它的内部语句;当i从初值200开始每减一个1时,第二个for语句就被执行100次;第二个for语句中j是从初值0开始,每执行一次循环,j的值就加1,直到j等于99;而第一个for语句要循环执行200次。所以,这段程序执行完成时,共执行了200×100次for语句,延时时间大大增加了。

        用C语言编写的延时程序,精确的延时时间不容易计算出来,只能计算出大概的延时时间。如果要实现精度较高的延时,可以采用单片机内部的定时器。

【例】编程,用延时程序实现发光二极管间隔1秒亮灭闪动的程序。

#include<reg51.h>
sbit led1=P2^0;
unsigned int a,b;
void main()
{
	while(1)
	{
		led1=0;		//LED点亮
		for(a=1000;a>0;a--)		 //延时程序
		for(b=110;b>0;b--);
		led1=1;
		for(a=1000;a>0;a--)
		for(b=110;b>0;b--);
	}
}

        以上程序中,用两个for语句循环嵌套实现延时。主程序中先用了一个while(1)实现大循环,循环体内部先点亮发光二极管,延时后再熄灭,再经过相同的延时,返回点亮发光二极管,这是一个不断重复的过程。两个for语句循环嵌套形成的延时时间到底有多长,可以在KeilμVision4软件调试环境下得到。

        在Debug菜单中选择Start/Stop Debug Session,或快捷工具栏上的按钮进入调试界面。

        界面中可见Registers窗口中有一项是sec,它后面的数据代表程序从第一条指令,到执行完箭头所在指令的前一个指令所花费的时间,单位是秒。利用sec的值,我们就可以知道延时程序的延时时间,可按照下面的方法。

        要从调试软件上得到程序运行时间,先要让软件的时钟设置和实际硬件相符。        

        选择Project菜单中的Options for Target ‘Target1’,弹出如图窗口。在其中选择Target标签,再修改Xtal(MHZ)后面方框中的数据为11.0592,最后单击OK按钮完成设置。

        设置断点。在指令编号10和12的位置前面的灰色区域,单击鼠标就会出现一个红色圆点,即为断点。如图所示。

        第一个断点让程序在执行完LED点亮后,停在延时程序的开始位置,这时可以记下此时sec的值;第二个断点让程序在执行完延时程序后停下来,再记下此时的sec值;两个sec值相减即为延时时间。

六、流水灯的控制

        单片机的流水灯控制,就是使接在单片机某个并口上的发光二极管,按一定规则循环点亮,形成流水追逐效果。

1.延时子程序的应用

【例】编程,让8个LED某一时刻只有1个点亮,从最右边(最低位)开始,每隔1s循环左移一位。

#include<reg51.h>
void delay( )
{
  unsigned int a,b;
  for(a=1000;a>0;a--)
  for(b=110;b>0;b--);
}
void main()
{
 while(1)
 {
  P2=0xfe;
  delay();
  P2=0xfd;
  delay();
  P2=0xfb;
  delay();
  P2=0xf7;
  delay();
  P2=0xef;
  delay();
  P2=0xdf;
  delay();
  P2=0xbf;
  delay();
  P2=0x7f;
  delay();
 }
}

        程序中反复给P2口赋值,比如“P2=0xfe”,把这个值展开成二进制数就是1111 1110B,这个状态是只有P2口最低位的灯亮;调用一秒延时后再让P2赋值为0xfd,即只有P2的倒数第二个灯亮,循环直到最高位的灯亮;最后while(1)指令再控制程序从头开始执行,形成一个发光二极管循环左移点亮的效果。

        在这例程序中,延时程序要反复的用到,我们可以把它写成一个不带参数的子函数,其中void delay()就是我们定义的延时子函数。

        子函数即可以写在主函数之前,也可以写在之后,本例是写在之前的情况。如果写在之后,必须要在主函数之前声明,对本例的声明格式为:void delay( );

        这是声明无参数函数的写法。声明子函数的目的是让编译器知道有一个子函数存在,方便编译器给它分配存储空间。如果要声明有参数函数,需要在括号里写上参数类型,但不需写参数名,各项之间用逗号分开,最后一定要加分号。如:void delay(int,int);

        如果控制流水灯点亮时间不等,按上述方法就至少要编写两个延时子程序了,使用起来不方便。实际上,这种情况可以用带参数的子函数解决,子函数可以这样写:

void delay(unsigned int x)
{
    uint i,j;
    for(i=x;i>0;i--)   //延时约为xms
    for(j=110;j>0;j--)
}

【例】P2口一个灯循环右移点亮,点亮的时间长短按照亮1s,再亮2s,再亮1s的状态循环。

#include<reg51.h>
void delay(unsigned int x)
{
  unsigned int a,b;
  for(a=x;a>0;a--)
  for(b=110;b>0;b--);
}
void main()
{
 while(1)
 {
  P2=0xfe;
  delay(1000);
  P2=0xfd;
  delay(2000);
  P2=0xfb;
  delay(1000);
  P2=0xf7;
  delay(2000);
  P2=0xef;
  delay(1000);
  P2=0xdf;
  delay(2000);
  P2=0xbf;
  delay(1000);
  P2=0x7f;
  delay(2000);
 }
}

        这里用到了一个带参数的延时子函数delay(),它实现的延时时间是x毫秒。在主程序里调用它时,x被具体数据代替。

2.移位指令的应用

【例】用右移运算指令实现流水灯从高位到低位依次点亮,并循环。

#include<reg51.h>     
unsigned int a;
void delay()
{
 unsigned int i,j;
 for(i=1000;i>0;i--)
  for(j=110;j>0;j--);
}
void main()
{
 while(1)	//无限次循环
 {
    P2=0xff;		//P2口的所有灯熄灭
    delay();
    for(a=8;a>0;a--)		//循环八次
    {
      P2=P2>>1;	 //右移指令,将P2口的值右移一位,高位补零
      delay();
   }
 }
}

        该程序的功能是:先让 P2口接的所有灯都灭,延时1s后让最高位的灯亮,再延时1s 让最高位和次高位的灯亮。这样每经过1s,亮的灯增加一个,直到8s后所有灯被点亮,再返回灯都灭的状态,重复上述过程。

        这个流水灯控制的例子主要用到了右移指令“P2=P2>>1”,它的功能是P2口数据右移一位,移出的低位丢弃,高位补0。左移和右移指令功能如下:

        ① 左移。C51 中操作符为“ <<” ,每执行一次左移指令,被操作的数将最高位移入单片机 PSW 寄存器的 CY 位, CY 位中原来的数丢弃,最低位补 0, 其他位依次向左移动一位,如图 所示。

        ②右移。C51中操作符为“>>”,每执行一次右移指令,被操作的数将最低位移入单片机PSW寄存器的CY位,CY位中原来的数丢弃,最高位补0,其他位依次向右移动一位,如图所示。

        PSW (Program Status Word)全称为程序状态字标志寄存器,是一个8位寄存器,位于单片机片内的特殊功能寄存器区,字节地址DOH,用来存放运算结果的一些特征,如有无进位、借位等,使用汇编编程时PSW寄存器很有用,但在利用C语言编程时,编译器会自动控制该寄存器,很少人为操作它,只需做简单了解即可。其每位的具体含义如下图所示。

3.循环移位指令的应用

        C51库中自带的循环移位指令格式为:

        unsigned char_crol_(unsigned char c, unsigned char b)

        其中_crol_是函数名,函数名前面的“unsigned char”表示这个函数是有返回值的。

        这个函数包含在intrins.h头文件中,如果在程序中用到这个函数时,必须在程序的开头包含这个头文件,因为头文件中有该函数的具体说明,这样在编写的程序中才可以用到这个函数。

        循环左移和右移指令的功能如下:

        ① 循环左移。最高位移入最低位,其他位依次向左移一位。

        ②循环右移。最低位移入最高位,其他位依次向右移一位。

【例】用_crol_函数实现让一个发光二极管,从最右边开始向左循环移位点亮。

#include<reg51.h>	
#include<intrins.h>			//包含函数_crol_()声明的头文件
void delay(unsigned int x)			//带参数的延时子程序
	{
	unsigned int a,b;
	for(a=x;a>0;a--)
	 for(b=110;b>0;b--);
	}
void main()
{
	P2=0xfe;			//P2口只赋一次初值,让最低位的灯亮
	delay(500);
	while(1)
	{
	P2=_crol_(P2,1);		//P2口的二进制位循环左移一位后再赋给P2
	delay(500);
	}	
}

        语句“P2=_crol_(P2,1);”执行时,先执行等号右边的表达式,即将 P2口的二进制值循环左移一位,再将结果赋给等号左边的P2。程序中P2赋的初值为0xfe,二进制值 为11111110B,执行循环左移一位后,它的值变为11111101B,再赋给 P2,等待0.5s后,再移位和赋值。这样程序实现的功能为:先是 P2口最低位的灯亮,然后每隔0.5s点亮的灯向左移一位,直到最高位的灯被点亮,再隔0.5s,最低位的灯再亮,循环上述过程。

(1)如何建立一个 Keil工程文件并进行 C程序的编译?

答:建立一个新的工程,先要单击 Project 菜单中的 NewμVision Project 选项,此时会自动弹出一个创建新工程对话框,首先要在最上面的框里输入保存的路径, 因为一个工程里通常含有很多文件,为了管理方便,应该将一个工程单独放在一 个文件夹下。新建的工程放在 gc1 文件夹下,该文件夹原来没有任何文件。再在下面的文件名处输入要保存的新工程名 xj1,然后按下保存按钮,就建立了一个新工程。 此时会自动弹出选择单片机型号对话框。可以根据当前使用的单片机选择型号。 51 单片机内核具有通用性,无论你用的是哪款 51 单片机,只要选择 51 系列中的即可。右边描述栏里就会出现该型号单片机的基本说明,最后单击 OK 按钮完成选 择。 单击 File 菜单中的 New 菜单项,或单击对应的快捷图标,会自动弹出新建文件窗口。此时可以在编辑窗口中输入用户程序,还要使新建的文件和新建的工程之间 建立联系。当程序输入完成后,单击保存按钮。在下面的文件名框中输入想保存的文件名,注意扩展名一定要输入正确。这里是用 C 语言编写的程序,文件名的后缀一定是.c。最后单击保存按钮。 回到编辑界面,单击项目管理窗口 Target1 前面的“+”号,在下面出现的 Source Group1 选项上单击右键,在弹出菜单中选择 Add Existing Files to Group ‘Source Group1’。 刚才新建的文件名是 xj1.c,此时向工程添加文件时,选中 xj1.c 并单击 add 按钮, 再单击 Close 按钮退出添加。然后单击项目管理窗口 Source Group1 前面的“+” 号,可以看到刚才添加的文件。 此时可以看到 Source Group1 文件夹中多了一个文件 xj1.c。此时,源文件 xj1.c 就属于此工程了。建立好了一个工程后,并且源文件输入完毕,按下 F7 或工具栏里的快捷键就可以对文件编译。工程中含有的源文件在编译和其它的操作过程中, 产生的所有文件就都在这个工程目录下了。

(2)在程序编译通过后,如何以单步和全速运行方式调试程序?

答:程序调试中必须明确的两个重要概念是:单步执行与全速运行。全速运行是 指一行程序执行完以后紧接着执行下一行程序,中间不停止。这样程序执行速度很快,并可以看到该段程序执行的总体效果,即最终结果是正确还是错误。但如果程序有错,则难以确定错误出现在哪些程序行。单步执行是每次执行一行程序,执行完该行程序即停止,等待命令执行下一行程序。此时可以观察该行程序执行完以后,所得到的结果是否与写该行程序所要得到的结果相同,借此可以找到程序中的问题所在。在程序调试中,这两种运行方式都要用到。

(3)如何采用 Proteus 软件进行仿真调试

答:用鼠标左键单击原理图中的单片机,弹出元器件编辑窗口。在该窗口的 Program File 栏单击文件夹浏览按钮,找到在 Keil 软件中编辑生成的 Hex 文件,再 单击 OK 按钮完成填加文件。同时注意,该窗口中的 Clock Frequency 文本框中频率 要选择 12MHz,再单击 OK 退出。此时单击仿真工具栏的全速运行按钮即可进行虚 拟仿真。例如,导入单片机的程序是使三个发光二极管轮流点亮,此时就可以看到三个发光二极管和单片机三个驱动口有小点变色,表示二极管在交替发光。

( 4 )简述for循环的用法

for 语句的格式如下。 for(表达式 1;表达式 2;表达式 3) {内部语句,可以为空}
该语句执行过程为: 求解表达式 1; 求解表达式 2,它的值若不为零(为真),执行内部语句,再执行表达式 3;值若为零(为假),跳出该 for 语句,执行它后面的语句。 求解表达式 3; 重复执行第 2 步,直到表达式 2 的值为假,跳出。
for 语句的具体用法举例如下: unsigned char i; for(i=2;i>0;i--); 以上程序段,第一句定义了一个无符号字符型变量 i。第二句的表达式 1,定义 i 的初值为 2;表达式 2 当 i>0 成立时,执行内部语句,此时内部语句为空,直接去 执行表达式 3;表达式 3 对 i 自减一,第一次执行时 i=1,返回执行表达式 2,此时 表达式 2 仍成立;再执行表达式 3,i 值的再减一,得到 i=0;返回执行表达式 2 时,表达式 2 不成立,跳出 for 语句。所以,for 语句执行时,表达式 1 执行一 次,其他都是在表达式 2 和 3 之间反复执行,直到表达式 2 不成立时,跳出 for 语 句。也就是表达式 1 一般控制循环次数,表达式 2 控制跳出循环的条件。因为在 单片机里每条指令执行都需要一定的时间,所以这种有限次的循环就可以实现延时的功能

( 5 )用for语句编写一个延时1min的子程序

#include<reg51.h>
unsigned int a,b;
void main()
{
  for(a=60000;a>0;a--)
  for(b=110;b>0;b--);
  while(1);
}

( 6 )简述移位指令“ ”和“ ”的用法和作用

答:(1)左移。C51 中操作符为“<<”,每执行一次左移指令,被操作的数将最高 位移入单片机 PSW 寄存器的 CY 位,CY 位中原来的数丢弃,最低位补 0,其他位依 次向左移动一位。(2)右移。C51 中操作符为“>>”,每执行一次右移指令,被操作的数将最低位移 入单片机 PSW 寄存器的 CY 位,CY 位中原来的数丢弃,最高位补 0,其他位依次 向右移动一位。右移指令“P2=P2>>1”,它的功能是:P2 口数据右移一位,移出的低位丢弃,高位补 0。如果实现左移一位时,指令可改成“P2=P2<<1”。

( 7 )简述循环移位指令“_crol_”和“_cror_”的用法和作用

答:(1)循环左移。最高位移入最低位,其他位依次向左移一位。 (2)循环右移。最低位移入最高位,其他位依次向右移一位。 C51 库中自带的循环移位指令格式为: unsigned char_crol_(unsigned char c, unsigned char b) 这条指令的功能是:将字符 c 循环左移 b 位。循环左移的作用是,当循环左移执行移动一位时,依次将字符 c 的各位向高位移动一位,并且移出的最高位移到最低位中。实现循环右移,只需要将函数名换成_cror_即可。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值