光电工程师社区

标题: 单片机技术!!! [打印本页]

作者: 老马识途    时间: 2003-3-15 23:15
标题: 单片机技术!!!
做单片机技术的和想做单片机技术的可以来讨论这方面的相关技术啊!
欢迎大家参加啊!!!
单片机开发的想关产品也可提供啊!!!
作者: hustph    时间: 2003-3-17 20:35
标题: 单片机技术!!!
好啊,特别是单片机用在激光行业的

呵呵


作者: CTVIP    时间: 2003-3-19 17:41
标题: 单片机技术!!!
请问斑竹在激光设备的控制中用单片机做了那些事,有成功的案例吗?
作者: 老马识途    时间: 2003-3-19 18:18
标题: 单片机技术!!!
呵呵!不多,做过几个啊!
有一套数控系统,有光功率、能量检测,还有一种激光脉冲电源啊!
都在试用啊。可单片机系统的应用就做的多了啊!
也许你还能指导!
作者: hustph    时间: 2003-3-19 18:21
标题: 单片机技术!!!
呵呵,楚天的兄弟正在做什么呢?

一起研究阿

呵呵
作者: ldpsbs    时间: 2003-4-3 01:40
标题: 单片机技术!!!
有朋友干光束控制的吗?
作者: dnke    时间: 2003-4-4 00:20
标题: 单片机技术!!!
正准备干
作者: suncon    时间: 2003-4-6 22:53
标题: 单片机技术!!!
单片机课程体系改革总体规划

第一部份:入门

一、 单片机的基础知识

1、 微型计算机与单片机

1) 微型计算机的构成

2) 单片机的由来

3) 人与计算机的关系

2、 数制

1)十、二、十六进制概念

2)以上数制互换

3)常用单位(K、M)

3、几个基本概念

1) 位的含义
2) 字节的含义

3) 字的含义
4) 总线概念初步
二、 任务一(单灯闪烁)
1、 单片机引脚功能

1) 电源引脚和EA引脚。

2) RST引脚及RESET电路

3) 晶振引脚及晶振电路

2、 指令初步知识

1)SETB 、CLR、LCALL、LJMP 指令

2)标号的应用

3)指令的助记符形式与目标代码形式

3、 编程器的使用

4、 存储器组织

三、 任务二(键控灯亮)
1、 指令的继续学习

2、 输入、输出的含义

3、 并行口的结构

1) P1、P2、P3口的结构

2) P0口的结构

四、 任务三(彩灯)
1、 指令的继续学习

2、 片内RAM组织

3、 工作寄存器组织
第二部份:巩固提高
一、 指令的全面认识
1、 寻址方式

2、 所有指令

3、 编程

1) 实例讲解

2) 软件仿真器

3) 软件仿真器调试
二、 任务四(定时器)
1、 定时器结构

2、 定时器工作方式

3、 定时器编程
三、 任务五(中断)
1、 中断结构

2、 中断编程

1) 按键中断

2) 定时中断
四、 任务六(串口应用)
1、 串口结构

2、 串口编程

1) 同步扩展(74LS164)

2) 异步通讯
第三部份:提高
一、 任务七(外部ROM、RAM扩展)
二、 任务八(并行口扩展)
三、 综合应用(一)
1、 LED显示器编程

1)

2)定时器法

2、 键盘编程
四、 综合应用(二)
1、 时钟应用

2、
以上是初步的规划,当然还只是设想,是否合理尚需实践检验。
成功的若干关键:能否合理分解各部份知识点,能否将它们恰当地组合在一个任务中,能否不断保持学习的兴趣,能否找到大量的、确切、形象的比喻,能否编制出内容、难度恰当的习题……
难点应当在编程训练上,要将一个从未有任何编程经验的人训练成能熟练地编程,决非易事,当然这有点超过我们的范围了——程序概念和常用算法应当是在BASIC学习时解决的,但事实上很多人在学单片机时,早就忘光了BASIC的,所以任务很艰巨,说实话,这是我最没信心的部份。

单片机教学 第一课
教学内容:单片机概述
1、何谓单片机 一台能够工作的计算机要有这样几个部份构成:CPU(进行运算、控制)、RAM(数据存储)、ROM(程序存储)、输入/输出设备(例如:串行口、并行输出口等)。在个人计算机上这些部份被分成若干块芯片,安装一个称之为主板的印刷线路板上。而在单片机中,这些部份,全部被做到一块集成电路芯片中了,所以就称为单片(单芯片)机,而且有一些单片机中除了上述部份外,还集成了其它部份如A/D,D/A等。
天!PC中的CPU一块就要卖几千块钱,这么多东西做在一起,还不得买个天价!再说这块芯片也得非常大了。
不,价格并不高,从几元人民币到几十元人民币,体积也不大,一般用40脚封装,当然功能多一些单片机也有引脚比较多的,如68引脚,功能少的只有10多个或20多个引脚,有的甚至只8只引脚。
为什么会这样呢?
功能有强弱,打个比方,市场上面有的组合音响一套才卖几百块钱,可是有的一台功放机就要卖好几千。另外这种芯片的生产量很大,技术也很成熟,51系列的单片机已经做了十几年,所以价格就低了。
既然如此,单片机的功能肯定不强,干吗要学它呢?
话不能这样说,实际工作中并不是任何需要计算机的场合都要求计算机有很高的性能,一个控制电冰箱温度的计算机难道要用PIII?应用的关键是看是否够用,是否有很好的性能价格比。所以8051出来十多年,依然没有被淘汰,还在不断的发展中。
2、MCS51单片机和8051、8031、89C51等的关系
我们平常老是讲8051,又有什么8031,现在又有89C51,它们之间究竟是什么关系?
MCS51是指由美国INTEL公司(对了,就是大名鼎鼎的INTEL)生产的一系列单片机的总称,这一系列单片机包括了好些品种,如8031,8051,8751,8032,8052,8752等,其中8051是最早最典型的产品,该系列其它单片机都是在8051的基础上进行功能的增、减、改变而来的,所以人们习惯于用8051来称呼MCS51系列单片机,而8031是前些年在我国最流行的单片机,所以很多场合会看到8031的名称。INTEL公司将MCS51的核心技术授权给了很多其它公司,所以有很多公司在做以8051为核心的单片机,当然,功能或多或少有些改变,以满足不同的需求,其中89C51就是这几年在我国非常流行的单片机,它是由美国ATMEL公司开发生产的。以后我们将用89C51来完成一系列的实验。

单片机教学(2)
单片机的内部、外部结构(一)
一、单片机的外部结构
拿到一块芯片,想要使用它,首先必须要知道怎样连线,我们用的一块称之为89C51的芯片,下面我们就看一下如何给它连线。 1、 电源:这当然是必不可少的了。单片机使用的是5V电源,其中正极接40引脚,负极(地)接20引脚。 2、 振蒎电路:单片机是一种时序电路,必须提供脉冲信号才能正常工作,在单片机内部已集成了振荡器,使用晶体振荡器,接18、19脚。只要买来晶振,电容,连上就可以了,按图1接上即可。 3、 复位引脚:按图1中画法连好,至于复位是何含义及为何需要复要复位,在单片机功能中介绍。 4、 EA引脚:EA引脚接到正电源端。 至此,一个单片机就接好,通上电,单片机就开始工作了。
图1
二、 任务分析
我们的第一个任务是要用单片机点亮一只发光二极管LED,显然,这个LED必须要和单片机的某个引脚相连,否则单片机就没法控制它了,那么和哪个引脚相连呢?单片机上除了刚才用掉的5个引脚,还有35个,我们将这个LED和1脚相连。(见图1,其中R1是限流电阻)
按照这个图的接法,当1脚是高电平时,LED不亮,只有1脚是低电平时,LED才发亮。因此要1脚我们要能够控制,也就是说,我们要能够让1引脚按要求变为高或低电平。即然我们要控制1脚,就得给它起个名字,总不能就叫它一脚吧?叫它什么名字呢?设计51芯片的INTEL公司已经起好了,就叫它P1.0,这是规定,不可以由我们来更改。
名字有了,我们又怎样让它变’’高’’或变’’低’’呢?叫人做事,说一声就可以,这叫发布命令,要计算机做事,也得要向计算机发命令,计算机能听得懂的命令称之为计算机的指令。让一个引脚输出高电平的指令是SETB,让一个引脚输出低电平的指令是CLR。因此,我们要P1.0输出高电平,只要写SETB P1.0,要P1.0输出低电平,只要写 CLR P1.0就可以了。
现在我们已经有办法让计算机去将P10输出高或低电平了,但是我们怎样才能计算机执行这条指令呢?总不能也对计算机也说一声了事吧。要解决这个问题,还得有几步要走。第一,计算机看不懂SETB CLR之类的指令,我们得把指令翻译成计算机能懂的方式,再让计算机去读。计算机能懂什么呢?它只懂一样东西——数字。因此我们得把SETB P1.0变为(D2H,90H ),把CLR P1.0变为 (C2H,90H ),至于为什么是这两个数字,这也是由51芯片的设计者--INTEL规定的,我们不去研究。第二步,在得到这两个数字后,怎样让这两个数字进入单片机的内部呢?这要借助于一个硬件工具编程器。
我们将编程器与电脑连好,运行编程器的软件,然后在编缉区内写入(D2H,90H)见图2,写入……好,拿下片子,把片子插入做好的电路板,接通电源……什么?灯不亮?这就对了,因为我们写进去的指令就是让 图2
P10输出高电平,灯当然不亮,要是亮就错了。现在我们再拨下这块芯片,重新放回到编程器上,将编缉区的内容改为(C2H,90H),也就是CLR P1.0,写片,拿下片子,把片子插进电路板,接电,好,灯亮了。因为我们写入的()就是让P10输出低电平的指令。这样我们看到,硬件电路的连线没有做任何改变,只要改变写入单片机中的内容,就可以改变电路的输出效果。
三、单片机内部结构分析
我们来思考一个问题,当我们在编程器中把一条指令写进单片要内部,然后取下单片机,单片机就可以执行这条指令,那么这条指令一定保存在单片机的某个地方,并且这个地方在单片机掉电后依然可以保持这条指令不会丢失,这是个什么地方呢?这个地方就是单片机内部的只读存储器即ROM(READ ONLY MEMORY)。为什么称它为只读存储器呢?刚才我们不是明明把两个数字写进去了吗?原来在89C51中的ROM是一种电可擦除的ROM,称为FLASH ROM,刚才我们是用的编程器,在特殊的条件下由外部设备对ROM进行写的操作,在单片机正常工作条件下,只能从那面读,不能把数据写进去,所以我们还是把它称为ROM。
半导体存储器
1.几个基本概念
1.数的本质和物理现象。
我们知道,计算机可以进行数学运算,这可令我们非常的难以理解,计算机吗,我们虽不了解它的组成,但它总只是一些电子元器件,怎么可以进行数学运算呢?我们做数学题如37+45是这样做的,先在纸上写37,然后在下面写45,然后大脑运算,最后写出结果,运算的原材料:37、45和结果:82都是写在纸上的,计算机中又是放在什么地方呢?为了解决这个问题,先让我们做一个实验:
这里有一盏灯,我们知道灯要么亮,要么不亮,就有两种状态,我们可以用’0’和’1’来代替这两种状态,规定亮为’1’,不亮为’0’。现在放上两盏灯,一共有几种状态呢?我们列表来看一下:
状态




表达 0 0 0 1 1 0 1 1
请大家自已写上3盏灯的情况000 001 010 011 100 101 110 111
我们来看,这个000,001,101 不就是我们学过的的二进制数吗?本来,灯的亮和灭只是一种物理现象,可当我们把它们按一按的顺序排更好后,灯的亮和灭就代表了数字了。让我们再抽象一步,灯为什么会亮呢?看电路1,是因为输出电路输出高电平,给灯通了电。因此,灯亮和灭就可以用电路的输出是高电平还是低电平来替代了。这样,数字就和电平的高、低联系上了。(请想一下,我们还看到过什么样的类似的例子呢?(海军之)灯语、旗语,电报,甚至红、绿灯)
2.位的含义:
通过上面的实验我们已经知道:一盏灯亮或者说一根线的电平的高低,可以代表两种状态:0和1。实际上这就是一个二进制位,因此我们就把一根线称之为一“位”,用BIT表示。
3.字节的含义:
一根线可以表于0和1,两根线可以表达00,01,10,11四种状态,也就是可以表于0到3,而三根可以表达0-7,计算机中通常用8根线放在一起,同时计数,就可以表过到0-255一共256种状态。这8根线或者8位就称之为一个字节(BYTE)。不要问我为什么是8根而不是其它数,因为我也不知道。(计算机世界是一个人造的世界,不是自然界,很多事情你无法问为什么,只能说:它是一种规定,大家在以后的学习过程中也要注意这个问题)
1.存储器的工作原理:
1、存储器构造
存储器就是用来存放数据的地方。它是利用电平的高低来存放数据的,也就是说,它存放的实际上是电平的高、低,而不是我们所习惯认为的1234这样的数字,这样,我们的一个谜团就解开了,计算机也没什么神秘的吗。
图2 图3

让我们看图2。这是一个存储器的示意图:一个存储器就象一个个的小抽屉,一个小抽屉里有八个小格子,每个小格子就是用来存放“电荷”的,电荷通过与它相连的电线传进来或释放掉,至于电荷在小格子里是怎样存的,就不用我们操心了,你可以把电线想象成水管,小格子里的电荷就象是水,那就好理解了。存储器中的每个小抽屉就是一个放数据的地方,我们称之为一个“单元”。
有了这么一个构造,我们就可以开始存放数据了,想要放进一个数据12,也就是00001100,我们只要把第二号和第三号小格子里存满电荷,而其它小格子里的电荷给放掉就行了(看图3)。可是问题出来了,看图2,一个存储器有好多单元,线是并联的,在放入电荷的时候,会将电荷放入所有的单元中,而释放电荷的时候,会把每个单元中的电荷都放掉,这样的话,不管存储器有多少个单元,都只能放同一个数,这当然不是我们所希望的,因此,要在结构上稍作变化,看图2,在每个单元上有个控制线,我想要把数据放进哪个单元,就给一个信号这个单元的控制线,这个控制线就把开关打开,这样电荷就可以自由流动了,而其它单元控制线上没有信号,所以开关不打开,不会受到影响,这样,只要控制不同单元的控制线,就可以向各单元写入不同的数据了,同样,如果要某个单元中取数据,也只要打开相应的控制开关就行了。
2、存储器译码
那么,我们怎样来控制各个单元的控制线呢?这个还不简单,把每个单元元的控制线都引到集成电路的外面不就行了吗?事情可没那么简单,一片27512存储器中有65536个单元,把每根线都引出来,这个集成电路就得有6万多个脚?不行,怎么办?要想法减少线的数量。
我们有一种方法称这为译码,简单介绍一下:一根线可以代表2种状态,2根线可以代表4种状态,3根线可以代表几种,256种状态又需要几根线代表?8种,8根线,所以65536种状态我们只需要16根线就可以代表了。
图4
3、存储器的选片及总线的概念
至此,译码的问题解决了,让我们再来关注另外一个问题。送入每个单元的八根线是用从什么地方来的呢?它就是从计算机上接过来的,一般地,这八根线除了接一个存储器之外,还要接其它的器件,如图4所示。这样问题就出来了,这八根线既然不是存储器和计算机之间专用的,如果总是将某个单元接在这八根线上,就不好了,比如这个存储器单元中的数值是0FFH另一个存储器的单元是00H,那么这根线到底是处于高电平,还是低电平?岂非要打架看谁历害了?所以我们要让它们分离。办法当然很简单,当外面的线接到集成电路的引脚进来后,不直接接到各单元去,中间再加一组开关(参考图4)就行了。平时我们让开关打开着,如果确实是要向这个存储器中写入数据,或要从存储器中读出数据,再让开关接通就行了。这组开关由三根引线选择:读控制端、写控制端和片选端。要将数据写入片中,先选中该片,然后发出写信号,开关就合上了,并将传过来的数据(电荷)写入片中。如果要读,先选中该片,然后发出读信号,开关合上,数据就被送出去了。注意图4,读和写信号同时还接入到另一个存储器,但是由于片选端不同,所以虽有读或写信号,但没有片选信号,所以另一个存储器不会“误会”而开门,造成冲突。那么会不同时选中两片芯片呢?只要是设计好的系统就不会,因为它是由计算控制的,而不是我们人来控制的,如果真的出现同时出现选中两片的情况,那就是电路出了故障了,这不在我们的讨论之列。
从上面的介绍中我们已经看到,用来传递数据的八根线并不是专用的,而是很多器件大家共用的,所以我们称之为数据总线,总线英文名为BUS,总即公交车道,谁者可以走。而十六根地址线也是连在一起的,称之为地址总线。
2.半导体存储器的分类
按功能可以分为只读和随机存取存储器两大类。所谓只读,从字面上理解就是只可以从里面读,不能写进去,它类似于我们的书本,发到我们手回之后,我们只能读里面的内容,不可以随意更改书本上的内容。只读存储器的英文缩写为ROM(READ ONLY MEMORY)
所谓随机存取存储器,即随时可以改写,也可以读出里面的数据,它类似于我们的黑板,我可以随时写东西上去,也可以用黑板擦擦掉重写。随机存储器的英文缩写为RAM(READ RANDOM MEMORY)这两种存储器的英文缩写一定要记牢。
注意:所谓的只读和随机存取都是指在正常工作情况下而言,也就是在使用这块存储器的时候,而不是指制造这块芯片的时候。否则,只读存储器中的数据是怎么来的呢?其实这个道理也很好理解,书本拿到我们手里是不能改了,可以当它还是原材料——白纸的时候,当然可以由印刷厂印上去了。
顺便解释一下其它几个常见的概念。
PROM,称之为可编程存储器。这就象我们的练习本,买来的时候是空白的,可以写东西上去,可一旦写上去,就擦不掉了,所以它只能用写一次,要是写错了,就报销了。
EPROM,称之为紫外线擦除的可编程只读存储器。它里面的内容写上去之后,如果觉得不满意,可以用一种特殊的方法去掉后重写,这就是用紫外线照射,紫外线就象“消字灵”,可以把字去掉,然后再重写。当然消的次数多了,也就不灵光了,所以这种芯片可以擦除的次数也是有限的——几百次吧。
FLASH,称之为闪速存储器,它和EPROM类似,写上去的东西也可以擦掉重写,但它要方便一些,不需要光照了,只要用电学方法就可以擦除,所以就方便许多,而且寿面也很长(几万到几十万次不等)。
再次强调,这里的所有的写都不是指在正常工作条件下。不管是PROM、EPROM还是FLASH ROM,它们的写都要有特殊的条件,一般我们用一种称之为“编程器”的设备来做这项工作,一旦把它装到它的工作位置,就不能随便改写了。

单片机教学(3)
单片机的内外部结构分析(二)
一、 程序的完善
  上一次我们的程序实在是没什么用,要灯亮还要重写一下片子,下面我们要让灯不断地闪烁,这就有一定的实用价值了,比如可以把它当成汽车上的一个信号灯用了。怎样才能让灯不断地闪烁呢?实际上就是要灯亮一段时间,再灭一段时间,也就是说要P10不断地输出高和低电平。怎样实现这个要求呢?请考虑用下面的指令是否可行:
SETB P10
CLR P10
……
这是不行的,有两个问题,第一,计算机执行指令的时间很快,执行完SETB P10后,灯是灭了,但在极短时间(微秒级)后,计算机又执行了CLR P10指令,灯又亮了,所以根本分辨不出灯曾灭过。第二,在执行完CLR P10后,不会再去执行SETB P10指令,所以以后再也没有机会让灭了。
  为了解决这两个问题,我们可以做如下设想,第一,在执行完SETB P10后,延时一段时间(几秒或零点几秒)再执行第二条指令,就可以分辨出灯曾灭过了。第二在执行完第二条指令后,让计算机再去执行第一条指令,不断地在原地兜圈,我们称之为循环,这样就可以完成任务了。
以下先给出程序(后面括号中的数字是为了便于讲解而写的,实际不用输入):
;主程序:
LOOP: SETB P10     ;(1)
    LCALL DELAY   ;(2)
    CLR P10     ;(3)
    LCALL DELAY   ;(4)
    AJMP LOOP    ;(5)
;以下子程序
DELAY: MOV R7,#250  ;(6)
D1: MOV R6,#250    ;(7)
D2: DJNZ R6,D2    ;(8)
  DJNZ R7,D1     ;(9)
  RET         ;(10)
  END         ;(11)
按上面的设想分析一下前面的五条指令。
  第一条是让灯灭,第二条应当是延时,第三条是让灯亮,第四条和第二条一模一样,也是延时,第五条应当是转去执行第一条指令。第二和第四条实现的原理稍后谈,先看第五条,LJMP是一条指令,意思是转移,往什么地方转移呢?后面跟的是LOOP,看一下,什么地方还有LOOP,对了,在第一条指令的前面有一个LOOP,所以很直观地,我们可以认识到,它要转到第一条指令处。这个第一条指令前面的LOOP被称之为标号,它的用途就是给这一行起一个名字,便于使用。是否一定要给它起名叫LOOP呢?当然不是,起什么名字,完全由编程序的人决定,可以称它为A,X等等,当然,这时,第五条指令LJMP后面的名字也得跟着改了。
  第二条和第四条指令的用途是延时,它是怎样实现的呢?指令的形式是LCALL,这条指令称为调用子程序指令,看一下指令后面跟的是什么,DELAY,找一下DELAY,在第六条指令的前面,显然,这也是一个标号。这条指令的作用是这样的:当执行LCALL指令时,程序就转到LCALL后面的标号所标定的程序处执行,如果在执行指令的过程中遇到RET指令,则程序就返回到LCALL指令的下面的一条指令继续执行,从第六行开始的指令中,可以看到确实有RET指令。在执行第二条指令后,将转去执行第6条指令,而在执行完6,7,8,9条指令后将遇到第10条令:RET,执行该条指令后,程序将回来执行第三条指令,即将P10清零,使灯亮,然后又是第四条指令,执行第四条指令就是转去执行第6,7,8,9,10条指令,然后回来执行第5条指令,第5条指令就是让程序回到第1条开始执行,如此周而复始,灯就在不断地亮、灭了。
  在标号DELAY标志的这一行到RET这一行中的所有程序,这是一段延时程序,大概延时零点几秒,至于具体的时间,以后我们再学习如何计算。 程序的最后一行是END,这不是一条指令,它只是告诉我们程序到此结束,它被称为伪指令。
二、单片机内部结构分析:
  为了知道延时程序是如何工作的,我们必需首先了解延时程序中出现的一些符号, 就从R1开始,R1被称之为工作寄存器。什么是工作寄存器呢?让我们从现实生活中来找找答案。如果出一道数学题:123+567,让你回答结果是多少,你会马上答出是690,再看下面一道题:123+567+562,要让你要上回答,就不这么容易了吧?我们会怎样做呢?如果有张纸,就容易了,我们先算出123+567=690,把690写在纸上,然后再算690+562得到结果是1552。这其中1552是我们想要的结果,而690并非我们所要的结果,但是为了得到最终结果,我们又不得不先算出690,并记下来,这其实是一个中间结果,计算机中做运算和这个类似,为了要得到最终结果,往往要做很多步的中间结果,这些中间结果要有个地方放才行,把它们放哪呢?放在前面提到过的ROM中可以吗?显然不行,因为计算机要将结果写进去,而ROM是不可以写的,所以在单片机中另有一个区域称为RAM区(RAM是随机存取存储器的英文缩写),它可以将数据写进去。
  特别地,在MCS-51单片机中,将RAM中分出一块区域,称为工作寄存器区。

单片机第五课:单片机的内外部结构分析(三)
一、延时程序分析
上一次课中,我们已经知道,程序中的符号R7、R6是代表了一个个的RAM单元,是用来放一些数据的,下面我们再来看一下其它符号的含义。
DELAY: MOV R7,#250   ;(6)
D1: MOV R6,#250   ;(7)
D2: DJNZ R6,D2    ;(8)
DJNZ R7,D1   ;(9)    
RET        ;(10)


1.MOV:这是一条指令,意思是传递数据。说到传递,我们都很清楚,传东西要从一个人的手上传到另一个人的手上,也就是说要有一个接受者,一个传递者和一样东西。从指令MOV R7,#250中来分析,R7是一个接受者,250是被传递的数,传递者在这条指令中被省略了(注意:并不是每一条传递指令都会省的,事实上大部份数据传递指令都会有传递者)。它的意义也很明显:将数据250送到R7中去,因此执行完这条指令后,R7单元中的值就应当是250。在250前面有个#号,这又是什么意思呢?这个#就是用来说明250就是一个被传递的东西本身,而不是传递者。那么MOV R6,#250是什么意思,应当不用分析了吧。
2.DJNZ:这是另一条指令,我们来看一下这条指令后面跟着的两个东西,一个是R6,一个是D2,R6我们当然已知是什么了,查一下D2是什么。D2在本行的前面,我们已学过,这称之为标号。标号的用途是什么呢?就是给本行起一个名字。DJNZ指令的执行过程是这样的,它将其后面的第一个参数中的值减1,然后看一下,这个值是否等于0,如果等于0,就往下执行,如果不等于0,就转移,转到什么地方去呢?可能大家已猜到了,转到第二个参数所指定的地方去(请大家用自已的话讲一下这条语句是怎样执行的)。本条指令的最终执行结果就是,在原地转圈250次。
3.执行完了DJNZ R6,D2之后(也就是R6的值等于0之后),就会去执行下面一行,也就是DJNZ R7,D1,请大家自行分析一下这句话执行的结果。(转去执行MOV R6,#250,同时R7中的值减1),最终DJNZ R6,D2这句话将被执行250*250=62500次,执行这么多次同一条指令干吗?就是为了延时。
4.一个问题:如果在R6中放入0,会有什么样的结果。
二、时序分析:
前面我们介绍了延时程序,但这还不完善,因为,我们只知道DJNZ R6,D2这句话会被执行62500次,但是执行这么多次需要多长时间呢?是否满足我们的要求呢?我们还不知道,所以下面要来解决这个问题。
先提一个问题:我们学校里什么是最重要的。(铃声)校长可以出差,老师可以休息,但学校一日无铃声必定大乱。整个学校就是在铃声的统一指挥下,步调一致,统一协调地工作着。这个铃是按一定的时间安排来响的,我们可以称之为“时序��时间的顺序”。一个由人组成的单位尚且要有一定的时序,计算机当然更要有严格的时序。事实上,计算机更象一个大钟,什么时候分针动,什么时候秒针动,什么时候时针动,都有严格的规定,一点也不能乱。计算机要完成的事更复杂,所以它的时序也更复杂。
我们已知,计算机工作时,是一条一条地从ROM中取指令,然后一步一步地执行,我们规定:计算机访问一次存储器的时间,称之为一个机器周期。这是一个时间基准,好象我们人用“秒”作为我们的时间基准一样,为什么不干脆用“秒”,多好,很习惯,学下去我们就会知道用“秒”反而不习惯。
一个机器周期包括12个时钟周期。下面让我们算一下一个机器周期是多长时间吧。设一个单片机工作于12M晶振,它的时钟周期是1/12(微秒)。它的一个机器周期是12*(1/12)也就是1微秒。(请计算一个工作于6M晶振的单片机,它的机器周期是多少)。
MCS-51单片机的所有指令中,有一些完成得比较快,只要一个机器周期就行了,有一些完成得比较慢,得要2个机器周期,还有两条指令要4个机器周期才行。这也不难再解,不是吗?我让你扫地的执行要完成总得比要你完成擦黑板的指令时间要长。为了恒量指令执行时间的长短,又引入一个新的概念:指令周期。所谓指令周期就是指执行一条指令的时间。INTEL对每一条指令都给出了它的指令周期数,这些数据,大部份不需要我们去记忆,但是有一些指令是需要记住的,如DJNZ指令是双周期指令。
下面让我们来计算刚才的延时。首先必须要知道晶振的频率,我们设所用晶振为12M,则一个机器周期就是1微秒。而DJNZ指令是双周期指令,所以执行一次要2个微秒。一共执行62500次,正好125000微秒,也就是125毫秒。
练习:设计一个延时100毫秒的延时程序。
要点分析:1、一个单元中的数是否可以超过255。2、如何分配两个数。
三、复位电路
任何单片机在工作之前都要有个复位的过程,复位是什么意思呢?它就象是我们上课之前打的预备铃。预备铃一响,大家就自动地从操场、其它地方进入教室了,在这一段时间里,是没有老师干预的,对单片机来说,是程序还没有开始执行,是在做准备工作。显然,准备工作不需要太长的时间,复位只需要5ms的时间就可以了。如何进行复位呢?只要在单片机的RST引脚上加上高电平,就可以了,按上面所说,时间不少于5ms。为了达到这个要求,可以用很多种方法,这里提供一种供参考,见图1。实际上,我们在上一次实验的图中已见到过了。
这种复位电路的工作原理是:通电时,电容两端相当于是短路,于是RST引脚上为高电平,然后电源通过电阻对电容充电,RST端电压慢慢下降,降到一定程序,即为低电平,单片机开始正常工作。

单片机第六课:单片机的内外部结构分析(四)
1.第三个实验
上两次我们做过两个实验,都是让P1.0这个引脚使灯亮,我们可以设想:既然P1.0可以让灯亮,那么其它的引脚可不可以呢?看一下图1,它是8031单片机引脚的说明,在P1.0旁边有P1.1,P1.2….P1.7,它们是否都可以让灯亮呢?除了以P1开头的外,还有以P0,P2,P3开头的,数一下,一共是32个引脚,前面我们以学过7个引脚,加上这32个这39个了。它们都以P字开头,只是后面的数字不一样,它们是否有什么联系呢?它们能不能都让灯亮呢?在我们的实验板上,除了P10之外,还有P11�&#017都与LED相连,下面让我们来做一个实验,程序如下:
MAIN: MOV P1,#0FFH
LCALL DELAY
MOV P1,#00H
LCALL DELAY
LJMP MAIN
DELAY:MOV R7,#250
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET
END
将这段程序转为机器码,用编程器写入芯片中,结果如何?通电以后我们可以看到8只LED全部在闪动。因此,P10�&#017是全部可以点亮灯的。事实上,凡以P开头的这32个引脚都是可以点亮灯的,也就是说:这32个引脚都可以作为输出使用,如果不用来点亮LED,可以用来控制继电器,可以用来控制其它的执行机构。
程序分析:这段程序和前面做过的程序比较,只有两处不一样:第一句:原来是SETB P1.0,现在改为MOV P1,#0FFH,第三句:原来是CLR P1.0,现在改为MOV P1.0,#00H。从中可以看出,P1是P1.0�&#01.7的全体的代表,一个P1就表示了所有的这八个管脚了。当然用的指令也不一样了,是用MOV指令。为什么用这条指令?看图2,我们把P1作为一个整体,就把它当作是一个存储器的单元,对一个单元送进一个数可以用MOV指令。
二、第四个实验
除了可以作为输出外,这32个引脚还可以做什么呢?下面再来做一个实验,程序如下:
MAIN: MOV P3,#0FFH
LOOP: MOV A,P3
MOV P1,A
LJMP LOOP
先看一下实验的结果:所有灯全部不亮,然后我按下一个按钮,第()个灯亮了,再按下另一个按钮,第()个灯亮了,松开按钮灯就灭了。从这个实验现象结合电路来分析一下程序。
从硬件电路的连线可以看出,有四个按钮被接入到P3口的P32,P33,P34,P35。第一条指令的用途我们可以猜到:使P3口全部为高电平。第二条指令是MOV A,P3,其中 MOV已经见,是送数的意思,这条指令的意思就是将P3口的数送到A中去,我们可以把A当成是一个中间单元(看图3),第三句话是将A中的数又送到P1口去,第四句话是循环,就是不断地重复这个过程,这我们已见过。当我们按下第一个按钮时,第(3)只灯亮了,所以P12口应当输出是低电平,为什么P12口会输出低电平呢?我们看一下有什么被送到了P1口,只有从P3口进来的数送到A,又被送到了P1口,所以,肯定是P3口进来的数使得P12位输出电平的。P3口的P32位的按钮被按下,使得P32位的电平为低,通过程序,又使P12口输出低电平,所以P3口起来了一个输入的作用。验证:按第二、三、四个按钮,同时按下2个、3个、4个按钮都可以得到同样的结论,所以P3口确实起到了输入作用,这样,我们可以看到,以P字开头的管脚,不仅可以用作输出,还可以用作输入,其它的管脚是否可以呢?是的,都可以。这32个引脚就称之为并行口,下面我们就对并行口的结构作一个分析,看一下它是怎样实现输入和输出的。
3.并行口结构分析:
1、输出结构
先看P1口的一位的结构示意图(只画出了输出部份):从图中可以看出,开关的打开和合上代表了引脚输出的高和低,如果开关合上了,则引脚输出就是低,如果开关打开了,则输出高电平,这个开关是由一根线来控制的,这根数据总线是出自于CPU,让我们回想一下,数据总线是一根大家公用的线,很多的器件和它连在一起,在不同的时候,不同的器件当然需要不同的信号,如某一时刻我们让这个引脚输出高电平,并要求保持若干时间,在这段时间里,计算机当然在忙个不停,在与其它器件进行联络,这根控制线上的电平未必能保持原来的值不变,输出就会发生变化了。怎么解决这个问题呢?我们在存储器一节中学过,存储器中是可以存放电荷的,我们不妨也加一个小的存储器的单元,并在它的前面加一个开关,要让这一位输出时,就把开关打开,信号就进入存储器的单元,然后马上关闭开关,这样这一位的状态就被保存下来,直到下一次命令让它把开关再打开为止。这样就能使这一位的状态与别的器件无关了,这么一个小单元,我们给它一个很形象的名字,称之为“锁存器”。
2、输入结构
这是并行口的一位的输出结构示意图,再看,除了输出之外,还有两根线,一根从外部引脚接入,另一根从锁存器的输出接出,分别标明读引脚和读锁存器。这两根线是用于从外部接收信号的,为什么要两根呢?原来,在51单片机中输入有两种方式,分别称为‘读引脚’和‘读锁存器’,第一种方式是将引脚作为输入,那是真正地从外部引脚读进输入的值,第二种方式是该引脚处于输出状态时,有时需要改变这一位的状态,则并不需要真正地读引脚状态,而只是读入锁存器的状态,然后作某种变换后再输出。
请注意输入结构图,如果将这一根引线作为输入口使用,我们并不能保证在任何时刻都能得到正确的结果(为什么?)参考图2输入示意图。接在外部的开关如果打开,则应当是输入1,而如果闭合开关,则输入0,但是,如果单片机内部的开关是闭合的,那么不管外部的开关是开还是闭,单片机接受到的数据都是0。可见,要让这一端口作为输入使用,要先做一个‘准备工作’,就是先让内部的开关断开,也就是让端口输出‘1’才行。正因为要先做这么一个准备工作,所以我们称之为“准双向I/O口”。
以上是P1口的一位的结构,P1口其它各位的结构与之相同,而其它三个口:P0、P2、P3则除入作为输入输出口之外还有其它用途,所以结构要稍复杂一些,但其用于输入、输出的结构是相同的。看图()。对我们来说,这些附加的功能不必由我们来控制,所以我们就不去关心它了。

单片机第七课:单片机内部结构分析(五)
通过前面的学习,我们已知单片机的内部有ROM、有RAM、有并行I/O口,那么,除了这些东西之外,单片机内部究竟还有些什么,这些个零碎的东西怎么连在一起的,让我们来对单片机内部作一个完整的分析吧!
看图(1)(本图太大,请大家找本书看吧,一般讲单片机的书,随便哪本都有)。从图中我们可以看出,在51单片机内部有一个CPU用来运算、控制,有四个并行I/O口,分别是P0、P1、P2、P3,有ROM,用来存放程序,有RAM,用来存放中间结果,此外还有定时/计数器,串行I/O口,中断系统,以及一个内部的时钟电路。在一个51单片机的内部包含了这么多的东西。
对上面的图进行进一步的分析,我们已知,对并行I/O口的读写只要将数据送入到相应I/O口的锁存器就可以了,那么对于定时/计数器,串行I/O口等怎么用呢?在单片机中有一些独立的存储单元是用来控制这些器件的,被称之为特殊功能寄存器(SFR)。事实上,我们已接触过P1这个特殊功能寄存器了,还有哪些呢?看表1
符号 地址 功能介绍
B F0H B寄存器
ACC E0H 累加器
PSW D0H 程序状态字
IP B8H 中断优先级控制寄存器
P3 B0H P3口锁存器
IE A8H 中断允许控制寄存器
P2 A0H P2口锁存器
SBUF 99H 串行口锁存器
SCON 98H 串行口控制寄存器
P1 90H P1口锁存器
TH1 8DH 定时器/计数器1(高8位)
TH0 8CH 定时器/计数器1(低8位)
TL1 8BH 定时器/计数器0(高8位)
TL0 8AH 定时器/计数器0(低8位)
TMOD 89A 定时器/计数器方式控制寄存器
TCON 88H 定时器/计数器控制寄存器
DPH 83H 数据地址指针(高8位)
DPL 82H 数据地址指针(低8位)
SP 81H 堆栈指针
P0 80H P0口锁存器
PCON 87H 电源控制寄存器
表1
下面,我们介绍一下几个常用的SFR,看图2。
1.ACC:累加器,通常用A表示。这是个什么东西,可不能从名字上理解,它是一个寄存器,而不是一个做加法的东西,为什么给它这么一个名字呢?或许是因为在运算器做运算时其中一个数一定是在ACC中的缘故吧。它的名字特殊,身份也特殊,稍后我们将学到指令,可以发现,所有的运算类指令都离不开它。
2、B:一个寄存器。在做乘、除法时放乘数或除数,不做乘除法时,随你怎么用。
3、PSW:程序状态字。这是一个很重要的东西,里面放了CPU工作时的很多状态,借此,我们可以了解CPU的当前状态,并作出相应的处理。它的各位功能请看表2
D7D6D5D4D3D2D1D0
CYACF0RS1RS0OV P
表2
下面我们逐一介绍各位的用途
(1)CY:进位标志。8051中的运算器是一种8位的运算器,我们知道,8位运算器只能表示到0-255,如果做加法的话,两数相加可能会超过255,这样最高位就会丢失,造成运算的错误,怎么办?最高位就进到这里来。这样就没事了。
例:78H+97H(01111000+10010111)
(2)AC:半进位标志。
例:57H+3AH(01010111+00111010)
(3)F0:用户标志位,由我们(编程人员)决定什么时候用,什么时候不用。
(4)RS1、RS0:工作寄存器组选择位。这个我们已知了。
(5)0V:溢出标志位。什么是溢出我们稍后再谈吧。
(6)P:奇偶校验位:它用来表示ALU运算结果中二进制数位“1”的个数的奇偶性。若为奇数,则P=1,否则为0。
例:某运算结果是78H(01111000),显然1的个数为偶数,所以P=0。
4、DPTR(DPH、DPL):数据指针,可以用它来访问外部数据存储器中的任一单元,如果不用,也可以作为通用寄存器来用,由我们自已决定如何使用。
5、P0、P1、P2、P3:这个我们已经知道,是四个并行输入/输出口的寄存器。它里面的内容对应着管脚的输出。
6、SP:堆栈指针。
堆栈介绍:日常生活中,我们都注意到过这样的现象,家里洗的碗,一只一只摞起来,最晚放上去的放在最上面,而最早放上去的则放在最下面,在取的时候正好相反,先从最上面取,这种现象我们用一句话来概括:“先进后出,后进先出”。请大家想想,还有什么地方有这种现象?其实比比皆是,建筑工地上堆放的砖头、材料,仓库里放的货物,都是“先进后出,后进先出”,这实际是一种存取物品的规则,我们称之为“堆栈”。
在单片机中,我们也可以在RAM中构造这样一个区域,用来存放数据,这个区域存放数据的规则就是“先进后出,后进先出”,我们称之为“堆栈”。为什么需要这样来存放数据呢?存储器本身不是可以按地址来存放数据吗?对,知道了地址的确就可以知道里面的内容,但如果我们需要存放的是一批数据,每一个数据都需要知道地址那不是麻烦吗?如果我们让数据一个接一个地放置,那么我们只要知道第一个数据所在地址单元就可以了(看图2)如果第一个数据在27H,那么第二、三个就在28H、29H了。所以利用堆栈这种方法来放数据可以简化操作
那么51中堆栈什么地方呢?单片机中能存放数据的区域有限,我们不能够专门分配一块地方做堆栈,所以就在内存(RAM)中开辟一块地方,用于堆栈,但是用内存的哪一块呢?还是不好定,因为51是一种通用的单片机,各人的实际需求各不相同,有人需要多一些堆栈,而有人则不需要那么多,所以怎么分配都不合适,怎样来解决这个问题?分不好干脆就不分了,把分的权利给用户(编程者),根据自已的需要去定吧,所以51单片机中堆栈的位置是可以变化的。而这种变化就体现在SP中值的变化,看图2,SP中的值等于27H不就相当于是一个指针指向27H单元吗?当然在真正的51机中,开始指针所指的位置并非就是数据存放的位置,而是数据存放的前一个位置,比如一开始指针是指向27H单元的,那么第一个数据的位置是28H单元,而不是27H单元,为什么会这样,我们在学堆栈命令时再说明。
图2
其它的SFR,我们在用到时再介绍。

单片机第八课(寻址方式与指令系统)
通过前面的学习,我们已经了解了单片机内部的结构,并且也已经知道,要控制单片机,让它为我们干学,要用指令,我们已学了几条指令,但很零散,从现在开始,我们将要系统地学习8051的指令部份。
一、概述
1、指令的格式
我们已知,要让计算机做事,就得给计算机以指令,并且我们已知,计算机很“笨”,只能懂得数字,如前面我们写进机器的75H,90H,00H等等,所以指令的第一种格式就是机器码格式,也说是数字的形式。但这种形式实在是为难我们人了,太难记了,于是有另一种格式,助记符格式,如MOV P1,#0FFH,这样就好记了。 这两种格式之间的关系呢,我们不难理解,本质上它们完全等价,只是形式不一样而已。
2、汇编
我们写指令使用汇编格式,而计算机只懂机器码格式,所以要将我们写的汇编格式的指令转换为机器码格式,这种转换有两种方法:手工汇编和机器汇编。手工汇编实际上就是查表,因为这两种格式纯粹是格式不同,所以是一一对应的,查一张表格就行了。不过手工查表总是嫌麻烦,所以就有了计算机软件,用计算机软件来替代手工查表,这就是机器汇编。
二、寻址
让我们先来复习一下我们学过的一些指令:MOV P1,#0FFH,MOV R7,#0FFH这些指令都是将一些数据送到相应的位置中去,为什么要送数据呢?第一个因为送入的数可以让灯全灭掉,第二个是为了要实现延时,从这里我们可以看出来,在用单片机的编程语言编程时,经常要用到数据的传递,事实上数据传递是单片机编程时的一项重要工作,一共有28条指令(单片机共111条指令)。下面我们就从数据传递类指令开始吧。
分析一下MOV P1,#0FFH这条指令,我们不难得出结论,第一个词MOV是命令动词,也就是决定做什么事情的,MOV是MOVE少写了一个E,所以就是“传递”,这就是指令,规定做什么事情,后面还有一些参数,分析一下,数据传递必须要有一个“源”也就是你要送什么数,必须要有一个“目的”,也就是你这个数要送到什么地方去,显然在上面那条指令中,要送的数(源)就是0FFH,而要送达的地方(目的地)就是P1这个寄存器。在数据传递类指令中,均将目的地写在指令的后面,而将源写在最后。
这条指令中,送给P1是这个数本身,换言之,做完这条指令后,我们可以明确地知道,P1中的值是0FFH,但是并不是任何时候都可以直接给出数本身的。例如,在我们前面给出的延时程序例是这样写的:
MAIN: SETB P1.0     ;(1)
   LCALL DELAY ;(2)
    CLR P1.0      ;(3)
   LCALL DELAY   ;(4)
    AJMP MAIN    ;(5)
;以下子程序
DELAY: MOV R7,#250   ;(6)
D1: MOV R6,#250   ;(7)
D2: DJNZ R6,D2    ;(8)
   DJNZ R7,D1   ;(9)
   RET        ;(10)
   END        ;(11)


表1 MAIN: SETB P1.0     ;(1)
   MOV 30H,#255
    LCALL DELAY ;
    CLR P1.0      ;(3)
    MOV 30H,#200
    LCALL DELAY   ;(4)
    AJMP MAIN    ;(5)
;以下子程序
DELAY: MOV R7,30H   ;(6)
D1: MOV R6,#250   ;(7)
D2: DJNZ R6,D2    ;(8)
   DJNZ R7,D1   ;(9)
   RET        ;(10)
   END        ;(11)
表2
 这样一来,我每次调用延时程序延时的时间都是相同的(大致都是0.13S),如果我提出这样的要求:灯亮后延时时间为0.13S灯灭,灯灭后延时0.1秒灯亮,如此循环,这样的程序还能满足要求吗?不能,怎么办?我们可以把延时程序改成这样(见表2):调用则见表2中的主程,也就是先把一个数送入30H,在子程序中R7中的值并不固定,而是根据30H单元中传过来的数确定。这样就可以满足要求。
从这里我们可以得出结论,在数据传递中要找到被传递的数,很多时候,这个数并不能直接给出,需要变化,这就引出了一个概念:如何寻找操作数,我们把寻找操作数所在单元的地址称之为寻址。在这里我们直接使用数所在单元的地址找到了操作数,所以称这种方法为直接寻址。除了这种方法之外,还有一种,如果我们把数放在工作寄存器中,从工作寄存器中寻找数据,则称之为寄存器寻址。例:MOV A,R0就是将R0工作寄存器中的数据送到累加器A中去。提一个问题:我们知道,工作寄存器就是内存单元的一部份,如果我们选择工作寄存器组0,则R0就是RAM的00H单元,那么这样一来,MOV A,00H,和MOV A,R0不就没什么区别了吗?为什么要加以区分呢?的确,这两条指令执行的结果是完全相同的,都是将00H单元中的内容送到A中去,但是执行的过程不同,执行第一条指令需要2个周期,而第二条则只需要1个周期,第一条指令变成最终的目标码要两个字节(E5H 00H),而第二条则只要一个字节(E8h)就可以了。
这么斤斤计较!不就差了一个周期吗,如果是12M的晶振的话,也就1个微秒时间了,一个字节又能有多少?
不对,如果这条指令只执行一次,也许无所谓,但一条指令如果执行上1000次,就是1毫秒,如果要执行1000000万次,就是1S的误差,这就很可观了,单片机做的是实时控制的事,所以必须如此“斤斤计较”。字节数同样如此。
再来提一个问题,现在我们已知,寻找操作数可以通过直接给的方式(立即寻址)和直接给出数所在单元地址的方式(直接寻址),这就够了吗?
看这个问题,要求从30H单元开始,取20个数,分别送入A累加器。
就我们目前掌握的办法而言,要从30H单元取数,就用MOV A,30H,那么下一个数呢?是31H单元的,怎么取呢?还是只能用MOV A,31H,那么20个数,不是得20条指令才能写完吗?这里只有20个数,如果要送200个或2000个数,那岂不要写上200条或2000条命令?这未免太笨了吧。为什么会出现这样的状况?是因为我们只会把地址写在指令中,所以就没办法了,如果我们不是把地址直接写在指令中,而是把地址放在另外一个寄存器单元中,根据这个寄存器单元中的数值决定该到哪个单元中取数据,比如,当前这个寄存器中的值是30H,那么就到30H单元中去取,如果是31H就到31H单元中去取,就可以解决这个问题了。怎么个解决法呢?既然是看的寄存器中的值,那么我们就可以通过一定的方法让这里面的值发生变化,比如取完一个数后,将这个寄存器单元中的值加1,还是执行同一条指令,可是取数的对象却不一样了,不是吗。通过例子来说明吧。
   MOV R7,#20
   MOV R0,#30H
LOOP:MOV A,@R0
   INC R0
   DJNZ R7,LOOP
这个例子中大部份指令我们是能看懂的,第一句,是将立即数20送到R7中,执行完后R7中的值应当是20。第二句是将立即数30H送入R0工作寄存器中,所以执行完后,R0单元中的值是30H,第三句,这是看一下R0单元中是什么值,把这个值作为地址,取这个地址单元的内容送入A中,此时,执行这条指令的结果就相当于MOV A,30H。第四句,没学过,就是把R0中的值加1,因此执行完后,R0中的值就是31H,第五句,学过,将R7中的值减1,看是否等于0,不等于0,则转到标号LOOP处继续执行,因此,执行完这句后,将转去执行MOV A,@R0这句话,此时相当于执行了MOV A,31H(因为此时的R0中的值已是31H了),如此,直到R7中的值逐次相减等于0,也就是循环20次为止,就实现了我们的要求:从30H单元开始将20个数据送入A中。
这也是一种寻找数据的方法,由于数据是间接地被找到的,所以就称之为间址寻址。注意,在间址寻址中,只能用R0或R1存放等寻找的数据。
二、指令
1.数据传递类指令
1) 以累加器为目的操作数的指令
MOV A,Rn
MOV A,direct
MOV A,@Ri
MOV A,#data
第一条指令中,Rn代表的是R0-R7。第二条指令中,direct就是指的直接地址,而第三条指令中,就是我们刚才讲过的。第四条指令是将立即数data送到A中。
下面我们通过一些例子加以说明:
MOV A,R1 ;将工作寄存器R1中的值送入A,R1中的值保持不变。
MOV A,30H ;将内存30H单元中的值送入A,30H单元中的值保持不变。
MOV A,@R1 ;先看R1中是什么值,把这个值作为地址,并将这个地址单元中的值送入A中。如执行命令前R1中的值为20H,则是将20H单元中的值送入A中。
MOV A,#34H ;将立即数34H送入A中,执行完本条指令后,A中的值是34H。
2)以寄存器Rn为目的操作的指令
MOV Rn,A
  MOV Rn,direct
  MOV Rn,#data
这组指令功能是把源地址单元中的内容送入工作寄存器,源操作数不变。

单片机指令(二)
1.数据传递类指令
(3)以直接地址为目的操作数的指令
MOV direct,A 例: MOV 20H,A
MOV direct,Rn MOV 20H,R1
MOV direct1,direct2 MOV 20H,30H
MOV direct,@Ri MOV 20H,@R1
MOV direct,#data MOV 20H,#34H
(4)以间接地址为目的操作数的指令
MOV @Ri,A 例:MOV @R0,A
MOV @Ri,direct MOV @R1,20H
MOV @Ri,#data MOV @R0,#34H
(5)十六位数的传递指令
MOV DPTR,#data16
8051是一种8位机,这是唯一的一条16位立即数传递指令,其功能是将一个16位的立即数送入DPTR中去。其中高8位送入DPH,低8位送入DPL。例:MOV DPTR,#1234H,则执行完了之后DPH中的值为12H,DPL中的值为34H。反之,如果我们分别向DPH,DPL送数,则结果也一样。如有下面两条指令:MOV DPH,#35H,MOV DPL,#12H。则就相当于执行了MOV DPTR,#3512H。
综合练习:
1.给出每条指令执行后的结果
MOV 23H,#30H
MOV 12H,#34H
MOV R0,#23H
MOV R7,#22H
MOV R1,12H
MOV A,@R0
MOV 34H,@R1(23h)=30h
(12h)=34h
(R0)=23H
(R7)=22H
(R1)=12H
(A)=30H
(34H)=34HMOV 45H,34H
MOV DPTR,#6712H
MOV 12H,DPH
MOV R0,DPL
MOV A,@R0(45H)=34H
(DPTR)=6712H
(12H)=67H
(R0)=12H
(A)=67H
2.说明:用括号括起来代表内容,如(23H)则代表内部RAM23H单元中的值,(A)则代表累加器A单元中的值。
3.上机练习:
1.进入DOS状态,进入WAVE所在的目录,例D:\WAVE
2.键入MCS51,出现如下画面

图1
3.按File-Open,出现对话框后,在Name处输入一个文件名(见图2),如果是下面列表中已存在的,则打开这个文件,如果不存在这个文件,则新建一个文件(见图3)
图2
4.在空白处将上面的程序输入。见图4。用ALT+A汇编通过。用F8即可单步执行,在执行过程中注意观察屏幕左边的工作寄存器及A累加器中的值的变化。

图4
5.内存中值的变化在此是看不到的,可以用如下方法观察(看图5):将鼠标移到DATA,双击,则光标进入此行,此时可以键盘上的上下光标键上下翻动来观察内存值的变化。本行的最前面DATA后面的数据代表的是“一段”的开始地址,如现在为20H,再看屏幕的最上方,数字从0到F,显示两者相加就等于真正的地址值,如现在图上所示的内存20H、21H、22H、23H中的值分别是FBH 、0EH、E8H、30H。

图5
6、当运行完程序后,即进入它的反汇编区,不是我们想要的东西。为了再从头开始,可以用CTRL+F2功能键复位PC值。注意此时不会看到原来的窗口,为看到原来的窗口,请用ALT+4或ALT+5等来切换。当然以上操作也可以菜单进行。CTRL+F2是程序复位,用RUN菜单。窗口用WINDOWS菜单。
此次大家就用用熟这个软件吧,说实话,我并不很喜欢它,操作起来不方便,但给我的机器只能上这个,没办法,下次再给网友单独介绍一个好一点的吧
单片机指令(三)
2、累加器A与片外RAM之间的数据传递类指令
MOVX A,@Ri
MOVX @Ri,A
MOVX A,@DPTR
MOVX @DPTR,A
说明:
1)在51中,与外部存储器RAM打交道的只可以是A累加器。所有需要送入外部RAM的数据必需要通过A送去,而所有要读入的外部RAM中的数据也必需通过A读入。在此我们可以看出内外部RAM的区别了,内部RAM间可以直接进行数据的传递,而外部则不行,比如,要将外部RAM中某一单元(设为0100H单元的数据)送入另一个单元(设为0200H单元),也必须先将0100H单元中的内容读入A,然后再送到0200H单元中去。
2.要读或写外部的RAM,当然也必须要知道RAM的地址,在后两条指令中,地址是被直接放在DPTR中的。而前两条指令,由于Ri(即R0或R1)只是一个8位的寄存器,所以只提供低8位地址。因为有时扩展的外部RAM的数量比较少,少于或等于256个,就只需要提供8位地址就够了。
3.使用时应当首先将要读或写的地址送入DPTR或Ri中,然后再用读写命令。
例:将外部RAM中100H单元中的内容送入外部RAM中200H单元中。
MOV DPTR,#0100H
MOVX A,@DPTR
MOV DPTR,#0200H
MOVX @DPTR,A
3.程序存储器向累加器A传送指令
MOVC A,@A+DPTR
本指令是将ROM中的数送入A中。本指令也被称为查表指令,常用此指令来查一个已做好在ROM中的表格
说明:
1.此条指令引出一个新的寻址方法:变址寻址。本指令是要在ROM的一个地址单元中找出数据,显然必须知道这个单元的地址,这个单元的地址是这样确定的:在执行本指令立脚点DPTR中有一个数,A中有一个数,执行指令时,将A和DPTR中的数加起为,就成为要查找的单元的地址。
2.查找到的结果被放在A中,因此,本条指令执行前后,A中的值不一定相同。
例:有一个数在R0中,要求用查表的方法确定它的平方值(此数的取值范围是0-5)
MOV DPTR,#TABLE
MOV A,R0
MOVC A,@A+DPTR
.
.
TABLE: DB 0,1,4,9,16,25
设R0中的值为2,送入A中,而DPTR中的值则为TABLE,则最终确定的ROM单元的地址就是TABLE+2,也就是到这个单元中去取数,取到的是4,显然它正是2的平方。其它数据也可以类推。



标号的真实含义:从这个地方也可以看到另一个问题,我们使用了标号来替代具体的单元地址。事实上,标号的真实含义就是地址数值。在这里它代表了,0,1,4,9,16,25这几个数据在ROM中存放的起点位置。而在以前我们学过的如LCALL DELAY指令中,DELAY 则代表了以DELAY为标号的那段程序在ROM中存放的起始地址。事实上,CPU正是通过这个地址才找到这段程序的。

可以通过以下的例子再来看一看标号的含义:

MOV DPTR,#100H

MOV A,R0

MOVC A,@A+DPTR

.
ORG 0100H.
DB 0,1,4,9,16,25
如果R0中的值为2,则最终地址为100H+2为102H,到102H单元中找到的是4。这个可以看懂了吧?
那为什么不这样写程序,要用标号呢?不是增加疑惑吗?
如果这样写程序的话,在写程序时,我们就必须确定这张表格在ROM中的具体的位置,如果写完程序后,又想在这段程序前插入一段程序,那么这张表格的位置就又要变了,要改ORG 100H这句话了,我们是经常需要修改程序的,那多麻烦,所以就用标号来替代,只要一编译程序,位置就自动发生变化,我们把这个麻烦事交给计算机��指PC机去做了。
堆栈操作
PUSH direct
POP direct
第一条指令称之为推入,就是将direct中的内容送入堆栈中,第二条指令称之为弹出,就是将堆栈中的内容送回到direct中。推入指令的执行过程是,首先将SP中的值加1,然后把SP中的值当作地址,将direct中的值送进以SP中的值为地址的RAM单元中。例:
MOV SP,#5FH
MOV A,#100
MOV B,#20
PUSH ACC
PUSH B
则执行第一条PUSH ACC指令是这样的:将SP中的值加1,即变为60H,然后将A中的值送到60H单元中,因此执行完本条指令后, 内存60H单元的值就是100,同样,执行PUSH B时,是将SP+1,即变为61H,然后将B中的值送入到61H单元中,即执行完本条指令后,61H单元中的值变为20。
POP指令的执行是这样的,首先将SP中的值作为地址,并将此地址中的数送到POP指令后面的那个direct中,然后SP减1。
接上例:
POP B
POP ACC
则执行过程是:将SP中的值(现在是61H)作为地址,取61H单元中的数值(现在是20),送到B中,所以执行完本条指令后B中的值是20,然后将SP减1,因此本条指令执行完后,SP的值变为60H,然后执行POP ACC,将SP中的值(60H)作为地址,从该地址中取数(现在是100),并送到ACC中,所以执行完本条指令后,ACC中的值是100。
这有什么意义呢?ACC中的值本来就是100,B中的值本来就是20,是的,在本例中,的确没有意义,但在实际工作中,则在PUSH B后往往要执行其他指令,而且这些指令会把A中的值,B中的值改掉,所以在程序的结束,如果我们要把A和B中的值恢复原值,那么这些指令就有意义了。
还有一个问题,如果我不用堆栈,比如说在PUSH ACC指令处用MOV 60H,A,在PUSH B处用指令MOV 61H,B,然后用MOV A,60H,MOV B,61H来替代两条POP指令,不是也一样吗?是的,从结果上看是一样的,但是从过程看是不一样的,PUSH和POP指令都是单字节,单周期指令,而MOV指令则是双字节,双周期指令。更何况,堆栈的作用不止于此,所以一般的计算机上都设有堆栈,而我们在编写子程序,需要保存数据时,通常也不采用后面的方法,而是用堆栈的方法来实现。
例:写出以下程序的运行结果
MOV 30H,#12
MOV 31H,#23
PUSH 30H
PUSH 31H
POP 30H
POP 31H
结果是30H中的值变为23,而31H中的值则变为12。也就两者进行了数据交换。从这个例子可以看出:使用堆栈时,入栈的书写顺序和出栈的书写顺序必须相反,才能保证数据被送回原位,否则就要出错了。
作业:在MCS51下执行上面的例程,注意观察内存窗口和堆栈的变化。
单片机指令(四)算术运算类指令
1.不带进位位的加法指令
ADD A,#DATA &#59;例:ADD A,#10H
ADD A,direct &#59;例:ADD A,10H
ADD A,Rn &#59;例:ADD A,R7
ADD A,@Ri &#59;例:ADD A,@R0
用途:将A中的值与其后面的值相加,最终结果否是回到A中。
例:MOV A,#30H
ADD A,#10H
则执行完本条指令后,A中的值为40H。
下面的题目自行练习
MOV 34H,#10H
MOV R0,#13H
MOV A,34H
ADD A,R0
MOV R1,#34H
ADD A,@R1
2.带进位位的加法指令
ADDC A,Rn
ADDC A,direct
ADDC A,@Ri
ADDC A,#data
用途:将A中的值和其后面的值相加,并且加上进位位C中的值。
说明:由于51单片机是一种8位机,所以只能做8位的数学运算,但8位运算的范围只有0-255,这在实际工作中是不够的,因此就要进行扩展,一般是将2个8位的数学运算合起来,成为一个16位的运算,这样,可以表达的数的范围就可以达到0-65535。如何合并呢?其实很简单,让我们看一个10进制数的例子:
66+78。
这两个数相加,我们根本不在意这的过程,但事实上我们是这样做的:先做6+8(低位),然后再做6+7,这是高位。做了两次加法,只是我们做的时候并没有刻意分成两次加法来做罢了,或者说我们并没有意识到我们做了两次加法。之所以要分成两次来做,是因为这两个数超过了一位数所能表达的范置(0-9)。
在做低位时产生了进位,我们做的时候是在适当的位置点一下,然后在做高位加法是将这一点加进去。那么计算机中做16位加法时同样如此,先做低8位的,如果两数相加产生了进位,也要“点一下”做个标记,这个标记就是进位位C,在PSW中。在进行高位加法是将这个C加进去。例:1067H+10A0H,先做67H+A0H=107H,而107H显然超过了0FFH,因此最终保存在A中的是7,而1则到了PSW中的CY位了,换言之,CY就相当于是100H。然后再做10H+10H+CY,结果是21H,所以最终的结果是2107H。
3.带借位的减法指令
SUBB A,Rn
SUBB A,direct
SUBB A,@Ri
SUBB A,#data
设(每个H,(R2)=55H,CY=1,执行指令SUBB A,R2之后,A中的值为73H。
说明:没有不带借位的减法指令,如果需要做不带位的减法指令(在做第一次相减时),只要将CY清零即可。
4.乘法指令
MUL AB
此指令的功能是将A和B中的两个8位无符号数相乘,两数相乘结果一般比较大,因此最终结果用1个16位数来表达,其中高8位放在B中,低8位放在A中。在乘积大于FFFFFH(65535)时,0V置1(溢出),否则OV为0,而CY总是0。
例:(A)=4EH,(B)=5DH,执行指令
MUL AB后,乘积是1C56H,所以在B中放的是1CH,而A中放的则是56H。
5.除法指令
DIV AB
此指令的功能是将A中的8位无符号数除了B中的8位无符号数(A/B)。除法一般会出现小数,但计算机中可没法直接表达小数,它用的是我们小学生还没接触到小数时用的商和余数的概念,如13/5,其商是2,余数是3。除了以后,商放在A中,余数放在B中。CY和OV都是0。如果在做除法前B中的值是00H,也就是除数为0,那么0V=1。
6.加1指令
INC A
INC Rn
INC direct
INC @Ri
INC DPTR
用途很简单,就是将后面目标中的值加1。例:(A)=12H,(R0)=33H,(21H)=32H,(34H)=22H,DPTR=1234H。执行下面的指令:
INC A (A)=13H
INC R2 (R0)=34H
INC 21H (21H)=33H
INC @R0 (34H)=23H
INC DPTR ( DPTR)=1235H
后结果如上所示。
说明:从结果上看INC A和ADD A,#1差不多,但INC A是单字节,单周期指令,而ADD #1则是双字节,双周期指令,而且INC A不会影响PSW位,如(A)=0FFH,INC A后(A)=00H,而CY依然保持不变。如果是ADD A ,#1,则(A)=00H,而CY一定是1。因此加1指令并不适合做加法,事实上它主要是用来做计数、地址增加等用途。另外,加法类指令都是以A为核心的��其中一个数必须放在A中,而运算结果也必须放在A中,而加1类指令的对象则广泛得多,可以是寄存器、内存地址、间址寻址的地址等等。
减1指令
7.减1指令
DEC A
DEC RN
DEC direct
DEC @Ri
与加1指令类似,就不多说了。
综合练习:
MOV A,#12H
MOV R0,#24H
MOV 21H,#56H
ADD A,#12H
MOV DPTR,#4316H
ADD A,DPH
ADD A,R0
CLR C
SUBB A,DPL
SUBB A,#25H
INC A
SETB C
ADDC A,21H
INC R0
SUBB A,R0
MOV 24H,#16H
CLR C
ADD A,@R0
先写出每步运行结果,然后将以上题目建入,并在软件仿真中运行,观察寄存器及有关单元的内容的变化,是否与自已的预想结果相同
三、逻辑运算类指令:
1.对累加器A的逻辑操作:
CLR A ;将A中的值清0,单周期单字节指令,与MOV A,#00H效果相同。
CPL A ;将A中的值按位取反

RL A ;将A中的值逻辑左移
RLC A ;将A中的值加上进位位进行逻辑左移
RR A ;将A中的值进行逻辑右移
RRC A ;将A中的值加上进位位进行逻辑右移
SWAP A ;将A中的值高、低4位交换。
例:(A)=73H,则执行CPL A,这样进行:
73H化为二进制为01110011,
逐位取反即为 10001100,也就是8CH。
RL A是将(A)中的值的第7位送到第0位,第0位送1位,依次类推。
例:A中的值为68H,执行RL A。68H化为二进制为01101000,按上图进行移动。01101000化为11010000,即D0H。
RLC A,是将(A)中的值带上进位位(C)进行移位。
例:A中的值为68H,C中的值为1,则执行RLC A
1 01101000后,结果是0 11010001,也就是C进位位的值变成了0,而(A)则变成了D1H。
RR A和RRC A就不多谈了,请大家参考上面两个例子自行练习吧。
SWAP A,是将A中的值的高、低4位进行交换。
例:(A)=39H,则执行SWAP A之后,A中的值就是93H。怎么正好是这么前后交换呢?因为这是一个16进制数,每1个16进位数字代表4个二进位。注意,如果是这样的:(A)=39,后面没H,执行SWAP A之后,可不是(A)=93。要将它化成二进制再算:39化为二进制是10111,也就是0001,0111高4位是0001,低4位是0111,交换后是01110001,也就是71H,即113。
练习,已知(A)=39H,执行下列指令后写出每步的结果
CPL A
RL A
CLR C
RRC A
SETB C
RLC A
SWAP A
通过前面的学习,我们已经掌握了相当一部份的指令,大家对这些枯燥的指令可能也有些厌烦了,下面让我们轻松一下,做个实验。
实验五:
ORG 0000H
LJMP START
ORG 30H
START:
MOV SP,#5FH
MOV A,#80H
LOOP:
MOV P1,A
RL A
LCALL DELAY
LJMP LOOP
delay:
mov r7,#255
d1: mov r6,#255
d2: nop
nop
nop
nop
djnz r6,d2
djnz r7,d1
ret
END
先让我们将程序写入片中,装进实验板,看一看现象。
看到的是一个暗点流动的现象,让我们来分析一下吧。
前而的ORG 0000H、LJMP START、ORG 30H等我们稍后分析。从START开始,MOV SP,#5FH,这是初始化堆栈,在本程序中有无此句无关紧要,不过我们慢慢开始接触正规的编程,我也就慢慢给大家培养习惯吧。
MOV A,#80H,将80H这个数送到A中去。干什么呢?不知道,往下看。
MOV P1,A。将A中的值送到P1端口去。此时A中的值是80H,所以送出去的也就是80H,因此P1口的值是80H,也就是10000000B,通过前面的分析,我们应当知道,此时P1。7接的LED是不亮的,而其它的LED都是亮的,所以就形成了一个“暗点”。继续看,RL A,RL A是将A中的值进行左移,算一下,移之后的结果是什么?对了,是01H,也就是00000001B,这样,应当是接在P1。0上的LED不亮,而其它的都亮了,从现象上看“暗点”流到了后面。然后是调用延时程序,这个我们很熟悉了,让这个“暗点”“暗”一会儿。然后又调转到LOOP处(LJMP LOOP)。请大家计算一下,下面该哪个灯不亮了。。。。。对了,应当是接在P1。1上灯不亮了。这样依次循环,就形成了“暗点流动”这一现象。
问题:
1.如何实现亮点流动?
2.如何改变流动的方向?
答案:
1、将A中的初始值改为7FH即可。
2、将RL A改为RR A即可。

逻辑与指令
ANL A,Rn &#59;A与Rn中的值按位’’与’’,结果送入A中
ANL A,direct &#59;A与direct中的值按位’’与’’,结果送入A中
ANL A,@Ri &#59;A与间址寻址单元@Ri中的值按位’’与’’,结果送入A中
ANL A,#data &#59;A与立即数data按位’’与’’,结果送入A中
ANL direct,A &#59;direct中值与A中的值按位’’与’’,结果送入direct中
ANL direct,#data &#59;direct中的值与立即数data按位’’与’’,结果送入direct中。
这几条指令的关键是知道什么是逻辑与。这里的逻辑与是指按位与
例:71H和56H相与则将两数写成二进制形式:
(71H) 01110001
(56H) 00100110
结果 00100000 即20H,从上面的式子可以看出,两个参与运算的值只要其中有一个位上是0,则这位的结果就是0,两个同是1,结果才是1。
理解了逻辑与的运算规则,结果自然就出来了。看每条指令后面的注释
下面再举一些例子来看。
MOV A,#45H &#59;(A)=45H
MOV R1,#25H &#59;(R1)=25H
MOV 25H,#79H &#59;(25H)=79H
ANL A,@R1 &#59;45H与79H按位与,结果送入A中为 41H (A)=41H
ANL 25H,#15H &#59;25H中的值(79H)与15H相与结果为(25H)=11H)
ANL 25H,A &#59;25H中的值(11H)与A中的值(41H)相与,结果为(25H)=11H
在知道了逻辑与指令的功能后,逻辑或和逻辑异或的功能就很简单了。逻辑或是按位“或”,即有“1”为1,全“0”为0。例:
10011000
或 01100001
结果 11111001
而异或则是按位“异或”,相同为“0”,相异为“1”。例:
10011000
异或 01100001
结果 11111001
而所有的或指令,就是将与指仿中的ANL 换成ORL,而异或指令则是将ANL 换成XRL。即
或指令:
ORL A,Rn &#59;A和Rn中的值按位’’或’’,结果送入A中
ORL A,direct &#59;A和与间址寻址单元@Ri中的值按位’’或’’,结果送入A中
ORL A,#data &#59;A和立direct中的值按位’’或’’,结果送入A中
ORL A,@Ri &#59;A和即数data按位’’或’’,结果送入A中
ORL direct,A &#59;direct中值和A中的值按位’’或’’,结果送入direct中
ORL direct,#data &#59;direct中的值和立即数data按位’’或’’,结果送入direct中。
异或指令:
XRL A,Rn &#59;A和Rn中的值按位’’异或’’,结果送入A中
XRL A,direct &#59;A和direct中的值按位’’异或’’,结果送入A中
XRL A,@Ri &#59;A和间址寻址单元@Ri中的值按位’’异或’’,结果送入A中
XRL A,#data &#59;A和立即数data按位’’异或’’,结果送入A中
XRL direct,A &#59;direct中值和A中的值按位’’异或’’,结果送入direct中
XRL direct,#data &#59;direct中的值和立即数data按位’’异或’’,结果送入direct中。
练习:
MOV A,#24H
MOV R0,#37H
ORL A,R0
XRL A,#29H
MOV 35H,#10H
ORL 35H,#29H
MOV R0,#35H
ANL A,@R0
四、控制转移类指令
1.无条件转移类指令
1.短转移类指令
AJMP addr11
2.长转移类指令
LJMP addr16
3.相对转移指令
SJMP rel
上面的三条指令,如果要仔细分析的话,区别较大,但初学时,可不理会这么多,统统理解成:JMP 标号,也就是跳转到一个标号处。事实上,LJMP 标号,在前面的例程中我们已接触过,并且也知道如何来使用了。而AJMP和SJMP也是一样。那么他们的区别何在呢?在于跳转的范围不一样。好比跳远,LJMP一下就能跳64K这么远(当然近了更没关系了)。而AJMP 最多只能跳2K距离,而SJMP则最多只能跳256这么远。原则上,所有用SJMP或AJMP的地方都可以用LJMP来替代。因此在初学时,需要跳转时可以全用LJMP,除了一个场合。什么场合呢?先了解一下AJMP,AJMP是一条双字节指令,也就说这条指令本身占用存储器(ROM)的两个单元。而LJMP则是三字节指令,即这条指令占用存储器(ROM)的三个单元。下面是第四条跳转指令。
4.间接转移指令
JMP @A+DPTR
这条指令的用途也是跳转,转到什么地方去呢?这可不能由标号简单地决定了。让我们从一个实际的例子入手吧。
MOV DPTR,#TAB &#59;将TAB所代表的地址送入DPTR
MOV A,R0 &#59;从R0中取数(详见下面说明)
MOV B,#2
MUL A,B &#59;A中的值乘2(详见下面的说明)
JMP A,@A+DPTR &#59;跳转
TAB: AJMP S1 &#59;跳转表格
AJMP S2
AJMP S3
.
.
.


图2


图3
  应用背景介绍:在单片机开发中,经常要用到键盘,见上面的9个按键的键盘。我们的要求是:当按下功能键A………..G时去完成不同的功能。这用程序设计的语言来表达的话,就是:按下不同的键去执行不同的程序段,以完成不同的功能。怎么样来实现呢?
  看图2,前面的程序读入的是按键的值,如按下’’A’’键后获得的键值是0,按下’’B’’键后获得的值是’’1’’等等,然后根据不同的值进行跳转,如键值为0就转到S1执行,为1就转到S2执行。。。。如何来实现这一功能呢?
  先从程序的下面看起,是若干个AJMP语句,这若干个AJMP语句最后在存储器中是这样存放的(见图3),也就是每个AJMP语句都占用了两个存储器的空间,并且是连续存放的。而AJMP S1存放的地址是TAB,到底TAB等于多少,我们不需要知道,把它留给汇编程序来算好了。
  下面我们来看这段程序的执行过程:第一句MOV DPTR,#TAB执行完了之后,DPTR中的值就是TAB,第二句是MOV A,R0,我们假设R0是由按键处理程序获得的键值,比如按下A键,R0中的值是0,按下B键,R0中的值是1,以此类推,现在我们假设按下的是B键,则执行完第二条指令后,A中的值就是1。并且按我们的分析,按下B后应当执行S2这段程序,让我们来看一看是否是这样呢?第三条、第四条指令是将A中的值乘2,即执行完第4条指令后A中的值是2。下面就执行JMP @A+DPTR了,现在DPTR中的值是TAB,而A+DPTR后就是TAB+2,因此,执行此句程序后,将会跳到TAB+2这个地址继续执行。看一看在TAB+2这个地址里面放的是什么?就是AJMP S2这条指令。因此,马上又执行AJMP S2指令,程序将跳到S2处往下执行,这与我们的要求相符合。
请大家自行分析按下键“A”、“C”、“D”……之后的情况。
  这样我们用JMP @A+DPTR就实现了按下一键跳到相应的程序段去执行的这样一个要求。再问大家一个问题,为什么取得键值后要乘2?如果例程下面的所有指令换成LJMP,即:
LJMP S1,LJMP S2……这段程序还能正确地执行吗?如果不能,应该怎么改?
单片机第十三课
条件转移指令:
条件转移指令是指在满足一定条件时进行相对转移。
1.判A内容是否为0转移指令
JZ rel
JNZ rel
第一指令的功能是:如果(A)=0,则转移,否则顺序执行(执行本指令的下一条指令)。转移到什么地方去呢?如果按照传统的方法,就要算偏移量,很麻烦,好在现在我们可以借助于机器汇编了。因此这第指令我们可以这样理解:JZ 标号。即转移到标号处。下面举一例说明:
MOV A,R0
JZ L1
MOV R1,#00H
AJMP L2
L1: MOV R1,#0FFH
L2: SJMP L2
END
在执行上面这段程序前如果R0中的值是0的话,就转移到L1执行,因此最终的执行结果是R1中的值为0FFH。而如果R0中的值不等于0,则顺序执行,也就是执行 MOV R1,#00H指令。最终的执行结果是R1中的值等于0。
第一条指令的功能清楚了,第二条当然就好理解了,如果A中的值不等于0,就转移。把上面的那个例子中的JZ改成JNZ试试吧,看看程序执行的结果是什么?
2.比较转移指令
CJNE A,#data,rel
CJNE A,direct,rel
CJNE Rn,#data,rel
CJNE @Ri,#data,rel
第一条指令的功能是将A中的值和立即数data比较,如果两者相等,就顺序执行(执行本指令的下一条指令),如果不相等,就转移,同样地,我们可以将rel理解成标号,即:CJNE A,#data,标号。这样利用这条指令,我们就可以判断两数是否相等,这在很多场合是非常有用的。但有时还想得知两数比较之后哪个大,哪个小,本条指令也具有这样的功能,如果两数不相等,则CPU还会反映出哪个数大,哪个数小,这是用CY(进位位)来实现的。如果前面的数(A中的)大,则CY=0,否则CY=1,因此在程序转移后再次利用CY就可判断出A中的数比data大还是小了。
例:
MOV A,R0
CJNE A,#10H,L1
MOV R1,#0FFH
AJMP L3
L1: JC L2
MOV R1,#0AAH
AJMP L3
L2: MOV R1,#0FFH
L3: SJMP L3
上面的程序中有一条指令我们还没学过,即JC,这条指令的原型是JC rel,作用和上面的JZ类似,但是它是判CY是0,还是1进行转移,如果CY=1,则转移到JC后面的标号处执行,如果CY=0则顺序执行(执行它的下面一条指令)。
分析一下上面的程序,如果(A)=10H,则顺序执行,即R1=0。如果(A)不等于10H,则转到L1处继续执行,在L1处,再次进行判断,如果(A)10H,则CY=1,将顺序执行,即执行MOV R1,#0AAH指令,而如果(A)10H,则将转移到L2处指行,即执行MOV R1,#0FFH指令。因此最终结果是:本程序执行前,如果(R0)=10H,则(R1)=00H,如果(R0)10H,则(R1)=0AAH,如果(R0)10H,则(R1)=0FFH。
弄懂了这条指令,其它的几条就类似了,第二条是把A当中的值和直接地址中的值比较,第三条则是将直接地址中的值和立即数比较,第四条是将间址寻址得到的数和立即数比较,这里就不详谈了,下面给出几个相应的例子。
CJNE A,10H &#59;把A中的值和10H中的值比较(注意和上题的区别)
CJNE 10H,#35H &#59;把10H中的值和35H中的值比较
CJNE @R0,#35H &#59;把R0中的值作为地址,从此地址中取数并和35H比较
3.循环转移指令
DJNZ Rn,rel
DJNZ direct,rel
第一条指令在前面的例子中有详细的分析,这里就不多谈了。第二条指令,只是将Rn改成直接地址,其它一样,也不多说了,给一个例子。
DJNZ 10H,LOOP
3.调用与返回指令
(1)主程序与子程序 在前面的灯的实验中,我们已用到过了子程序,只是我们并没有明确地介绍。子程序是干什么用的,为什么要用子程序技术呢?举个例子,我们数据老师布置了10道算术题,经过观察,每一道题中都包含一个(3*5+2)*3的运算,我们可以有两种选择,第一种,每做一道题,都把这个算式算一遍,第二种选择,我们可以先把这个结果算出来,也就是51,放在一边,然后要用到这个算式时就将51代进去。这两种方法哪种更好呢?不必多言。设计程序时也是这样,有时一个功能会在程序的不同地方反复使用,我们就可以把这个功能做成一段程序,每次需要用到这个功能时就“调用”一下。
(2)调用及回过程:主程序调用了子程序,子程序执行完之后必须再回到主程序继续执行,不能“一去不回头”,那么回到什么地方呢?是回到调用子程序的下面一条指令继续执行(当然啦,要是还回到这条指令,不又要再调用子程序了吗?那可就没完没了了……)。参考图1

图1
4.调用指令
LCALL addr16 &#59;长调用指令
ACALL addr11 &#59;短调用指令
上面两条指令都是在主程序中调用子程序,两者有一定的区别,但在初学时,可以不加以区分,而且可以用LCALL 标号,ACALL 标号,来理解,即调用子程序。
(5)返回指令 则说了,子程序执行完后必须回到主程序,如何返回呢?只要执行一条返回指令就可以了,即执行
ret
指令
4.空操作指令
nop
空操作,就是什么事也不干,停一个周期,一般用作短时间的延时。
 
单片机第十七课
位及位操作指令
通过前面那些流水灯的例子,我们已经习惯了“位”一位就是一盏灯的亮和灭,而我们学的指令却全都是用“字节”来介绍的:字节的移动、加法、减法、逻辑运算、移位等等。用字节来处理一些数学问题,比如说:控制冰箱的温度、电视的音量等等很直观,可以直接用数值来表在。可是如果用它来控制一些开关的打开和合上,灯的亮和灭,就有些不直接了,记得我们上次课上的流水灯的例子吗?我们知道送往P1口的数值后并不能马上知道哪个灯亮和来灭,而是要化成二进制才知道。工业中有很多场合需要处理这类开关输出,继电器吸合,用字节来处理就显示有些麻烦,所以在8031单片机中特意引入一个位处理机制。
1.位寻址区
在8031中,有一部份RAM和一部份SFR是具有位寻址功能的,也就是说这些RAM的每一个位都有自已的地址,可以直接用这个地址来对此进行操作。
字节地址位地址
2FH7FH      78H
2EH77H      70
2DH6FH      68H
2CH67H      60H
2BH5FH      58H
2AH57H      50H
29H4FH      48H
28H47H      40H
27H3FH      38H
26H37H      30H
25H2FH      28H
24H27H      20H
23H1FH      18H
22H17H      10H
21H0FH      08H
20H07H06H05H04H03H02H01H00H
图1
内部RAM的20H-2FH这16个字节,就是8031的位寻址区。看图1。可见这里面的每一个RAM中的每个位我们都可能直接用位地址来找到它们,而不必用字节地址,然后再用逻辑指令的方式。
2.可以位寻址的特殊功能寄存器
8031中有一些SFR是可以进行位寻址的,这些SFR的特点是其字节地址均可被8整除,如A累加器,B寄存器、PSW、IP(中断优先级控制寄存器)、IE(中断允许控制寄存器)、SCON(串行口控制寄存器)、TCON(定时器/计数器控制寄存器)、P0-P3(I/O端口锁存器)。以上的一些SFR我们还不熟,等我们讲解相关内容时再作详细解释。
3.位操作指令
MCS-51单片机的硬件结构中,有一个位处理器(又称布尔处理器),它有一套位变量处理的指令集。在进行位处理时,CY(就是我们前面讲的进位位)称“位累加器”。有自已的位RAM,也就是我们刚讲的内部RAM的20H-2FH这16个字节单元即128个位单元,还有自已的位I/O空间(即P0.0…..P0.7,P1.0…….P1.7,P2.0……..P2.7,P3.0……..P3.7)。当然在物理实体上它们与原来的以字节寻址用的RAM,及端口是完全相同的,或者说这些RAM及端口都可以有两种用法。
1.位传送指令
MOV C,BIT
MOV BIT,C
这组指令的功能是实现位累加器(CY)和其它位地址之间的数据传递。
例:MOV P1.0,CY &#59;将CY中的状态送到P1.0引脚上去(如果是做算术运算,我们就可以通过观察知道现在CY是多少啦)。
MOV P1.0,CY &#59;将P1.0的状态送给CY。
2.位修正指令
1.位清0指令
CLR C &#59;使CY=0
CLR bit &#59;使指令的位地址等于0。例:CLR P1.0 &#59;即使P1.0变为0
2.位置1指令
SETB C &#59;使CY=1
SETB bit &#59;使指定的位地址等于1。例:SETB P1.0 &#59;使P.0变为1
3.位取反指令
CPL C &#59;使CY等于原来的相反的值,由1变为0,由0变为1。
CPL bit &#59;使指定的位的值等于原来相反的值,由0变为1,由1变为0。
例:CPL P1.0
以我们做过的实验为例,如果原来灯是亮的,则执行本指令后灯灭,反之原来灯是灭的,执行本指令后灯亮。
1.位逻辑运算指令
1.位与指令
ANL C,bit &#59;CY与指定的位地址的值相与,结果送回CY
ANL C,/bit &#59;先将指定的位地址中的值取出后取反,再和CY相与,结果送回CY,但注意,指定的位地址中的值本身并不发生变化。
例:ANL C,/P1.0
设执行本指令前,CY=1,P1.0等于1(灯灭),则执行完本指令后CY=0,而P1.0也是等于1。
可用下列程序验证:
ORG 0000H
AJMP START
ORG 30H
START: MOV SP,#5FH
MOV P1,#0FFH
SETB C
ANL C,/P1.0
MOV P1.1,C &#59;将做完的结果送P1.1,结果应当是P1.1上的灯亮,而P1.0上的灯还是不亮。
2.位或指令
ORL C,bit
ORL C,/bit
这个的功能大家自行分析吧,然后对照上面的例程,编一个验证程序,看看你相得对吗?
1.位条件转移指令
1.判CY转移指令
JC rel
JNC rel
第一条指令的功能是如果CY等于1就转移,如果不等于1就顺序执行。那么转移到什么地方去呢?我们可以这样理解:JC 标号,如果等于1就转到标号处执行。这条指令我们在上节课中已讲到,不再重复。
第二条指令则和第一条指令相反,即如果CY=0就转移,不等于0就顺序执行,当然,我们也同样理解: JNC 标号
2.判位变量转移指令
JB bit,rel
JNB bit,rel
第一条指令是如果指定的bit位中的值是1,则转移,否则顺序执行。同样,我们可以这样理解这条指令:JB bit,标号
第二条指令请大家先自行分析
下面我们举个例子说明:
ORG 0000H
LJMP START
ORG 30H
START:MOV SP,#5FH
MOV P1,#0FFH
MOV P3,#0FFH
L1: JNB P3.2,L2 &#593.2上接有一只按键,它按下时,P3.2=0
JNB P3.3,L3 &#593.3上接有一只按键,它按下时,P3.3=0
LJM P L1
L2: MOV P1,#00H
LJMP L1
L3: MOV P1,#0FFH
LJMP L1
END
把上面的例子写入片子,看看有什么现象………
.
.
按下接在P3.2上的按键,P1口的灯全亮了,松开或再按,灯并不熄灭,然后按下接在P3.3上的按键,灯就全灭了。这像什么?这不就是工业现场经常用到的“启动”、“停止”的功能吗?
怎么做到的呢?一开始,将0FFH送入P3口,这样,P3的所有引线都处于高电平,然后执行L1,如果P3.2是高电平(键没有按下),则顺序执行JNB P3.3,L3语句,同样,如果P3.3是高电平(键没有按下),则顺序执行LJMP L1语句。这样就不停地检测P3.2、P3.3,如果有一次P3.2上的按键按下去了,则转移到L2,执行MOV P1,#00H,使灯全亮,然后又转去L1,再次循环,直到检测到P3.3为0,则转L3,执行MOV P1,#0FFH,例灯全灭,再转去L1,如此循环不已。
大家能否稍加改动,将本程序用JB指令改写
计数器与定时器
一、计数概念的引入
从选票的统计谈起:画“正”。这就是计数,生活中计数的例子处处可见。例:录音机上的计数器、家里面用的电度表、汽车上的里程表等等,再举一个工业生产中的例子,线缆行业在电线生产出来之后要计米,也就是测量长度,怎么测法呢?用尺量?不现实,太长不说,要一边做一边量呢,怎么办呢?行业中有很巧妙的方法,用一个周长是1米的轮子,将电缆绕在上面一周,由线带轮转,这样轮转一周不就是线长1米嘛,所以只要记下轮转了多少圈,就可以知道走过的线有多长了。
二、计数器的容量
从一个生活中的例子看起:一个水盆在水龙头下,水龙没关紧,水一滴滴地滴入盆中。水滴不断落下,盆的容量是有限的,过一段时间之后,水就会逐渐变满。录音机上的计数器最多只计到999….那么单片机中的计数器有多大的容量呢?8031单片机中有两个计数器,分别称之为T0和T1,这两个计数器分别是由两个8位的RAM单元组成的,即每个计数器都是16位的计数器,最大的计数量是65536。
三、定时
8031中的计数器除了可以作为计数之用外,还可以用作时钟,时钟的用途当然很大,如打铃器,电视机定时关机,空调定时开关等等,那么计数器是如何作为定时器来用的呢?
一个闹钟,我将它定时在1个小时后闹响,换言之,也可以说是秒针走了(3600)次,所以时间就转化为秒针走的次数的,也就是计数的次数了,可见,计数的次数和时间之间的确十分相关。那么它们的关系是什么呢?那就是秒针每一次走动的时间正好是1秒。

图1
结论:只要计数脉冲的间隔相等,则计数值就代表了时间的流逝。
由此,单片机中的定时器和计数器是一个东西,只不过计数器是记录的外界发生的事情,而定时器则是由单片机提供一个非常稳定的计数源。
那么提供组定时器的是计数源是什么呢?看图1,原来就是由单片机的晶振经过12分频后获得的一个脉冲源。晶振的频率当然很准,所以这个计数脉冲的时间间隔也很准。问题:一个12M的晶振,它提供给计数器的脉冲时间间隔是多少呢?当然这很容易,就是12M/12等于1M,也就是1个微秒。
结论:计数脉冲的间隔与晶振有关,12M的晶振,计数脉冲的间隔是1微秒。
四、溢出
让我们再来看水滴的例子,当水不断落下,盆中的水不断变满,最终有一滴水使得盆中的水满了。这时如果再有一滴水落下,就会发生什么现象?水会漫出来,用个术语来讲就是“溢出”。
水溢出是流到地上,而计数器溢出后将使得TF0变为“1”。至于TF0是什么我们稍后再谈。一旦TF0由0变成1,就是产生了变化,产生了变化就会引发事件,就象定时的时间一到,闹钟就会响一样。至于会引发什么事件,我们下次课再介绍,现在我们来研究另一个问题:要有多少个计数脉冲才会使TF0由0变为1。
五、任意定时及计数的方法
刚才已研究过,计数器的容量是16位,也就是最大的计数值到65536,因此计数计到65536就会产生溢出。这个没有问题,问题是我们现实生活中,经常会有少于65536个计数值的要求,如包装线上,一打为12瓶,一瓶药片为100粒,怎么样来满足这个要求呢?
……
提示:如果是一个空的盆要1万滴水滴进去才会满,我在开始滴水之前就先放入一勺水,还需要10000滴嘛?
对了,我们采用预置数的方法,我要计100,那我就先放进65436,再来100个脉冲,不就到了65536了吗。
定时也是如此,每个脉冲是1微秒,则计满65536个脉冲需时65.536毫秒,但现在我只要10毫秒就可以了,怎么办?
……
10个毫秒为10000个微秒,所以,只要在计数器里面放进55536就可以了。
定时/计数器的方式控制字
从上一节我们已经得知,单片机中的定时/计数器都可以有多种用途,那么我怎样才能让它们工作于我所需要的用途呢?这就要通过定时/计数器的方式控制字来设置。
在单片机中有两个特殊功能寄存器与定时/计数有关,这就是TMOD和TCON。顺便说一下,TMOD和TCON是名称,我们在写程序时就可以直接用这个名称来指定它们,当然也可以直接用它们的地址89H和88H来指定它们(其实用名称也就是直接用地址,汇编软件帮你翻译一下而已)。
从图1中我们可以看出,TMOD被分成两部份,每部份4位。分别用于控制T1和T0,至于这里面是什么意思,我们下面介绍。
从图2中我们可以看出,TCON也被分成两部份,高4位用于定时/计数器,低4位则用于中断(我们暂不管)。而TF1(0)我们上节课已提到了,当计数溢出后TF1(0)就由0变为1。原来TF1(0)在这儿!那么TR0、TR1又是什么呢?看上节课的图。
计数脉冲要进入计数器还真不容易,有层层关要通过,最起码,就是TR0(1)要为1,开关才能合上,脉冲才能过来。因此,TR0(1)称之为运行控制位,可用指令SETB来置位以启动计数器/定时器运行,用指令CLR来 关闭定时/计数器的工作,一切尽在自已的掌握中。
定时/计数器的四种工作方式
1.工作方式0
定时器/计数器的工作方式0称之为13位定时/计数方式。它由TL(1/0)的低5位和TH(0/1)的8位构成13位的计数器,此时TL(1/0)的高3位未用。
我们用这个图来讨论几个问题:
1.M1M0:定时/计数器一共有四种工作方式,就是用M1M0来控制的,2位正好是四种组合。
2.C/T:前面我们说过,定时/计数器即可作定时用也可用计数用,到底作什么用,由我们根据需要自行决定,也说是决定权在我们��编程者。如果C/T为0就是用作定时器(开关往上打),如果C/T为1就是用作计数器(开关往下打)。顺便提一下:一个定时/计数器同一时刻要么作定时用,要么作计数用,不能同时用的,这是个极普通的常识,几乎没有教材会提这一点,但很多初学者却会有此困惑。
3.GATE:看图,当我们选择了定时或计数工作方式后,定时/计数脉冲却不一定能到达计数器端,中间还有一个开关,显然这个开关不合上,计数脉冲就没法过去,那么开关什么时候过去呢?有两种情况
1.GATE=0,分析一下逻辑,GATE非后是1,进入或门,或门总是输出1,和或门的另一个输入端INT1无关,在这种情况下,开关的打开、合上只取决于TR1,只要TR1是1,开关就合上,计数脉冲得以畅通无阻,而如果TR1等于0则开关打开,计数脉冲无法通过,因此定时/计数是否工作,只取决于TR1。
2.GATE=1,在此种情况下,计数脉冲通路上的开关不仅要由TR1来控制,而且还要受到INT1引脚的控制,只有TR1为1,且INT1引脚也是高电平,开关才合上,计数脉冲才得以通过。这个特性可以用来测量一个信号的高电平的宽度,想想看,怎么测?
为什 么在这种模式下只用13位呢?干吗不用16位,这是为了和51机的前辈48系列兼容而设的一种工作式,如果你觉得用得不顺手,那就干脆用第二种工作方式。
1.工作方式1
工作方式1是16位的定时/计数方式,将M1M0设为01即可,其它特性与工作方式0相同。
2.工作方式2
在介绍这种式方式之前先让我们思考一个问题:上一次课我们提到过任意计数及任意定时的问题,比如我要计1000个数,可是16位的计数器要计到65536才满,怎么办呢?我们讨论后得出的办法是用预置数,先在计数器里放上64536,再来1000个脉冲,不就行了吗?是的,但是计满了之后我们又该怎么办呢?要知道,计数总是不断重复的,流水线上计满后马上又要开始下一次计数,下一次的计数还是1000吗?当计满并溢出后,计数器里面的值变成了0(为什么,可以参考前面课程的说明),因此下一次将要计满65536后才会溢出,这可不符合要求,怎么办?当然办法很简单,就是每次一溢出时执行一段程序(这通常是需要的,要不然要溢出干吗?)可以在这段程序中做把预置数64536送入计数器中的事情。所以采用工作方式0或1都要在溢出后做一个重置预置数的工作,做工作当然就得要时间,一般来说这点时间不算什么,可是有一些场合我们还是要计较的,所以就有了第三种工作方式��自动再装入预置数的工作方式。
既然要自动得新装入预置数,那么预置数就得放在一个地方,要不然装什么呢?那么预置数放在什么地方呢?它放在T(0/1)的高8位,那么这样高8位不就不能参与计数了吗?是的,在工作方式2,只有低8位参与计数,而高8位不参与计数,用作预置数的存放,这样计数范围就小多了,当然做任可事总有代价的,关键是看值不值,如果我根本不需要计那么多数,那么就可以用这种方式。看图4,每当计数溢出,就会打开T(0/1)的高、低8位之间的开关,计预置数进入低8位。这是由硬件自动完成的,不需要由人工干预。
通常这种式作方式用于波特率发生器(我们将在串行接口中讲解),用于这种用途时,定时器就是为了提供一个时间基准。计数溢出后不需要做事情,要做的仅仅只有一件,就是重新装入预置数,再开始计数,而且中间不要任何延迟,可见这个任务用工作方式2来完成是最妙不过了。
3.工作方式3
这种式作方式之下,定时/计数器0被拆成2个独立的定时/计数器来用。其中,TL0可以构成8位的定时器或计数器的工作方式,而TH0则只能作为定时器来用。我们知道作定时、计数器来用,需要控制,计满后溢出需要有溢出标记,T0被分成两个来用,那就要两套控制及、溢出标记了,从何而来呢?TL0还是用原来的T0的标记,而TH0则借用T1的标记。如此T1不是无标记、控制可用了吗?是的。
一般情况处,只有在T1以工作方式2运行(当波特率发生器用)时,才让T0工作于方式3的。
定时器/计数器的定时/计数范围
工作方式0:13位定时/计数方式,因此,最多可以计到2的13次方,也就是8192次。
工作方式1:16位定时/计数方式,因此,最多可以计到2的16次方,也就是65536次。
工作方式2和工作方式3,都是8位的定时/计数方式,因此,最多可以计到2的8次方,也说是256次。
预置值计算:用最大计数量减去需要的计数次数即可。
例:流水线上一个包装是12盒,要求每到12盒就产生一个动作,用单片机的工作方式0来控制,应当预置多大的值呢?对了,就是8192-12=8180。
以上是计数,明白了这个道理,定时也是一样。这在前面的课程已提到,我们不再重复,请参考前面的例子。
 
单片机第二十课:中断系统
1.有关中断的概念
什么是中断,我们从一个生活中的例子引入。你正在家中看书,突然电话铃响了,你放下书本,去接电话,和来电话的人交谈,然后放下电话,回来继续看你的书。这就是生活中的“中断”的现象,就是正常的工作过程被外部的事件打断了。
仔细研究一下生活中的中断,对于我们学习单片机的中断也很有好处。第一、什么可经引起中断,生活中很多事件可以引起中断:有人按了门铃了,电话铃响了,你的闹钟闹响了,你烧的水开了….等等诸如此类的事件,我们把可以引起中断的称之为中断源,单片机中也有一些可以引起中断的事件,8031中一共有5个:两个外部中断,两个计数/定时器中断,一个串行口中断。
第二、中断的嵌套与优先级处理:设想一下,我们正在看书,电话铃响了,同时又有人按了门铃,你该先做那样呢?如果你正是在等一个很重要的电话,你一般不会去理会门铃的,而反之,你正在等一个重要的客人,则可能就不会去理会电话了。如果不是这两者(即不等电话,也不是等人上门),你可能会按你通常的习惯去处理。总之这里存在一个优先级的问题,单片机中也是如此,也有优先级的问题。优先级的问题不仅仅发生在两个中断同时产生的情况,也发生在一个中断已产生,又有一个中断产生的情况,比如你正接电话,有人按门铃的情况,或你正开门与人交谈,又有电话响了情况。考虑一下我们会怎么办吧。
第三、中断的响应过程:当有事件产生,进入中断之前我们必须先记住现在看书的第几页了,或拿一个书签放在当前页的位置,然后去处理不同的事情(因为处理完了,我们还要回来继续看书):电话铃响我们要到放电话的地方去,门铃响我们要到门那边去,也说是不同的中断,我们要在不同的地点处理,而这个地点通常还是固定的。计算机中也是采用的这种方法,五个中断源,每个中断产生后都到一个固定的地方去找处理这个中断的程序,当然在去之前首先要保存下面将执行的指令的地址,以便处理完中断后回到原来的地方继续往下执行程序。具体地说,中断响应可以分为以下几个步骤:1、保护断点,即保存下一将要执行的指令的地址,就是把这个地址送入堆栈。2、寻找中断入口,根据5个不同的中断源所产生的中断,查找5个不同的入口地址。以上工作是由计算机自动完成的,与编程者无关。在这5个入口地址处存放有中断处理程序(这是程序编写时放在那儿的,如果没把中断程序放在那儿,就错了,中断程序就不能被执行到)。3、执行中断处理程序。4、中断返回:执行完中断指令后,就从中断处返回到主程序,继续执行。
究竟单片机是怎么样找到中断程序所在位置,又怎么返回的呢?我们稍后再谈。
2.MCS-51中断系统的结构:
如图(抱歉,本图请找本51书看一下)所示,由与中断有关的特殊功能寄存器、中断入口、顺序查询逻辑电路等组成,包括5个中断请求源,4个用于中断控制的寄存器IE、IP、ECON和SCON来控制中断 类弄、中断的开、关和各种中断源的优先级确定。
1.中断请求源:
(1)外部中断请求源:即外中断0和1,经由外部引脚引入的,在单片机上有两个引脚,名称为INT0、INT1,也就是P3.2、P3.3这两个引脚。在内部的TCON中有四位是与外中断有关的。
IT0:INT0触发方式控制位,可由软件进和置位和复位,IT0=0,INT0为低电平触发方式,IT0=1,INT0为负跳变触发方式。这两种方式的差异将在以后再谈。
IE0:INT0中断请求标志位。当有外部的中断请求时,这位就会置1(这由硬件来完成),在CPU响应中断后,由硬件将IE0清0。
IT1、IE1的用途和IT0、IE0相同。
(2)内部中断请求源
TF0:定时器T0的溢出中断标记,当T0计数产生溢出时,由硬件置位TF0。当CPU响应中断后,再由硬件将TF0清0。
TF1:与TF0类似。
TI、RI:串行口发送、接收中断,在串口中再讲解。
2、中断允许寄存器IE
在MCS-51中断系统中,中断的允许或禁止是由片内可进行位寻址的8位中断允许寄存器IE来控制的。见下表
EAXXESET1EX1ET0EX0
其中EA是总开关,如果它等于0,则所有中断都不允许。
ES-串行口中断允许
ET1-定时器1中断允许
EX1-外中断1中断允许。
ET0-定时器0中断允许
EX0-外中断0中断允许。
如果我们要设置允许外中断1,定时器1中断允许,其它不允许,则IE可以是
EAXXESET1EX1ET0EX0
10001100
即8CH,当然,我们也可以用位操作指令
SETB EA
SETB ET1
SETB EX1
来实现它。
3、五个中断源的自然优先级与中断服务入口地址
外中断0:0003H
定时器0:000BH
外中断1:0013H
定时器1:001BH
串口 :0023H
它们的自然优先级由高到低排列。
写到这里,大家应当明白,为什么前面有一些程序一始我们这样写:
ORG 0000H
LJMP START
ORG 0030H
START:
这样写的目的,就是为了让出中断源所占用的向量地址。当然,在程序中没用中断时,直接从0000H开始写程序,在原理上并没有错,但在实际工作中最好不这样做。
优先级:单片机采用了自然优先级和人工设置高、低优先级的策略,即可以由程序员设定那些中断是高优先级、哪些中断是低优先级,由于只有两级,必有一些中断处于同一级别,处于同一级别的,就由自然优先级确定。
开机时,每个中断都处于低优先级,我们可以用指令对优先级进行设置。看表2
中断优先级中由中断优先级寄存器IP来高置的,IP中某位设为1,相应的中断就是高优先级,否则就是低优先级。
XXXPSPT1PX1PT0PX0
例:设有如下要求,将T0、外中断1设为高优先级,其它为低优先级,求IP的值。
XXXPSPT1PX1PT0PX0
00000110
IP的首3位没用,可任意取值,设为000,后面根据要求写就可以了
因此,最终,IP的值就是06H。
例:在上例中,如果5个中断请求同时发生,求中断响应的次序。
响应次序为:定时器0->外中断1->外中断0->实时器1->串行中断。
1.MCS-51的中断响应过程:
1、中断响应的条件:讲到这儿,我们依然对于计算机响应中断感到神奇,我们人可以响应外界的事件,是因为我们有多种“传感器“――眼、耳可以接受不同的信息,计算机是如何做到这点的呢?其实说穿了,一点都不希奇,MCS51工作时,在每个机器周期中都会去查询一下各个中断标记,看他们是否是“1“,如果是1,就说明有中断请求了,所以所谓中断,其实也是查询,不过是每个周期都查一下而已。这要换成人来说,就相当于你在看书的时候,每一秒钟都会抬起头来看一看,查问一下,是不是有人按门铃,是否有电话,很蠢,不是吗?可计算机本来就是这样,它根本没人聪明。
了解了上述中断的过程,就不难解中断响应的条件了。在下列三种情况之一时,CPU将封锁对中断的响应:
1.CPU正在处理一个同级或更高级别的中断请求。
2.现行的机器周期不是当前正执行指令的最后一个周期。我们知道,单片机有单周期、双周期、三周期指令,当前执行指令是单字节没有关系,如果是双字节或四字节的,就要等整条指令都执行完了,才能响应中断(因为中断查询是在每个机器周期都可能查到的)。
3.当前正执行的指令是返回批令(RETI)或访问IP、IE寄存器的指令,则CPU至少再执行一条指令才应中断。这些都是与中断有关的,如果正访问IP、IE则可能会开、关中断或改变中断的优先级,而中断返回指令则说明本次中断还没有处理完,所以都要等本指令处理结束,再执行一条指令才可以响应中断。
2、中断响应过程
CPU响应中断时,首先把当前指令的下一条指令(就是中断返回后将要执行的指令)的地址送入堆栈,然后根据中断标记,将相应的中断入口地址送入PC,PC是程序指针,CPU取指令就根据PC中的值,PC中是什么值,就会到什么地方去取指令,所以程序就会转到中断入口处继续执行。这些工作都是由硬件来完成的,不必我们去考虑。这里还有个问题,大家是否注意到,每个中断向量地址只间隔了8个单元,如0003-000B,在如此少的空间中如何完成中断程序呢?很简单,你在中断处安排一个LJMP指令,不就可以把中断程序跳转到任何地方了吗?
一个完整的主程序看起来应该是这样的:
ORG 0000H
LJMP START
ORG 0003H
LJMP INT0 ;转外中断0
ORG 000BH
RETI ;没有用定时器0中断,在此放一条RETI,万一 “不小心“产生了中断,也不会有太大的后果。
中断程序完成后,一定要执行一条RETI指令,执行这条指令后,CPU将会把堆栈中保存着的地址取出,送回PC,那么程序就会从主程序的中断处继续往下执行了。注意:CPU所做的保护工作是很有限的,只保护了一个地址,而其它的所有东西都不保护,所以如果你在主程序中用到了如A、PSW等,在中断程序中又要用它们,还要保证回到主程序后这里面的数据还是没执行中断以前的数据,就得自己保护起来
定时、中断练习一
1、利用定时器实现灯的闪烁
在学单片机时我们第一个例子就是灯的闪烁,那是用延时程序做的,现在回想起来,这样做不很恰当,为什么呢?我们的主程序做了灯的闪烁,就不能再干其它的事了,难道单片机只能这样工作吗?当然不是,我们可以用定时器来实现灯的闪烁的功能。
例1:查询方式
ORG 0000H
AJMP START
ORG 30H
START:
MOV P1,#0FFH &#59;关所 灯
MOV TMOD,#00000001B &#59;定时/计数器0工作于方式1
MOV TH0,#15H
MOV TL0,#0A0H &#59;即数5536
SETB TR0 &#59;定时/计数器0开始运行
LOOP:JBC TF0,NEXT &#59;如果TF0等于1,则清TF0并转NEXT处
AJMP LOOP &#59;否则跳转到LOOP处运行
NEXT:CPL P1.0
MOV TH0,#15H
MOV TL0,#9FH&#59;重置定时/计数器的初值
AJMP LOOP
END AJMP LOOP
END
 
键入程序,看到了什么?灯在闪烁了,这可是用定时器做的,不再是主程序的循环了。简单地分析一下程序,为什么用JBC呢?TF0是定时/计数器0的溢出标记位,当定时器产生溢出后,该位由0变1,所以查询该位就可知宇时时间是否已到。该位为1后,要用软件将标记位清0,以便下一次定时是间到时该位由0变1,所以用了JBC指令,该指位在判1转移的同时,还将该位清0。
以上程序是可以实现灯的闪烁了,可是主程序除了让灯闪烁外,还是不能做其他的事啊!不,不对,我们可以在LOOP:……和AJMP LOOP指令之间插入一些指令来做其他的事情,只要保证执行这些指令的时间少于定时时间就行了。那我们在用软件延时程序的时候不是也可以用一些指令来替代DJNZ吗?是的,但是那就要求你精确计算所用指令的时间,然后再减去相应的DJNZ循环次数,很不方便,而现在只要求所用指令的时间少于定时时间就行,显然要求低了。当然,这样的方法还是不好,所以我们常用以下的方法来实现。
程序2:用中断实现
ORG 0000H
AJMP START
ORG 000BH &#59;定时器0的中断向量地址
AJMP TIME0 &#59;跳转到真正的定时器程序处
ORG 30H
START:
MOV P1,#0FFH &#59;关所 灯
MOV TMOD,#00000001B &#59;定时/计数器0工作于方式1
MOV TH0,#15H
MOV TL0,#0A0H &#59;即数5536
SETB EA &#59;开总中断允许
SETB ET0 &#59;开定时/计数器0允许
SETB TR0 &#59;定时/计数器0开始运行
LOOP: AJMP LOOP &#59;真正工作时,这里可写任意程序
TIME0: &#59;定时器0的中断处理程序
PUSH ACC
PUSH PSW &#59;将PSW和ACC推入堆栈保护
CPL P1.0
MOV TH0,#15H
MOV TL0,#0A0H &#59;重置定时常数
POP PSW
POP ACC
RETI
END
 
上面的例子中,定时时间一到,TF0由0变1,就会引发中断,CPU将自动转至000B处寻找程序并执行,由于留给定时器中断的空间只有8个字节,显然不足以写下所有有中断处理程序,所以在000B处安排一条跳转指令,转到实际处理中断的程序处,这样,中断程序可以写在任意地方,也可以写任意长度了。进入定时中断后,首先要保存当前的一些状态,程序中只演示了保存存ACC和PSW,实际工作中应该根据需要将可能会改变的单元的值都推入堆栈进行保护(本程序中实际不需保存护任何值,这里只作个演示)。
上面的两个程序运行后,我们发现灯的闪烁非常快,根本分辨不出来,只是视觉上感到灯有些晃动而已,为什么呢?我们可以计算一下,定时器中预置的数是5536,所以每计60000个脉冲就是定时时间到,这60000个脉冲的时间是多少呢?我们的晶振是12M,所以就是60000微秒,即60毫秒,因此速度是非常快的。如果我想实现一个1S的定时,该怎么办呢?在该晶振濒率下,最长的定时也就是65。536个毫秒啊!上面给出一个例子。
ORG 0000H
AJMP START
ORG 000BH &#59;定时器0的中断向量地址
AJMP TIME0 &#59;跳转到真正的定时器程序处
ORG 30H
START:
MOV P1,#0FFH &#59;关所 灯
MOV 30H,#00H &#59;软件计数器预清0
MOV TMOD,#00000001B &#59;定时/计数器0工作于方式1
MOV TH0,#3CH
MOV TL0,#0B0H &#59;即数15536
SETB EA &#59;开总中断允许
SETB ET0 &#59;开定时/计数器0允许
SETB TR0 &#59;定时/计数器0开始运行
LOOP: AJMP LOOP &#59;真正工作时,这里可写任意程序
TIME0: &#59;定时器0的中断处理程序
PUSH ACC
PUSH PSW &#59;将PSW和ACC推入堆栈保护
INC 30H
MOV A,30H
CJNE A,#20,T_RET &#59;30H单元中的值到了20了吗?
T_L1: CPL P1.0 &#59;到了,取反P10
MOV 30H,#0 &#59;清软件计数器
T_RET:
MOV TH0,#15H
MOV TL0,#9FH &#59;重置定时常数
POP PSW
POP ACC
RETI
END
先自己分析一下,看看是怎么实现的?这里采用了软件计数器的概念,思路是这样的,先用定时/计数器0做一个50毫秒的定时器,定时是间到了以后并不是立即取反P10,而是将软件计数器中的值加1,如果软件计数器计到了20,就取反P10,并清掉软件计数器中的值,否则直接返回,这样,就变成了20次定时中断才取反一次P10,因此定时时间就延长了成了20*50即1000毫秒了。
这个思路在工程中是非常有用的,有的时候我们需要若干个定时器,可51中总共才有2个,怎么办呢?其实,只要这几个定时的时间有一定的公约数,我们就可以用软件定时器加以实现,如我要实现P10口所接灯按1S每次,而P11口所接灯按2S每次闪烁,怎么实现呢?对了我们用两个计数器,一个在它计到20时,取反P10,并清零,就如上面所示,另一个计到40取反P11,然后清0,不就行了吗?这部份的程序如下
ORG 0000H
AJMP START
ORG 000BH &#59;定时器0的中断向量地址
AJMP TIME0 &#59;跳转到真正的定时器程序处
ORG 30H
START:
MOV P1,#0FFH &#59;关所 灯
MOV 30H,#00H &#59;软件计数器预清0
MOV TMOD,#00000001B &#59;定时/计数器0工作于方式1
MOV TH0,#3CH
MOV TL0,#0B0H &#59;即数15536
SETB EA &#59;开总中断允许
SETB ET0 &#59;开定时/计数器0允许
SETB TR0 &#59;定时/计数器0开始运行
LOOP: AJMP LOOP &#59;真正工作时,这里可写任意程序
TIME0: &#59;定时器0的中断处理程序
PUSH ACC
PUSH PSW &#59;将PSW和ACC推入堆栈保护
INC 30H
INC 31H &#59;两个计数器都加1
MOV A,30H
CJNE A,#20,T_NEXT &#59;30H单元中的值到了20了吗?
T_L1: CPL P1.0 &#59;到了,取反P10
MOV 30H,#0 &#59;清软件计数器
T_NEXT:
MOV A,31H
CJNE A,#40,T_RET &#59;31h单元中的值到40了吗?
T_L2:
CPL P1.1
MOV 31H,#0 &#59;到了,取反P11,清计数器,返回
T_RET:
MOV TH0,#15H
MOV TL0,#9FH &#59;重置定时常数
POP PSW
POP ACC
RETI
END
程序一下载 代码下载 程序二下载 代码下载 程序三下载 代码下载 程序四下载 代码下载
您能用定时器的方法实现前面讲的流水灯吗?试试看。
定时/计数器实验2
前面我们做了定时器的实验,现在来看一看计数实验,在工作中计数通常会有两种要求:第一、将计数的值显示出来,第二、计数值到一定程度即中断报警。第一种如各种计数器、里程表,第二种如前面例中讲到的生产线上的计数。先看第一种吧。我们的硬件中是这样连线的:324构成的振荡器连到定时/计数器1的外部引脚T1上面,我们就利用这个来做一个计数实验,要将计数的值显示出来,当然最好用数码管了,可我们还没讲到这一部份,为了避免把问题复杂化,我们用P1口的8个LED来显示计到的数据。
程序如下:
ORG 0000H
AJMP START
ORG 30H
START:
MOV SP,#5FH
MOV TMOD,#01000000B &#59;定时/计数器1作计数用,0不用全置0
SETB TR1 &#59;启动计数器1开始运行.
LOOP: MOV A,TL0
MOV P1,A
AJMP LOOP
END
在硬件上用线将324的输出与T1连通(印板上有焊盘)运行这种程序,注意将板按正确的位置放置(LM324放在左手边,LED排列是按从高位到低们排列)看到什么?随着324后接的LED的闪烁,单片机的8只LED也在不断变化,注意观察,是不是按二进制:
00000000
00000001
00000010
00000011



这样的顺序在变呢?这就对了,这就是TL0中的数据。
程序二:
ORG 0000H
AJMP START
ORG 001BH
AJMP TIMER1 &#59;定时器1的中断处理
ORG 30H
START: MOV SP,#5FH
MOV TMOD,#01010000B &#59;定时/计数器1作计数用,模式1,0不用全置0
MOV TH1,#0FFH
MOV TL1,#0FAH &#59;预置值,要求每计到6个脉冲即为一个事件
SETB EA
SETB ET1 &#59;开总中断和定时器1中断允许
SETB TR1 &#59;启动计数器1开始运行.
AJMP $
TIMER1:
PUSH ACC
PUSH PSW
CPL P1.0 &#59;计数值到,即取反P1.0
MOV TH1,#0FFH
MOV TL1,#0FAH &#59;重置计数初值
POP PSW
POP ACC
RETI
END
上面这个程序完成的工作很简单,就是在每6个脉冲到来后取反一次P1。0,因此实验的结果应当是:LM324后接的LED亮、灭6次,则P1。0口所接LED亮或灭一次。这实际就是我们上面讲的计数器的第二种应用。
程序三:外部中断实验
ORG 0000H
AJMP START
ORG 0003H &#59;外部中断地直入口
AJMP INT0
ORG 30H
START: MOV SP,#5FH
MOV P1,#0FFH &#59;灯全灭
MOV P3,#0FFH &#593口置高电平
SETB EA
SETB EX0
AJMP $
INT0:
PUSH ACC
PUSH PSW
CPL P1.0
POP PSW
POP ACC
RETI
END
本程序的功能很简单,按一次按键1(接在12引脚上的)就引发一次中断0,取反一次P1。0,因此理论上按一下灯亮,按一下灯灭,但在实际做实验时,可能会发觉有时不“灵”,按了它没反应,但在大部份时候是对的,这是怎么回事呢?我们在讲解键盘时再作解释,这个程序本身是没有问题的。
程序1下载 程序1代码 程序2下载 程序2代码 程序3下载 程序3代码
串行接口
1.概述
1.串行接口的一般概念 单片机与外界进行信息交换称之为通讯。
8051单片机的通讯方式有两种:
并行通讯:数据的各位同时发送或接收。
串行通讯:数据一位一位顺序发送或接收。参看下图:

串行通讯的方式:
1.异步通讯:它用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下:
在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(可以省略),最后是停止位1。用这种格式表示字符,则字符可以一个接一个地传送。
在异步通讯中,CPU与外设之间必须有两项规定,即字符格式和波特率。字符格式的规定是双方能够在对同一种0和1的串理解成同一种意义。原则上字符格式可以由通讯的双方自由制定,但从通用、方便的角度出发,一般还是使用一些标准为好,如采用ASCII标准。
波特率即数据传送的速率,其定义是每秒钟传送的二进制数的位数。例如,数据传送的速率是120字符/s,而每个字符如上述规定包含10数位,则传送波特率为1200波特。
2.同步通讯:在同步通讯中,每个字符要用起始位和停止位作为字符开始和结束的标志,占用了时间;所以在数据块传递时,为了提高速度,常去掉这些标志,采用同步传送。由于数据块传递开始要用同步字符来指示,同时要求由时钟来实现发送端与接收端之间的同步,故硬件较复杂。
3.通讯方向:在串行通讯中,把通讯接口只能发送或接收的单向传送方法叫单工传送;而把数据在甲乙两机之间的双向传递,称之为双工传送。在双工传送方式中又分为半双工传送和全双工传送。半双工传送是两机之间不能同时进行发送和接收,任一时该,只能发或者只能收信息。
2.8051单片机的串行接口结构
8051串行接口是一个可编程的全双工串行通讯接口。它可用作异步通讯方式(UART),与串行传送信息的外部设备相连接,或用于通过标准异步通讯协议进行全双工的8051多机系统也可以通过同步方式,使用TTL或CMOS移位寄存器来扩充I/O口。
8051单片机通过引脚RXD(P3.0,串行数据接收端)和引脚TXD(P3.1,串行数据发送端)与外界通讯。SBUF是串行口缓冲寄存器,包括发送寄存器和接收寄存器。它们有相同名字和地址空间,但不会出现冲突,因为它们两个一个只能被CPU读出数据,一个只能被CPU写入数据。
1.串行口的控制与状态寄存器
1.串行口控制寄存器SCON
它用于定义串行口的工作方式及实施接收和发送控制。字节地址为98H,其各位定义如下表:
D7 D6 D5 D4 D3 D2 D1 D0
SM0 SM1 SM2 REN TB8 RB8 TI RI
SM0、SM1:串行口工作方式选择位,其定义如下:
SM0、SM1 工作方式 功能描述 波特率
0 0 方式0 8位移位寄存器 Fosc/12
0 1 方式1 10位UART 可变
1 0 方式2 11位UART Fosc/64或fosc/32
1 1 方式3 11位UART 可变
其中fosc为晶振频率
SM2:多机通讯控制位。在方式0时,SM2一定要等于0。在方式1中,当(SM2)=1则只有接收到有效停止位时,RI才置1。在方式2或方式3当(SM2)=1且接收到的第九位数据RB8=0时,RI才置1。
REN:接收允许控制位。由软件置位以允许接收,又由软件清0来禁止接收。
TB8: 是要发送数据的第9位。在方式2或方式3中,要发送的第9位数据,根据需要由软件置1或清0。例如,可约定作为奇偶校验位,或在多机通讯中作为区别地址帧或数据帧的标志位。
RB8:接收到的数据的第9位。在方式0中不使用RB8。在方式1中,若(SM2)=0,RB8为接收到的停止位。在方式2或方式3中,RB8为接收到的第9位数据。
TI: 发送中断标志。在方式0中,第8位发送结束时,由硬件置位。在其它方式的发送停止位前,由硬件置位。TI置位既表示一帧信息发送结束,同时也是申请中断,可根据需要,用软件查询的方法获得数据已发送完毕的信息,或用中断的方式来发送下一个数据。TI必须用软件清0。
RI: 接收中断标志位。在方式0,当接收完第8位数据后,由硬件置位。在其它方式中,在接收到停止位的中间时刻由硬件置位(例外情况见于SM2的说明)。RI置位表示一帧数据接收完毕,可用查询的方法获知或者用中断的方法获知。RI也必须用软件清0。
2.特殊功能寄存器PCON
PCON是为了在CHMOS的80C51单片机上实现电源控制而附加的。其中最高位是SMOD。
1.串行口的工作方式
8051单片机的全双工串行口可编程为4种工作方式,现分述如下:
1.方式0为移位寄存器输入/输出方式。可外接移位寄存器以扩展I/O口,也可以外接同步输入/输出设备。8位串行数据者是从RXD输入或输出,TXD用来输出同步脉冲。
1.输出 串行数据从RXD引脚输出,TXD引脚输出移位脉冲。CPU将数据写入发送寄存器时,立即启动发送,将8位数据以fos/12的固定波特率从RXD输出,低位在前,高位在后。发送完一帧数据后,发送中断标志TI由硬件置位。
2.输入 当串行口以方式0接收时,先置位允许接收控制位REN。此时,RXD为串行数据输入端,TXD仍为同步脉冲移位输出端。当(RI)=0和(REN)=1同时满足时,开始接收。当接收到第8位数据时,将数据移入接收寄存器,并由硬件置位RI。
下面两图分别是方式0扩展输出和输入的接线图。

1.方式1为波特率可变的10位异步通讯接口方式。发送或接收一帧信息,包括1个起始位0,8个数据位和1个停止位1。
1.输出 当CPU执行一条指令将数据写入发送缓冲SBUF时,就启动发送。串行数据从TXD引脚输出,发送完一帧数据后,就由硬件置位TI。
2.输入 在(REN)=1时,串行口采样RXD引脚,当采样到1至0的跳变时,确认是开始位0,就开始接收一帧数据。只有当(RI)=0且停止位为1或者(SM2)=0时,停止位才进入RB8,8位数据才能进入接收寄存器,并由硬件置位中断标志RI;否则信息丢失。所以在方式1接收时,应先用软件清零RI和SM2标志。
1.方式2
方式月为固定波特率的11位UART方式。它比方式1增加了一位可程控为1或0的第9位数据。
1.输出: 发送的串行数据由TXD端输出一帧信息为11位,附加的第9位来自SCON寄存器的TB8位,用软件置位或复位。它可作为多机通讯中地址/数据信息的标志位,也可以作为数据的奇偶校验位。当CPU执行一条数据写入SUBF的指令时,就启动发送器发送。发送一帧信息后,置位中断标志TI。
2.输入: 在(REN)=1时,串行口采样RXD引脚,当采样到1至0的跳变时,确认是开始位0,就开始接收一帧数据。在接收到附加的第9位数据后,当(RI)=0或者(SM2)=0时,第9位数据才进入RB8,8位数据才能进入接收寄存器,并由硬件置位中断标志RI;否则信息丢失。且不置位RI。再过一位时间后,不管上述条件时否满足,接收电路即行复位,并重新检测RXD上从1到0的跳变。
1.工作方式3
方式3为波特率可变的11位UART方式。除波特率外,其余与方式2相同。
1.波特率选择
如前所述,在串行通讯中,收发双方的数据传送率(波特率)要有一定的约定。在8051串行口的四种工作方式中,方式0和2的波特率是固定的,而方式1和3的波特率是可变的,由定时器T1的溢出率控制。
1.方式0
方式0的波特率固定为主振频率的1/12。
2.方式2
方式2的波特率由PCON中的选择位SMOD来决定,可由下式表示:
波特率=2的SMOD次方除以64再乘一个fosc,也就是当SMOD=1时,波特率为1/32fosc,当SMOD=0时,波特率为1/64fosc
3.方式1和方式3
定时器T1作为波特率发生器,其公式如下:
波特率= 定时器T1溢出率
T1溢出率= T1计数率/产生溢出所需的周期数
式中T1计数率取决于它工作在定时器状态还是计数器状态。当工作于定时器状态时,T1计数率为fosc/12&#59;当工作于计数器状态时,T1计数率为外部输入频率,此频率应小于fosc/24。产生溢出所需周期与定时器T1的工作方式、T1的预置值有关。
定时器T1工作于方式0:溢出所需周期数=8192-x
定时器T1工作于方式1:溢出所需周期数=65536-x
定时器T1工作于方式2:溢出所需周期数=256-x
因为方式2为自动重装入初值的8位定时器/计数器模式,所以用它来做波特率发生器最恰当。
当时钟频率选用11.0592MHZ时,取易获得标准的波特率,所以很多单片机系统选用这个看起来“怪”的晶振就是这个道理。
下表列出了定时器T1工作于方式2常用波特率及初值。
常用波特率Fosc(MHZ)SMODTH1初值
1920011.05921FDH
960011.05920FDH
480011.05920FAH
240011.05920F4h
120011.05920E8h

串行口应用编程实例
1. 串口方式0应用编程 8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就可以扩展一个并行口。

例:用8051串行口外接CD4094扩展8位并行输出口,如图所示,8位并行口的各位都接一个发光二极管,要求发光管呈流水灯状态。 串行口方式0的数据传送可采用中断方式,也可采用查询方式,无论哪种方式,都要借助于TI或RI标志。串行发送时,可以靠TI置位(发完一帧数据后)引起中断申请,在中断服务程序中发送下一帧数据,或者通过查询TI的状态,只要TI为0就继续查询,TI为1就结束查询,发送下一帧数据。在串行接收时,则由RI引起中断或对RI查询来确定何时接收下一帧数据。无论采用什么方式,在开始通讯之前,都要先对控制寄存器SCON进行初始化。在方式0中将,将00H送SCON就可以了。
ORG 2000H
START: MOV SCON,#00H &#59;置串行口工作方式0
MOV A,#80H &#59;最高位灯先亮
CLR P1.0 &#59;关闭并行输出(避象传输过程中,各LED的暗红现象)
OUT0: MOV SBUF,A &#59;开始串行输出
OUT1: JNB TI,OUT1 &#59;输出完否
CLR TI &#59;完了,清TI标志,以备下次发送
SETB P1.0 &#59;打开并行口输出
ACALL DELAY &#59;延时一段时间
RR A &#59;循环右移
CLR P1.0 &#59;关闭并行输出
JMP OUT0 &#59;循环
说明:DELAY延时子程序可以用前面我们讲P1口流水灯时用的延时子程序,这里就不给出了。
二、异步通讯
org 0000H
AJMP START
ORG 30H
START:
mov SP,#5fh &#59;
mov TMOD,#20h &#59;T1: 工作模式2
mov PCON,#80h &#59;SMOD=1
mov TH1,#0FDH &#59;初始化波特率(参见表)
mov SCON,#50h &#59;Standard UART settings
MOV R0,#0AAH &#59;准备送出的数
SETB REN &#59;允许接收
SETB TR1 &#59;T1开始工作
WAIT:
MOV A,R0
CPL A
MOV R0,A
MOV SBUF,A
LCALL DELAY
JBC TI,WAIT1 &#59;如果TI等于1,则清TI并转WAIT1
AJMP WAIT
WAIT1: JBC RI,READ &#59;如果RI等于1,则清RI并转READ
AJMP WAIT1
READ:
MOV A,SBUF &#59;将取得的数送P1口
MOV P1,A
LJMP WAIT
DELAY: &#59;延时子程序
MOV R7,#0ffH
DJNZ R7,$
RET
END
将程序编译通过,写入芯片,插入实验板,用通读电缆将实验板与主机的串口相连就可以实验了。上面的程序功能很简单,就是每隔一段时间向主机轮流送数55H和AAH,并把主机送去的数送到P1口。可以在PC端用串口精灵来做实验。串口精灵在我主页上有下载。运行串口精灵后,按主界面上的“设置参数”按钮进入“设置参数”对话框,按下面的参数进行设置。注意,我的机器上用的是串口2,如果你不是串口2,请自行更改串口的设置。

设置完后,按确定返回主界面,注意右边有一个下拉列表,应当选中“按16进制”。然后按“开始发送”、“开始接收”就可以了。按此设置,实验板上应当有两只灯亮,6只灯灭。大家可以自行更改设置参数中的发送字符如55,00,FF等等,观察灯的亮灭,并分析原因,也可以在主界面上更改下拉列表中的“按16进制”为“按10进制”或“按ASCII字符”来观察现象,并仔细分析。这对于大家理解16进制、10进制、ASCII字符也是很有好处的。程序本身很简单,又有注释,这里就不详加说明了。
三、上述程序的中断版本
org 0000H
AJMP START
org 0023h
AJMP SERIAL &#59;
ORG 30H
START:
mov SP,#5fh &#59;
mov TMOD,#20h &#59;T1: 工作模式2
mov PCON,#80h &#59;SMOD=1
mov TH1,#0FDH &#59;初始化波特率(参见表)
mov SCON,#50h &#59;Standard UART settings
MOV R0,#0AAH &#59;准备送出的数
SETB REN &#59;允许接收
SETB TR1 &#59;T1开始工作
SETB EA &#59;开总中断
SETB ES &#59;开串口中断
SJMP $
SERIAL:
MOV A,SBUF
MOV P1,A
CLR RI
RETI
END
本程序没有写入发送程序,大家可以自行添加。

常用接口电路及其编程
1.LED数码显示器的连接与编程
在单片机系统中,通常用LED数码显示器来显示各种数字或符号。由于它具有显示清晰、亮度高、使用电压低、寿命长的特点,因此使用非常广泛。
1.八段LED显示器
引入:还记得我们小时候玩的“火柴棒游戏”吗,几根火柴棒组合起来,可以拼成各种各样的图形,LED显示器实际上也是这么一个东西。

八段LED显示器由8个发光二极管组成。基中7个长条形的发光管排列成“日”字形,另一个贺点形的发光管在显示器的右下角作为显示小数点用,它能显示各种数字及部份英文字母。LED显示器有两种不同的形式:一种是8个发光二极管的阳极都连在一起的,称之为共阳极LED显示器;另一种是8个发光二极管的阴极都连在一起的,称之为共阴极LED显示器。如下图所示。`
共阴和共阳结构的LED显示器各笔划段名和安排位置是相同的。当二极管导通时,相应的笔划段发亮,由发亮的笔划段组合而显示的各种字符。8个笔划段hgfedcba对应于一个字节(8位)的D7 D6 D5 D4 D3 D2 D1 D0,于是用8位二进制码就可以表示欲显示字符的字形代码。例如,对于共阴LED显示器,当公共阴极接地(为零电平),而阳极hgfedcba各段为0111011时,显示器显示P字符,即对于共阴极LED显示器,“P”字符的字形码是73H。如果是共阳LED显示器,公共阳极接高电平,显示“P”字符的字形代码应为10001100(8CH)。这里必须注意的是:很多产品为方便接线,常不按规则的方法去对应字段与位的关系,这时字形码就必须根据接线来自行设计了,后面我们会给出一个例子。
2.静态显示接口
在单片机应用系统中,显示器显示常用两种方法:静态显示和动态扫描显示。所谓静态显示,就是每一个显示器都要占用单独的具有锁存功能的I/O接口用于笔划段字形代码。这样单片机只要把要显示的字形代码发送到接口电路,就不用管它了,直到要显示新的数据时,再发送新的字形码,因此,使用这种方法单片机中CPU的开销小。可以提供单独锁存的I/O接口电路很多,这里以常用的串并转换电路74LS164为例,介绍一种常用静态显示电路,以使大家对静态显示有一定的了解。
MCS-51单片机串行口方式押为移们寄存器方式,外接6片74LS164作为6位LED显示器的静态显示接口,把8031的RXD作为数据输出线,TXD作为移位时钟脉冲。74LS164为TTL单向8位移位寄存器,可实现串行输入,并行输出。其中A、B(第1、2脚)为串行数据输入端,2个引脚按逻辑与运算规律输入信号,公一个输入信号时可并接。T(第8脚)为时钟输入端,可连接到串行口的TXD端。每一个时钟信号的上升沿加到T端时,移位寄存器移一位,8个时钟脉冲过后,8位二进制数全部移入74LS164中。R(第9脚)为复位端,当R=0时,移位寄存器各位复0,只有当R=1时,时钟脉冲才起作用。Q1…Q8(第3-6和10-13引脚)并行输出端分别接LED显示器的hg---a各段对应的引脚上。关于74LS164还可以作如下的介绍:所谓时钟脉冲端,其实就是需要高、低、高、低的脉冲,不管这个脉冲是怎么来的,比如,我们用根电线,一端接T,一端用手拿着,分别接高电平、低电平,那也是给出时钟脉冲,在74LS164获得时钟脉冲的瞬间(再讲清楚点,是在脉冲的沿),如果数据输入端(第1,2引脚)是高电平,则就会有一个1进入到74LS164的内部,如果数据输入端是低电平,则就会有一个0进入其内部。在给出了8个脉冲后,最先进入74LS164的第一个数据到达了最高位,然后再来一个脉冲会有什么发生呢?再来一个脉冲,第一个脉冲就会从最高位移出,就象车站排队买票,栏杆就那么长,要从后面进去一个人,前面必须要从前面走出去一个人才行。
搞清了这一点,下面让我们来看电路,6片7LS164首尾相串,而时钟端则接在一起,这样,当输入8个脉冲时,从单片机RXD端输出的数据就进入到了第一片74LS164中了,而当第二个8个脉冲到来后,这个数据就进入了第二片74LS164,而新的数据则进入了第一片74LS164,这样,当第六个8个脉冲完成后,首次送出的数据被送到了最左面的164中,其他数据依次出现在第一、二、三、四、五片74LS164中。有个问题,在第一个脉冲到来时,除了第一片74LS164中接收数据外,其他各片在干吗呢?它们也在接收数据,因为它们的时钟端都是被接在一起的,可是数据还没有送到其他各片呢,它们在接收什么数据呢?。。。。。。其实所谓数据不过是一种说法而已,实际就是电平的高低,当第一个脉冲到来时,第一片164固然是从单片机接收数据了,而其它各片也接到前一片的Q8上,而Q8是一根电线,在数字电路中它只可能有两种状态:低电平或高电平,也就是“0”和“1”。所以它的下一片74LS164也相当于是在接收数据啊。只是接收的全部是0或1而已。这个问题放在这儿说明,可能有朋友不屑一顾,而有的朋友可能还是不清楚,这实际上涉及到数的本质的问题,如果不懂的,请仔细思考,并找一些数字电路的数,理解164的工作原理,再来看这个问题,或者去看看我的另一篇文章《初学单片机易掌握的概念》。务必搞懂,搞懂了这一点,你的级别就高过初学者,可谓入门者了。
入口:把要显示的数分别放在显示缓冲区60H-65H共6个单元中,并且分别对应各个数码管LED0-LED5。
出口:将预置在显示缓冲区中的6个数成相应的显示字形码,然后输出到显示器中显示。
显示程序如下:
DISP: MOV SCON,#00H &#59;初始化串行口方式0
MOV R1,#06H &#59;显示6位数
MOV R0,#65H &#59;60H-65H为显示缓冲区
MOV DPTR,#SEGTAB &#59;字形表的入口地址
LOOP:
MOV A,@R0 &#59;取最高位的待显示数据
MOVC A,@A+DPTR &#59;查表获取字形码
MOV SBUF,A &#59;送串口显示
DELAY: JNB TI,DELAY &#59;等待发送完毕
CLR TI &#59;清发送标志
DEC R0 &#59;指针下移一位,准备取下一个待显示数
DJNZ R1,LOOP &#59;直到6个数据全显示完。
RET
SETTAB: &#59;字形表,前面有介绍,以后我们再介绍字形表的制作。
DB 03H 9FH 27H 0DH 99H 49H 41H 1FH 01H 09H 0FFH
&#59; 0 1 2 3 4 5 6 7 8 9 消隐码
测试用主程序
ORG 0000H
AJMP START
ORG 30H
START: MOV SP,#6FH
MOV 65H,#0
MOV 64H,#1
MOV 63H,#2
MOV 62H,#3
MOV 61H,#4
MOV 60H,#5
LCALL DISP
SJMP $
如果按图示数码管排列,则以上主程序将显示的是543210,想想看,如果要显示012345该怎样送数?
下面我们来分析一下字形表的制作问题。先就上述“标准”的图形来看吧。写出数据位和字形的对应关系并列一个表如下(设为共阳型,也就是相应的输出位为0时笔段亮)
数据位D7D6D5D4D3D2D1D0字形码
笔段位ABCDEFGH
00000001103H
1100111119FH
20010011127H
3000011010DH
41001100199H
50100100149H
60100000141H
7000111111FH
80000000101H
90000100109H
如何,字形表会做了吧,就是这样列个表格,根据要求(0亮或1亮)写出相应位的0和1,就成了。做个练习,写出A-F的字形码吧。
如果为了接线方便而打乱了接线的顺序,那么字形表又该如何接呢?也很简单,一样地列表啊。以新实验板为例,共阳型。接线如下:
P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0.1 P0.0
C E H D G F A B
则字形码如下所示:
&#59;0 00101000 28H
&#59;1 01111110 7EH
&#59;2 10100100 0A4H
&#59;3 01100100 64H
&#59;4 01110010 72H
&#59;5 01100001 61H
&#59;6 00100001 21H
&#59;7 01111100 7CH
&#59;8 00100000 20H
&#59;9 01100000 60H
作为练习,大家写出A-F的字形代码。
本来这里是讲解显示器的静态接口的,到此应当可算结束了,但是我还想接着上面讲到的数的本质的问题再谈一点。单片机中有一些术语、名词本来是帮助我们理解事物的,但有时我们会被这些术语的相关语义所迷惑,以致不能进一步认清他们的本质,由此往往陷入困惑的境界。只有深入地了解了74LS164的工作特性,才能真正理解何谓串行的数据。有兴趣的朋友还可以再看看我网站上“其他资料”中的“银行利率屏的设计”一文。
动态扫描显示接口
动态扫描显示接口是单片机中应用最为广泛的一种显示方式之一。其接口电路是把所有显示器的8个笔划段a-h同名端连在一起,而每一个显示器的公共极COM是各自独立地受I/O线控制。CPU向字段输出口送出字形码时,所有显示器接收到相同的字形码,但究竟是那个显示器亮,则取决于COM端,而这一端是由I/O控制的,所以我们就可以自行决定何时显示哪一位了。而所谓动态扫描就是指我们采用分时的方法,轮流控制各个显示器的COM端,使各个显示器轮流点亮。
在轮流点亮扫描过程中,每位显示器的点亮时间是极为短暂的(约1ms),但由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位显示器并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感。
下图所示就是我们的实验板上的动态扫描接口。由89C51的P0口能灌入较大的电流,所以我们采用共阳的数码管,并且不用限流电阻,而只是用两只1N4004进行降压后给数码管供电,这里仅用了两只,实际上还可以扩充。它们的公共端则由PNP型三极管8550控制,显然,如果8550导通,则相应的数码管就可以亮,而如果8550截止,则对应的数码管就不可能亮,8550是由P2.7,P2.6控制的。这样我们就可以通过控制P27、P26达到控制某个数码管亮或灭的目的。
下面的这个程序,就是用实验板上的数码管显示0和1。
FIRST EQU P2.7 &#59;第一位数码管的位控制
SECOND EQU P2.6 &#59;第二位数码管的位控制
DISPBUFF EQU 5AH &#59;显示缓冲区为5AH和5BH
ORG 0000H
AJMP START
ORG 30H
START:
MOV SP,#5FH &#59;设置堆栈
MOV P1,#0FFH
MOV P0,#0FFH
MOV P2,#0FFH &#59;初始化,所显示器,LED灭
MOV DISPBUFF,#0 &#59;第一位显示0
MOV DISPBUFF+1,#1 &#59;第二握显示1
LOOP:
LCALL DISP &#59;调用显示程序
AJMP LOOP
&#59;主程序到此结束
DISP:
PUSH ACC &#59;ACC入栈
PUSH PSW &#59SW入栈
MOV A,DISPBUFF &#59;取第一个待显示数
MOV DPTR,#DISPTAB &#59;字形表首地址
MOVC A,@A+DPTR &#59;取字形码
MOV P0,A &#59;将字形码送P0位(段口)
CLR FIRST &#59;开第一位显示器位口
LCALL DELAY &#59;延时1毫秒
SETB FIRST &#59;关闭第一位显示器(开始准备第二位的数据)
MOV A,DISPBUFF+1 &#59;取显示缓冲区的第二位
MOV DPTR,#DISPTAB
MOVC A,@A+DPTR
MOV P0,A &#59;将第二个字形码送P0口
CLR SECOND &#59;开第二位显示器
LCALL DELAY &#59;延时
SETB SECOND &#59;关第二位显示
POP PSW
POP ACC
RET
DELAY: &#59;延时1毫秒
PUSH PSW
SETB RS0
MOV R7,#50
D1: MOV R6,#10
D2: DJNZ R6,$
DJNZ R7,D1
POP PSW
RET
DISPTABB 28H,7EH,0a4H,64H,72H,61H,21H,7CH,20H,60H
END
从上面的例子中可以看出,动态扫描显示必须由CPU不断地调用显示程序,才能保证持续不断的显示。
上面的这个程序可以实现数字的显示,但不太实用,为什么呢?这里仅是显示两个数字,并没有做其他的工作,因此,两个数码管轮流显示1毫秒,没有问题,实际的工作中,当然不可能只显示两个数字,还是要做其他的事情的,这样在二次调用显示程序之间的时间间隔就不一不定了,如果时间间隔比较长,就会使显示不连续。而实际工作中是很难保证所有工作都能在很短时间内完成的。况且这个显示程序也有点“浪费”,每个数码管显示都要占用1个毫秒的时间,这在很多合是不允许的,怎么办呢?我们可以借助于定时器,定时时间一到,产生中断,点亮一个数码管,然后马上返回,这个数码管就会一直亮到下一次定时时间到,而不用调用延时程序了,这段时间可以留给主程序干其他的事。到下一次定时时间到则显示下一个数码管,这样就很少浪费了。
Counter EQU 59H &#59;计数器,显示程序通过它得知现正显示哪个数码管
FIRST EQU P2.7 &#59;第一位数码管的位控制
SECOND EQU P2.6 &#59;第二位数码管的位控制
DISPBUFF EQU 5AH &#59;显示缓冲区为5AH和5BH
ORG 0000H
AJMP START
ORG 000BH &#59;定时器T0的入口
AJMP DISP &#59;显示程序
ORG 30H
START:
MOV SP,#5FH &#59;设置堆栈
MOV P1,#0FFH
MOV P0,#0FFH
MOV P2,#0FFH &#59;初始化,所显示器,LED灭
MOV TMOD,#00000001B &#59;定时器T0工作于模式1(16位定时/计数模式)
MOV TH0,#HIGH(65536-2000)
MOV TL0,#LOW(65536-2000)
SETB TR0
SETB EA
SETB ET0
MOV Counter,#0 &#59;计数器初始化
MOV DISPBUFF,#0 &#59;第一位始终显示0
MOV A,#0
LOOP:
MOV DISPBUFF+1,A &#59;第二位轮流显示0-9
INC A
LCALL DELAY
CJNE A,#10,LOOP
MOV A,#0
AJMP LOOP &#59;在此中间可以按排任意程序,这里仅作示范。
&#59;主程序到此结束
DISP: &#59;定时器T0的中断响应程序
PUSH ACC &#59;ACC入栈
PUSH PSW &#59SW入栈
MOV TH0,#HIGH(65536-2000) &#59;定时时间为2000个周期,约2170微秒(11.0592M)
MOV TL0,#LOW(65536-2000)
SETB FIRST
SETB SECOND &#59;关显示
MOV A,#DISPBUFF &#59;显示缓冲区首地址
ADD A,Counter
MOV R0,A
MOV A,@R0 &#59;根据计数器的值取相应的显示缓冲区的值
MOV DPTR,#DISPTAB &#59;字形表首地址
MOVC A,@A+DPTR &#59;取字形码
MOV P0,A &#59;将字形码送P0位(段口)
MOV A,Counter &#59;取计数器的值
JZ DISPFIRST &#59;如果是0则显示第一位
CLR SECOND &#59;否则显示第二位
AJMP DISPNEXT
DISPFIRST:
CLR FIRST &#59;显示第一位
DISPNEXT:
INC Counter &#59;计数器加1
MOV A,Counter
DEC A &#59;如果计数器计到2,则让它回0
DEC A
JZ RSTCOUNT
AJMP DISPEXIT
RSTCOUNT:
MOV Counter,#0 &#59;计数器的值只能是0或1
DISPEXIT:
POP PSW
POP ACC
RETI
DELAY: &#59;延时130毫秒
PUSH PSW
SETB RS0
MOV R7,#255
D1: MOV R6,#255
D2: NOP
NOP
NOP
NOP
DJNZ R6,D2
DJNZ R7,D1
POP PSW
RET
DISPTABB 28H,7EH,0a4H,64H,72H,61H,21H,7CH,20H,60H
END
从上面的程序可以看出,和静态显示相比,动态扫描的程序稍有点复杂,不过,这是值得的。这个程序有一定的通用性,只要改变端口的值及计数器的值就可以显示更多位数了。下面给出显示程序的流程图。
 
程序一 程序一之代码 程序二 程序二之代码
键盘接口与编程
键盘是由若干按键组成的开关矩阵,它是微型计算机最常用的输入设备,用户可以通过键盘向计算机输入指令、地址和数据。一般单片机系统中采和非编码键盘,非编码键盘是由软件来识别键盘上的闭合键,它具有结构简单,使用灵活等特点,因此被广泛应用于单片机系统。
1.按键开关的抖动问题
组成键盘的按键有触点式和非触点式两种,单片机中应用的一般是由机械触点构成的。在下图中,当开

图1
图2
关S未被按下时,P1。0输入为高电平,S闭合后,P1。0输入为低电平。由于按键是机械触点,当机械触点断开、闭合时,会有抖动动,P1。0输入端的波形如图2所示。这种抖动对于人来说是感觉不到的,但对计算机来说,则是完全可以感应到的,因为计算机处理的速度是在微秒级,而机械抖动的时间至少是毫秒级,对计算机而言,这已是一个“漫长”的时间了。前面我们讲到中断时曾有个问题,就是说按键有时灵,有时不灵,其实就是这个原因,你只按了一次按键,可是计算机却已执行了多次中断的过程,如果执行的次数正好是奇数次,那么结果正如你所料,如果执行的次数是偶数次,那就不对了。
为使CPU能正确地读出P1口的状态,对每一次按键只作一次响应,就必须考虑如何去除抖动,常用的去抖动的方法有两种:硬件方法和软件方法。单片机中常用软件法,因此,对于硬件方法我们不介绍。软件法其实很简单,就是在单片机获得P1。0口为低的信息后,不是立即认定S1已被按下,而是延时10毫秒或更长一些时间后再次检测P1。0口,如果仍为低,说明S1的确按下了,这实际上是避开了按键按下时的抖动时间。而在检测到按键释放后(P1。0为高)再延时5-10个毫秒,消除后沿的抖动,然后再对键值处理。不过一般情况下,我们通常不对按键释放的后沿进行处理,实践证明,也能满足一定的要求。当然,实际应用中,对按键的要求也是千差万别,要根据不同的需要来编制处理程序,但以上是消除键抖动的原则。
2.键盘与单片机的连接

图3
图4
1、通过1/0口连接。将每个按键的一端接到单片机的I/O口,另一端接地,这是最简单的方法,如图3所示是实验板上按键的接法,四个按键分别接到P3.2 、P3.3、P3.4和P3.5。对于这种键各程序可以采用不断查询的方法,功能就是:检测是否有键闭合,如有键闭合,则去除键抖动,判断键号并转入相应的键处理。下面给出一个例程。其功能很简单,四个键定义如下:
P3.2:开始,按此键则灯开始流动(由上而下)
P3.3:停止,按此键则停止流动,所有灯为暗
P3.4:上,按此键则灯由上向下流动
P3.5:下,按此键则灯由下向上流动
UpDown EQU 00H &#59;上下行标志
StartEnd EQU 01H &#59;起动及停止标志
LAMPCODE EQU 21H &#59;存放流动的数据代码
ORG 0000H
AJMP MAIN
ORG 30H
MAIN:
MOV SP,#5FH
MOV P1,#0FFH
CLR UpDown &#59;启动时处于向上的状态
CLR StartEnd &#59;启动时处于停止状态
MOV LAMPCODE,#0FEH &#59;单灯流动的代码
LOOP:
ACALL KEY &#59;调用键盘程序
JNB F0,LNEXT &#59;如果无键按下,则继续
ACALL KEYPROC &#59;否则调用键盘处理程序
LNEXT:
ACALL LAMP &#59;调用灯显示程序
AJMP LOOP &#59;反复循环,主程序到此结束
&#59;---------------------------------------
DELAY:
MOV R7,#100
D1: MOV R6,#100
DJNZ R6,$
DJNZ R7,D1
RET
&#59;----------------------------------------延时程序,键盘处理中调用
KEYPROC:
MOV A,B &#59;从B寄存器中获取键值
JB ACC.2,KeyStart &#59;分析键的代码,某位被按下,则该位为1(因为在键盘程序中已取反)
JB ACC.3,KeyOver
JB ACC.4,KeyUp
JB ACC.5,KeyDown
AJMP KEY_RET
KeyStart:
SETB StartEnd &#59;第一个键按下后的处理
AJMP KEY_RET
KeyOver:
CLR StartEnd &#59;第二个键按下后的处理
AJMP KEY_RET
KeyUp: SETB UpDown &#59;第三个键按下后的处理
AJMP KEY_RET
KeyDown:
CLR UpDown &#59;第四个键按下后的处理
KEY_RET:RET
KEY:
CLR F0 &#59;清F0,表示无键按下。
ORL P3,#00111100B &#59;将P3口的接有键的四位置1
MOV A,P3 &#59;取P3的值
ORL A,#11000011B &#59;将其余4位置1
CPL A &#59;取反
JZ K_RET &#59;如果为0则一定无键按下
ACALL DELAY &#59;否则延时去键抖
ORL P3,#00111100B
MOV A,P3
ORL A,#11000011B
CPL A
JZ K_RET
MOV B,A &#59;确实有键按下,将键值存入B中
SETB F0 &#59;设置有键按下的标志
K_RET:
ORL P3,#00111100B &#59;此处循环等待键的释放
MOV A,P3
ORL A,#11000011B
CPL A
JZ K_RET1 &#59;直到读取的数据取反后为0说明键释放了,才从键盘处理程序中返回
AJMP K_RET
K_RET1:
RET
&#59;-----------------------------------
D500MS: &#59;流水灯的延迟时间
PUSH PSW
SETB RS0
MOV R7,#200
D51: MOV R6,#250
D52: NOP
NOP
NOP
NOP
DJNZ R6,D52
DJNZ R7,D51
POP PSW
RET
&#59;-----------------------------------
LAMP:
JB StartEnd,LampStart &#59;如果StartEnd=1,则启动
MOV P1,#0FFH
AJMP LAMPRET &#59;否则关闭所有显示,返回
LampStart:
JB UpDown,LAMPUP &#59;如果UpDown=1,则向上流动
MOV A,LAMPCODE
RL A &#59;实际就是左移位而已
MOV LAMPCODE,A
MOV P1,A
LCALL D500MS
AJMP LAMPRET
LAMPUP:
MOV A,LAMPCODE
RR A &#59;向下流动实际就是右移
MOV LAMPCODE,A
MOV P1,A
LCALL D500MS
LAMPRET:
RET
END
以上程序功能很简单,但它演示了一个键盘处理程序的基本思路,程序本身很简单,也不很实用,实际工作中还会有好多要考虑的因素,比如主循环每次都调用灯的循环程序,会造成按键反应“迟钝”,而如果一直按着键不放,则灯不会再流动,一直要到松开手为止,等等,大家可以仔细考虑一下这些问题,再想想有什么好的解决办法。
2、采用中断方式:如图4所示。各个按键都接到一个与非上,当有任何一个按键按下时,都会使与门输出为低电平,从而引起单片机的中断,它的好处是不用在主程序中不断地循环查询,如果有键按下,单片机再去做相应的处理。

1.矩阵式键盘接口技术及编程
1.矩阵式键盘的结构与工作原理:
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图1所示。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在


需要的键数比较多时,采用矩阵法来做键盘是合理的。
矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,上图中,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。这样,当按键没有按下时,所有的输出端都是高电平,代表无键按下。行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。具体的识别及编程方法如下所述。
2.矩阵式键盘的按键识别方法
确定矩阵式键盘上何键被按下介绍一种“行扫描法”。
行扫描法 行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,如上图所示键盘,介绍过程如下。
1.判断键盘中有无键按下 将全部行线Y0-Y3置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。
2.判断闭合键所在的位置 在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
下面给出一个具体的例子:
图仍如上所示。8031单片机的P1口用作键盘I/O口,键盘的列线接到P1口的低4位,键盘的行线接到P1口的高4位。列线P1.0-P1.3分别接有4个上拉电阻到正电源+5V,并把列线P1.0-P1.3设置为输入线,行线P1.4-P.17设置为输出线。4根行线和4根列线形成16个相交点。
1.检测当前是否有键被按下。检测的方法是P1.4-P1.7输出全“0”,读取P1.0-P1.3的状态,若P1.0-P1.3为全“1”,则无键闭合,否则有键闭合。
2.去除键抖动。当检测到有键按下后,延时一段时间再做下一步的检测判断。
3.若有键被按下,应识别出是哪一个键闭合。方法是对键盘的行线进行扫描。P1.4-P1.7按下述4种组合依次输出:
P1.7 1 1 1 0
P1.6 1 1 0 1
P1.5 1 0 1 1
P1.4 0 1 1 1
在每组行输出时读取P1.0-P1.3,若全为“1”,则表示为“0”这一行没有键闭合,否则有键闭合。由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值
4.为了保证键每闭合一次CPU仅作一次处理,必须却除键释放时的抖动。




键盘扫描程序:
从以上分析得到键盘扫描程序的流程图如图2所示。程序如下
SCAN: MOV P1,#0FH
MOV A,P1
ANL A,#0FH
CJNE A,#0FH,NEXT1
SJMP NEXT3
NEXT1: ACALL D20MS
MOV A,#0EFH
NEXT2: MOV R1,A
MOV P1,A
MOV A,P1
ANL A,#0FH
CJNE A,#0FH,KCODE&#59;
MOV A,R1
SETB C
RLC A
JC NEXT2
NEXT3: MOV R0,#00H
RET
KCODE: MOV B,#0FBH
NEXT4: RRC A
INC B
JC NEXT4
MOV A,R1
SWAP A
NEXT5: RRC A
INC B
INC B
INC B
INC B
JC NEXT5
NEXT6: MOV A,P1
ANL A,#0FH
CJNE A,#0FH,NEXT6
MOV R0,#0FFH
RET
键盘处理程序就作这么一个简单的介绍,实际上,键盘、显示处理是很复杂的,它往往占到一个应用程序的大部份代码,可见其重要性,但说到,这种复杂并不来自于单片机的本身,而是来自于操作者的习惯等等问题,因此,在编写键盘处理程序之前,最好先把它从逻辑上理清,然后用适当的算法表示出来,最后再去写代码,这样,才能快速有效地写好代码。
到本课为止,本站教程暂告一个段落!感谢大家的关心和支持!


作者: loveme    时间: 2003-4-7 22:39
标题: 单片机技术!!!
有用Keil C51和Proteus5.2(或6。0)的,指导一下如何
作者: suncon    时间: 2003-4-8 05:31
标题: 单片机技术!!!
Protel DXP 指导教程
Protel DXP 指导教程
目录
欢迎使用Protel DXP 在原理图中放置元件创建一个新的PCB文件  手式布线
Protel DXP 设计探索者  连接电路将新的PCB添加到项目  自动布线
设计文件夹是怎样保存的  网络与网络标签  转换设计  验证你的板设计
创建一个新项目设置项目选项  更新PCB设置项目输出
创建一个新的原理图图纸检查原理图的电气参数  设计PCB打印到Windows打印设备
将原理图图纸添加到项目  设置错误报告  设置PCB工作区  生产输出文件
  设置原理图选项  设置连接模式定义板层和其它非电层仿真设计
  绘制原理图  设置比较器  设置新的设计规则  设置仿真
  定位元件和加载元件库  编辑项目  在PCB上放置元件  运行瞬态特性分析
欢迎使用Protel DXP
欢迎来到Protel DXP世界--Protel DXP是一款Windows NT/XP的全32位电子设计系统。Protel DXP提供一套完全集成的设计,这些工具让你很容易地将你的设计从概念形成最终的板设计。
所有的Protel DXP工具需要在一个单一应用环境--设计探索者(the Design Explorer)中运行。启动Protel DXP,设计探索者打开,将你所有的设计工具放在你的手指尖。你将从一个单一的、一致的、个性化的用户环境受益。
这个教程的设计是为了为你提供一个怎样建立一张原理图、从PCB更新设计信息以及产生生产输出文件的预览。
Protel DXP设计探索者
设计探索者是你与你的设计和设计工具的界面。要启动Protel并打开设计探索者,从Windows开始菜单选择Programs » Altium » Protel DXP。当你打开Protel DXP后,将显示最常用的初始任务以便方便选择(如图)。
在你建立了你的设计文件夹后,你就能在编辑器之间转换,例如,原理图编辑器和PCB编辑器。设计探索者将根据你当前所工作的编辑器来改变工具栏和菜单。一些工作区面板的名字最初也会显示在工作区右下角。在这些名字上点击将会弹出面板,这些面板可以通过移动、固定或隐藏来适应你的工作环境。
下图展示了当几个文件和编辑器同时打开并且窗口进行平铺时的设计探索者。

设计文件怎样保存
Protel DXP将所有的设计文件和输出文件都作为个体文件保存在你的硬盘。你可以使用Windows Explorer来查找。项目文件可以的建立可以包含设计文件的连接,这样使得设计验证和同步成为可能。
创建一个新项目
在Protel DXP中,一个项目包括所有文件夹的连接和与设计有关的设置。一个项目文件,例如xxx.PrjPCB,是一个ASCII文本文件,用于列出在项目里有哪些文件以及有关输出的配置,例如打印和CAM。那些与项目没有关联的文件称作“自由文件(free documents)”。与原理图纸和目标输出的连接,例如PCB、FPGA、VHDL或库封装,将添加到项目中。一旦项目被编辑,设计验证、同步和对比就会产生。例如,当项目被编辑后,项目中的原始原理图或PCB的任何改变都会被更新。
建立一个新项目的步骤对各种类型的项目都是相同的。我们将以PCB项目为例。首先我们要创建一个项目文件,然后创建一个空的原理图图纸以添加到新的空项目中。在这个教程的最后我们将创建一个空白PCB并将它同样添加到项目中。
为开始教程,创建一个新的PCB项目:
1、在设计窗口的Pick a Task区中点击Create a new Board Level Design Project。

另外,你以可以在Files面板中的New区点击Blank Project (PCB)。如果这个面板未显示,选择File » New,或点击设计管理面板底部的Files标签。
2、Projects面板出现。新的项目文件,PCB Project1.PrjPCB,与“no documents added”文件夹一起列出。

3、通过选择File »Save Project As来将新项目重命名(扩展名为*.PrjPCB)。指定你要把这个项目保存在你的硬盘上的位置,在文件名栏里键入文件名Multivibrator.PrjPCB并点击Save。
下面,我们将创建一个原理图并添加到空项目文件。这个原理图是一个多谐振荡器电路。
创建一个新的原理图图纸
创建一个新的原理图图纸按照以下步骤来完成:
1、在Files面板的New单元选择File » New并点击Schematic Sheet。一个名为Sheet1.SchDoc的原理图图纸出现在设计窗口中,并且原理图文件夹也自动地添加(连接)到项目。这个原理图图纸现在列表在Projects标签中的紧挨着项目名下的Schematic Sheets文件夹下。

2、通过选择File » Save As来将新原理图文件重命名(扩展名为*.SchDoc)。指定你要把这个原理图保存在你的硬盘中的位置,在文件名栏键入Multivibrator.SchDoc,并点击Save。
3、当空白原理图纸打开后,你将注意到工作区发生了变化。主工具栏增加了一组新的按钮,新的工具栏出现,并且菜单栏增加了新的菜单项。现在你就在原理图编辑器中了。
你可以自定义工作区的许多模样。例如,你可以重新放置浮动的工具栏。单击并拖动工具栏的标题区,然后移动鼠标重新定位工具栏。改变工具栏,可以将其移动到主窗口区的左边、右边、上边或下边。
现在我们可以在设计开始之前将我们的空白原理图添加到项目中了。
将原理图图纸添加到项目中
如果你想添加到一个项目文件中的原理图图纸已经作为自由文件夹被打开,那么在Projects面板的Free Documents单元schematic document文件夹上右击,并选择Add to Project。现在这个原理图图纸就列表在Projects标签中的紧挨着项目名下的Schematic Sheets文件夹下,并连接到项目文件。
设置原理图选项
在你开始绘制电路图之前首先要做的是设置正确的文件夹选项。完成以下步骤:
1、从菜单选择Design » Options,文件夹选项对话框打开。作为本教程,在此我们唯一需要修改的是将图纸大小(sheet size)设置为标准A4格式。在Sheet Options标签,找到Standard Styles栏。点击输入框旁的箭头将看见一个图纸样式的列表。
2、使用滚动栏来向上滚动到A4样式并点击选择。
3、点击OK按钮关闭对话框,更新图纸大小。
4、为将文件再全部显示在可视区,选择View » Fit Document。
在Protel DXP中,你可以通过只按菜单热键(在菜单名中带下划线的字母)来激活任何菜单。以后任何菜单项也将有你可以用来激活该项的热键。例如,对于选择View » Fit Document菜单项的热键就是在按了V键后按D键。许多子菜单,诸如Edit » DeSelect菜单,是可以直接调用的。要激活Edit » DeSelect » All菜单项,你只需要按X键(用于直接调用DeSelect菜单)及A键。
下面我们将进行一般的原理图参数设置:
1、从菜单选择Tools » Preferences(热键T,P)打开原理图参数对话框。这个对话框允许你设置全部参数,这些将应用到你将继续工作的所有原理图图纸。
2、点击Default Primitives标签以使其为当前,勾选Permanent。点击OK按钮关闭对话框。
3、在你开始绘制原理图之前,保存这个原理图图纸,因此选择File » Save(热键F,S)。
绘制原理图
你现在准备开始绘制原理图了。在这个教程中,我们将使用如下图(Figure 1)所示的电路。这个电路用了两个2N3904晶体管来完成自激多谐振荡器。

定位元件和加载元件库
管理数以千计的原理图符号也包括在Protel DXP中,原理图编辑器提供强大的库搜索功能。尽管我们需要的元件已经在默认的安装库中,但对于知道怎样通过库搜索来找到元件还是很有用的。通过以下步骤的操作来定位并添加本教程电路所要用到的库。
首先我们要查找晶体管,两个均为2N3904。

1、点击Libraries标签显示库工作区面板。
2、在库面板中按下Search按钮,或选择Tools» Find Component。这将打开查找库对话框。
3、确认Scope被设置为Libraries on Path,并且Path区含有指向你的库的正确路径。如果你接受安装过程中的默认目录,路径中会显示C:\Program Files\Altium\Library\。确认Include Subdirectories未被选择(未被勾选)。
4、我们想查找所有与3904有关的,所以在Search Criteria单元的Name文本框内键入*3904*。
5、点击Search按钮开始查找。当查找进行时Results标签将显示。如果你输入的规则正确,一个库将被找到并显示在查找库对话框。
6、点击Miscellaneous Devices.IntLib库以选择它。
7、点击Install Library按钮使这个库在你的原理图中可用。
8、关闭Search Libraries对话框。
添加的库将显示在库面板的顶总。如果你点击上面列表中的库名,库中的元件会在下面列表。面板中的元件过滤器可以用来在一个库内快速定位一个元件。
在原理图中放置元件
在原理图中我们首先要放置的元件是两个晶体管(transistors),Q1和Q2。
1、从菜单选择View » Fit Document(热键V、D)确认你的原理图纸显示在整个窗口中。
2、点击Libraries标签以显示Libraries面板。
3、Q1和Q2是BJT晶体管,点击Miscellaneous Devices.IntLib库使其为当前库。
4、使用过滤器快速定位你需要的元件。默认通配符(*)将列出在库中找到的所有元件。在库名下的过滤器栏内键入*3904*设置过滤器。一个有“3904”作为元件名的元件列表将显示。
5、在列表中点击2N3904以选择它,然后点击Place按钮。另外,还可以双击元件名。
光标将变成十字状,并且在光标上“悬浮”着一个晶体管的轮廓。现在你处于元件放置状态。如果你移动光标,晶体管轮廓也会随之移动。
6、在原理图上放置元件之前,首先要编辑其属性。在晶体管悬浮在光标上时,按下TAB键。这将打开Component Properties(元件属性)对话框。我们现在要设置对话框选项如下图所示。

7、在对话框Properties单元,在Designator栏中键入Q1以将其值作为第一个元件序号。
8、下面我们将检查在PCB中用于表示元件的封装。在本教程中,我们已经使用了集成库,这些库已经包括了封装和电路仿真的模型。确认在模型列表中含有模型名BCY-W3/D4.7。保留其余栏为默认值。
现在准备放置元件。
1、移动光标(附有晶体管符号)到图纸中间偏左一点的位置。
2、当你对晶体管的位置满意后,左击或按ENTER键将晶体管放在原理图上。
3、移动光标,你会发现晶体管的一个复制品已经放在原理图纸上了,而你仍然处于在光标上悬浮着元件轮廓的元件放置状态。Protel DXP的这个功能让你放置许多相同型号的元件。现在让我们放第二个晶体管。这个晶体管同前一个相同,因此在放之前没必要再编辑它的属性。在你放置一系列元件时Protel DXP会自动增加一个元件的序号值。以这个例子中,我们放下的第二个晶体管会自动标记为Q2。
4、如果你查阅原理图(Figure 1),你会发现Q2与Q1是镜像的。要将悬浮在光标上的晶体管翻过来,按X键。这样可以使元件水平翻转。
5、移动光标到Q1右边的位置。要将元件的位置放得更精确些,按PAGEUP键两次以放大两倍。现在你能看见栅格线了。
6、当你将元件的位置确定后,左击或按ENTER键放下Q2。你所拖动的晶体管的一个复制品再一次放在原理图上后,下一个晶体管会悬浮在光标上准备放置。
7、由于我们已经放完了所有的晶体管,我们用右击鼠标或按ESC键来退出元件放置状态。光标会恢复到标准箭头。
下面我们要放四个电阻(resistors)
1、在Libraries面板中,确认Miscellaneous Devices.IntLib库为当前。
2、在库名下的过滤器栏里键入res1来设置过滤器。
3、在元件列表中点击RES1以选择它,然后点击Place按钮。现在你会有一个悬浮在光标上的电阻符号。
4、按TAB键编辑电阻的属性。在对话框的Properties单元,在Designator栏中键入R1以将其值作为第一个元件序号。
5、确认模型名为AXIAL-0.3包含在模型列表中。
6、对电阻的parameter 栏的设置将在原理中显示,并在本教程以后运行电路仿真时会被DXP使用。=Value规则可以作为关于元件的一般信息在仿真时使用,个别元件除外。我们也可以设置Comment来读取这个值,而这也会将Comment信息体现在PCB设计工具中。没必要将该值输入两次(在规则中的=Value和Comment栏),DXP提供“间接引用”,这可以用规则中的字符来替代Comment栏的内容。
在规则列表单元中点击Add显示Parameter Properties对话框。在name中输入Value以及在value中输入100K。确认String作为规则类型被选择,并且value的Visible框被勾选。点击OK。
7、在对话框的Properties单元,点击Comment栏并从下拉列表中选择=Value,将Visible关闭。点击OK按钮返回放置模式。
8、按SPACEBAR(空格键)将电阻旋转90°。
9、将电阻放在Q1基极的上边(参见Figure 1中的原理图)然后左击或按ENTER键放下元件。
10、接下来在Q2的基极上边放另一个100K电阻R2。
11、剩下两个电阻,R3和R4,阻值为1K,按TAB键显示Component Properties对话框,改变Value栏为1K(在Parameters列表中当Value被选择后按Edit按钮)。点击OK按钮关闭对话框。
12、参照Figure 1中的原理图所示定位并放置R3和R4。
13、放完所有电阻后,右击或按ESC键退出元件放置模式。
现在放置两个电容(capacitors):
1、电容元件也在Miscellaneous Devices.IntLib库里,该应该已经在Libraries面板中被选择。
2、在Libraries面板的元件过滤器栏键入cap。
3、在元件列表中点击CAP选择它,然后点击Place按钮。现在在你的光标上悬浮着一个电容符号。
4、按TAB键编辑电容的属性。在Component Properties对话框的Properties单元,设置Designator为C1,检查PCB封装模型为RAD-0.3被添加到Models列表中。
5、规则栏的设置将显示在原理图中。点击规则列表中的Add显示Parameter Properties对话框。输入名称Value以及值20n。确认String作为规则类型被选择,并且value的Visible框被勾选。点击OK。
6、在对话框的Properties单元,点击Comment栏并从下拉列表中选择=Value,将Visible关闭。点击OK按钮返回放置模式。
7、用放置以前的元件的方法放置两个电容。
8、右击或按ESC退出放置模式。
最后要放置的元件是连接器(connector),在Miscellaneous Connectors.IntLib 库里。
1、我们想要的连接器是两个引脚的插座,所以设置过滤器为*2*。
2、在元件列表中选择HEADER2并点击Place按钮。按TAB编辑其属性并设置Designator为Y1,检查PCB封装模型为HDR1X2。由于在仿真电路时我将把这个元件作为电路,所以不需要作规则设置。点击OK关闭对话框。
3、以放置连接器之前,按X作水平翻转。在原理图中放下连接器。
4、右击或按ESC退出放置模式。
5、从菜单选择File » Save(热键F,S)保存你的原理图。
现在你放完了所有的元件。注意在Figure 2中的元件之间留有间隔,这样就有大量的空间用来将导线连接到每个元件引脚上。这很重要,因为你不能将一根导线穿过一个引线的下面来连接在它的范围内的另一个引脚。如果你这样做,两个引脚就都连接到导线上了。
如果你需要移动元件,点击并拖动元件体,拖动鼠标重新放置。

连接电路
连线起着在你的电路中的各种元件之间建立连接的作用。要在原理图中连线,参照Figure 1的图示并完成以下步骤:
1、确认你的原理图图纸有一个好的视图,从菜单选择View » Fit All Objects(热键V,F)。
2、首先用以下方法将电阻R1与晶体管Q1的基极连接起来。从菜单选择Place »Wire(热键P,W)或从Wiring Tools(连线工具)工具栏点击Wire工具进入连线模式。光标将变为十字形状。
3、将光标放在R1的下端。当你放对位置时,一个红色的连接标记(大的星形标记)会出现在光标处。这表示光标在元件的一个电气连接点上。
4、左击或按ENTER固定第一个导线点。移动光标你会看见一根导线从光标处延伸到固定点。
5、将光标移到R1的下边Q1的基极的水平位置上,左击或按ENTER在该点固定导线。在第一个和第二个固定点之间的导线就放好了。
6、将光标称到Q1的基极上,你会看见光标变为一个红色连接标记。左击或按ENTER连接到Q1的基极。
7、完成这部分导线的放置。注意光标仍然为十字形状,表示你准备放置其它导线。要完全退出放置模式恢复箭头光标,你应该再一次右击或按ESC--但现在还不能这样做。
8、现在我们要将C1连接到Q1和R1。将光标放在C1左边的连接点上,左击或按ENTER开始新的连线。
9、水平移动光标一直到Q1的基极与R1的连线上。一个连接标记将出现。
10、左击或按ENTER放置导线段,然后右击或按ESC表示你已经完成该导线的放置。注意两条导线是怎样自动连接上的。
11、参照Figure 3连接电路中的剩余部分。

12、在完成所有的导线之后,右击或按ESC退出放置模式。光标恢复为箭头形状。
网络与网络标签
彼此连接在一起的一组元件引脚称为网络(net)。例如,一个网络包括Q1的基极、R1的一个引脚和C1的一个引脚。
在设计中识别重要的网络是很容易的,你可以添加网络标签(net labels)。
在两个电源网络上放置网络标签:
1、从菜单选择Place » Net Label。一个虚线框将悬浮在光标上。
2、在放置网络标签之前应先编辑,按TAB键显示Net Label (网络标签)对话框。
3、在Net栏键入12V,然后点击OK关闭对话框。
4、将该网络标签放在原理上,使该网络标签的左下角与最上边的导线靠在一起。
5、放完第一个网络标签后,你仍然处于网络标签放置模式,在放第二个网络标签之前再按TAB键进行编辑。
6、在Net栏键入GND,点击OK关闭对话框并放置网络标签。
7、选择File » Save(热键F,S)保存电路。
祝贺你!你已经用Protel DXP完成了你的第一张原理图。
在我们将原理图转为电路板之前,让我们进行项目选项设置。
设置项目选项
项目选项包括错误检查规则、连接矩阵、比较设置、ECO启动、输出路径和网络选项以及你想指定任何项目规则。在你编辑项目时Protel DXP将使用这些设置。
当项目被编辑时,详尽的设计和电气规则将应用于验证设计。当所有错误被解决后,原理图设计的再编辑将被启动的ECO加载到目标文件,例如一个PCB文件。项目比较允许你找出源文件和目标文件之间的差别,并在相互之间进行更新(同步)。
所有与项目有关的操作,如错误检查、比较文件和ECO启动均在Options for Project 对话框中设置(Project » Project Options)。
所有项目输出,如网络表、仿真器、文件的提供(打印)、集合和制造输出及报告在Outputs for Project 对话框中设置(Project » Output Jobs)。参见设置项目输出以获得更多信息。
1、选择Project » Project Options,Options for Project 对话框出现。

所有与项目有关的选均通过这个对话框来设置。
检查原理图的电气参数
在Protel DXP中原理图是不仅仅只是绘图--原理图还包含关于电路的连接信息。你可以使用连接检查器来验证你的设计。当你编辑项目时,DXP将根据在Error Reporting 和Connection Matrix 标签中的设置来检查错误,如果有错误发生则会显示在Messages 面板。
设置错误报告
在Options for Project 对话框中的Error Reporting标签用于设置设计草图检查。报告模式(Report Mode)表明违反规则的严格程度。如果你要修改Report Mode,点击你要修改的违反规则旁的Report Mode,并从下拉列表中选择严格程度。在本教程中我们使用默认设置。
设置连接矩阵
连接矩阵标签(Options for Project对话框)显示的是错误类型的严格性,这将在设计中运行错误报告检查电气连接产生,如引脚间的连接、元件和图纸输入。这个矩阵给出了一个在原理图中不同类型的连接点以及是否被允许的图表描述。
例如,在矩阵图的右边找到Output Pin,从这一行找到Open Collector Pin列。在它的相交处是一个橙色的方块,这而这个表示在原理中从一个Output Pin连接到一个Open Collector Pin的颜色将在项目被编辑时启动一个错误条件。

你可以用不同的错误程度来设置每一个错误类型,例如对一些致命的错误不予报告。
修改连接错误:
1、点击Options for Project 对话框的Connection Matrix标签。
2、点击两种类型的连接的相交处的方块,例如Output Sheet Entry and Open Collector Pin。
3、在方块变为图例中的errors表示的颜色时停止点击,例如一个橙色方块表示一个错误将表明这样的连接是否被发现。
我们的电路不只包含Passive Pins(在电阻、电容和连接器上)和Input Pins(在晶体管上)。让我们来检查一下看看连接矩阵是否会侦测出未连接的passive pins。
1、在行标签中找到Passive Pin,在列标签中找到Unconnected。它们的相交处的方块表示在原理中当一个Passive Pin被发现未连接时的错误条件。默认是一个绿色方块,表示运行时不给出报告。
2、点击这个相交处的方块,直到它变为黄色,这样当我们修改项目时,未连接的passive pins被发现时就会给出警告。
设置比较器
Options for Project 对话框的Comparator标签用于设置当一个项目修改时给出文件之间的不同或忽略。在本教程中,我们不需要将一些仅表示原理图设计等级的特性(如rooms)之间的不同显示出来。确认在你忽略元件等级时没有忽略元件。
1、点击Comparator标签并在Difference Associated with Components单元找到Changed Room Definitions、 Extra Room Definitions 和 Extra Component Classes。
2、从这些选项右边的Mode列中的下拉列表中选择Ignore Differences。

现在我们准备编辑项目并检查所有错误了。
编辑项目
编辑一个项目就是在设计文档中检查草图和电气规则错误并将你置于一个调试环境。我们已经在Options for Project 对话框中对Error Checking和Connection Matrix标签中的规则进行了设置。
1、要编辑我们的Multivibrator项目,选择Project » Compile PCB Project。
2、当项目被编辑时,任何已经启动的错误均将显示在设计窗口下部的Messages面板中。被编辑的文件会与同级的文件、元件和列出的网络以及一个能浏览的连接模型一起列表在Compiled面板中。
如果你的电路绘制正确,Messages面板应该是空白的。如果报告给出错误,则检查你的电路并确认所有的导线和连接是正确的。
我们现在要小心地加入一个错误到我们的电路中并重新编辑项目:
1、在设计窗口的顶部点击Multivibrator.SchDoc标签,以使原理图为当前文档。
2、点击连接C1和Q1基极的导线的中部,在导线的端点将出现小的方形编辑热点,一条沿着导线的虚线将显示选择颜色以表示这条导线被选取了。按DELETE键删除这条导线。
3、重新编辑项目(Project » Compile PCB Project)来检查错误被找到。
Messages面板将打开并给出一个警告信号:在你的电路中有一个未连接的输入引脚。一个悬浮输入引脚错误也会运行,这是因为在Project Options 对话框的Error Reporting标签有一个检查悬浮输入引脚的特殊选项。
4、在Messages面板点击一个错误,Compile Error 窗口将显示违反的详细情况。从这个窗口,你可点击一个错误并跳转到原理图的违反对象以便检查或修改错误。
在我们完成教程的本单元之前,让我们将原理图中的错误修复。
1、点击原理图图纸标签使其为激活。
2、从菜单选择Edit » Undo(热键E,U)。你先前删除的导线现在恢复了。
3、要检查恢复是否成功,重新编辑项目(Project » Compile PCB Project)来检查将没有错误被发现。Messages面板应该显示(no errors)。
4、从菜单选择View » Fit All Objects(热键V,F)恢复原理图视图,并保存无错误原理图。
创建一个新的PCB文件
在你将设计从原理图编辑器转换到PCB编辑器之前,你需要创建一个有最基本的板子轮廓的空白PCB。在Protel DXP中创建一个新的PCB设计的最简单方法是使用PCB向导,这将让你选择工业标准板轮廓又创建了你自定义的板子尺寸。在向导的任何阶段,你都可以使用Back按钮来检查或修改以前页的内容。
要使用PCB向导来创建PCB,完成以下步骤:
1、在Files面板的底部的New from Template单元点击PCB Board Wizard创建新的PCB。如果这个选项没有显示在屏幕上,点向上的箭头图标关闭上面的一些单元。
2、PCB Board Wizard打开。你首先看见的是介绍页。点Next按钮继续。
3、设置度量单位为英制(Imperial),注意,1000 mils = 1 inch 。
4、向导的第三页允许你选择你要使用的板轮廓。在本教程中我们使用我们自定义的板子尺寸。从板轮廓列表中选择Custom,点击Next。
5、在下一页,你进入了自定义板选项。在本教程电路中,一个2 x 2 inch的板子将给我大量的空间。选择Rectangular并在Width和Height栏键入2000。取消选择Title Block  Scale、Legend String 和 Dimension Lines 以及 Corner Cutoff 和 Inner Cutoff。点击Next继续。
6、在这一页允许你选择板子的层数。我需要两个signal layer,不需要power planes。点击Next继续。
7、在设计中使用的过孔(via)样式选择Thru-hole vias only,点击Next。
8、在下一页允许你设置元件/导线的技术(布线)选取项。选择Thru-hole components选项,将相邻焊盘(pad)间的导线数设为One Track。点击Next继续。
9、下一页允许你设置一些应用到你的板子上的设计规则。设为默认值。点Next按钮继续。
10、最后一页允许你将自定义的板子保存为模板,允许你按你输入的规则来创建新的板子基础。我们不想将我们的教程板子保存为模板,确认该选项未被选择,点击Finish关闭向导。

11、PCB向导现在收集了它需要的所有的信息来创建你的新板子。PCB编辑器将显示一个名为PCB1.PcbDoc的新的PCB文件。
12、PCB文档显示的是一个默认尺寸的白色图纸和一个空白的板子形状(带栅格的黑色区域)。要关闭图纸,选择Design » Options,在Board Options对话框取消选择Design Sheet。

你可以使用Protel DXP从其它PCB模板中添加你自己的板框、栅格特性和标题框。要获得关于板子形状、图纸和模板的更多信息,参见板子形状和图纸教程。
13、现在图纸被关闭,选择View » Fit Board(热键V,F)将只显示板子形状。
14、PCB文档会自动添加(连接)到项目,并列表在Projects标签中紧靠项目名称的PCBs下面。
15、选择File » Save As来将新PCB文件重命名(用*.PcbDoc扩展名)。指定你要把这个PCB保存在你的硬盘上的位置,在文件名栏里键入文件名Multivibrator.PcbDoc并点击Save。
将新的PCB添加到项目
如果你想添加到项目的PCB是以自由文件打开的,在Projects面板的Free Documents单元右击PCB文件,选择Add to Project。这个PCB现在就列表在Projects标签紧靠项目名称的PCBs下面并连接到项目文件。
转换设计
在将原理图信息转换到新的空白PCB之前,确认与原理图和PCB关联的所有库均可用。由于在本教程中只用到默认安装的集成元件库,所有封装也已经包括在内了。只要项目已经编辑过并且在原理图中的任何错误均已修复,那么使用Update PCB命令来启动ECO就能将原理图信息转换到目标PCB。
更新PCB
将项目中的原理图信息发送到目标PCB:
1、在原理图编辑器选择Design » Update PCB (Multivibrator.PcbDoc)。项目修改,Engineering Change Order 对话框出现。
2、点击Validate Changes。如果所有的改变均有效,检查将出现在状态列表中。如果改变无效,关闭对话框,检查Messages面板并清除所有错误。
3、点击Execute Changes将改变发送到PCB。完成后,状态变为完成(Done)
4、点击Close,目标PCB打开,而元件也在板子上以准备放置。如果你在当前视图不能看见元件,使用热键V、D(查看文档)。

设计PCB
现在我们可以开始在PCB上放置元件并在板上布线。
设置PCB工作区
在将元件定位在板子上之前,我们需要设置PCB工作区,如栅格、层和设计规则。
栅格(Grids)
在开始定位元件之前,我们需要确认放置栅格设置正确。放置在PCB工作区的所有对象均排列在称为捕获栅格(snap grid )上。这个栅格需要设置得适合我们要使用的布线技术。
我们的教程电路用的是标准英制元件,其最小引脚间距为100mil。我们将这个捕获栅格设定为100mil的一个平均分数,50或25mil,这样所有的元件引脚在放置时均将落在栅格点一。当然,板子上的导线宽度和间距分别是12mil和13mil(这是PCB板向导使用的默认值),在平行的导线的中心之间允许最小为25mil。所以最合适的捕获栅格应设为25mil。
完成以下步骤设置捕获栅格:
1、从菜单选择Design » Options(热键D,O)打开Board Options 对话框。
2、在Grids标签,将对话框中的Snap X、 Snap Y、 Component X 和 Component Y 栏的值设为25mil。注意这个对话框也用来定义电气栅格。电气栅格在你放置一个电气对象时工作,它将忽略捕获栅格而同时捕获电气对象。点击OK关闭对话框。
让我们设置一些其它选项,这样可以使定位元件更容易些。
1、从菜单选择Tools » Preferences(热键T,P)打开System Preferences 对话框。在Options标签的Editing Options单元,确认Snap to Center选项被选中。这会使你在抓住一个元件定位时,光标就会定位在元件的参考点上。
2、点击System Preferences 对话框中Display标签其为当前。在Show单元,将Show Pad Nets、Show Pad Numbers 和 Via Nets选项取消选择。在Draft Thresholds单元,将Strings栏设为4 pixels,然后关闭对话框。
定义板层和其它非电层
如果你查看PCB工作区的底部,你会看见一系列层标签。PCB编辑器是一个多层环境,你所做的大多数编辑工作都将在一个特殊层上。使用Board Layers 对话框(Design » Board Layers)来显示、添加、删除、重命名、及设置层的颜色。

在PCB编辑器中有三种类型的层:
1、电气层--包括32个信号层和16个平面层。电气层在设计中添加或移除是在板层管理器中,选择Design » Layer Stack Manager来显示这个对话框。
2、机械层--有16个用途的机械层,用来定义板轮廓、放置厚度,包括制造说明、或其它设计需要的机械说明。这些层在打印和底片文件的产生时都是可选择的。在Board Layers对话框你可以添加、移除和命名机械层。
3、特殊层--包括顶层和底层丝印层、阻焊和助焊层、钻孔层、禁止布线层(用于定义电气边界)、多层(用于多层焊盘和过孔)、连接层、DRC错误层、栅格层和孔层。在Board Layers对话框中控制这些特殊层的显示。
板层控制器
本教程是一个简单设计,使用单面板或双面板布线就可以了。如果设计更复杂些,你可以在板层管理器中添加更多的层。
1、选择Design » Layer Stack Manager显示Layer Stack Manager 对话框。

2、新层和平面添加在当前所选择的层下面。层的参数,如铜厚和非电参数都会用在信号完整分析中。点击OK关闭对话框。
新板打开时会有许多你用不上的可用层,因此,要关闭一些不需要的层。
完成以下步骤来关闭层:
1、按快捷键L显示Board Layers对话框。
2、右击并选择Used On将那些没有东西的层关闭。
3、确认四个Mask层和Drill Drawing层名称旁边的Show按钮因没有勾选而不会显示。点击OK关闭对话框。
设置新的设计规则
Protel DXP的PCB编辑器是一个规则驱动环境。这意味着,当你在PCB编辑器中工作并执行那些改变设计的操作时,如放置导线、移动元件、或自动布线,PCB编辑器将一直监视每一个操作并检查设计是否仍然满足设计规则。
在你开始在板子上工作之前设置设计规则允许你依然关注你的设计任务,而确信任何设计错误都会立即被标记出以引起你的注意。
设计规则分为10个类别,并进一步分为设计类型。设计规则覆盖了电气、布线、制造、放置、信号完整要求。
我们将对电源网络布线宽度设置新的设计规则。
完成以下步骤来设置这些规则:
1、PCB为当前文档时,从菜单选择Design » Rules。
2、PCB Rules and Constraints Editor 对话框出现。每一类规则都显示在对话框的设计规则面板(左手边)。双击Routing类展开后可以看见有关布线的规则。然后双击Width显示宽度规则为有效。

3、在设计规则面板中每个规则都点击一次来选择。当你在每个规则上点击后,对话框右边会在顶部单元显示规则范围(你所要的这个规则的目标),而在底部单元显示规则的约束特性。这些规则都是默认值,或已经由板向导在创建新的PCB文档时设置。
4、点击Width_1规则显示它的约束特性和范围。这个规则应用到整个板。

Protel DXP的设计规则系统的一个强大功能是:可以定义同类型的多重规则,而每个目标对象又不相同。每一个规则目标的同一组对象在规则的范围里定义。规则系统使用预定义等级来决定将哪个规则应用到每个对象。
例如,你可能有一个对整个板的宽度约束规则(即所有的导线都必须是这个宽度),而对接地网络需要另一个宽度约束规则(这个规则忽略前一个规则),在接地网络上的特殊连接却需要第三个宽度约束规则(这个规则忽略前两个规则)。规则依优先权顺序显示。
现在,在你的设计中有一个宽度约束规则需要应用到整个板。现在我们要为12V和GND网络添加一个新的宽度约束规则。要添加新的宽度约束规则,完成以下步骤:
1、在Design Rules规则面板的Width类被选择时,右击并选择New Rule,将一个宽度约束规则只添加到12V网络。
一个新的名为Width_2的规则出现。在Design Rules面板点击新的规则以修改其范围和约束。
2、在名称栏键入12V或GND。当你完成规则设置后在Design Rules面板点击时Design Rules面板中的这个名称会刷新。
3、下面我们要使用Query Builder来设置规则范围,如果你知道正确的语法结构,你也可以直接在范围中键入。
点击Where the First object matches单元的Net。在Query Kind单元里会出现InNet( )。点击All按钮旁的下拉列表,从有效的网络列表中选择12V。Query Kind单元会更新为InNet (‘12V’)。

4、下面我要使用Query Builder 将范围扩展到包括GND网络。点击Advanced (Query),然后点击Query Builder。Query Helper 对话框出现。

5、点击Query单元的InNet(‘12V’)的右边,然后点击Or按钮。现在Query单元的内容变为InNet(‘12V’) or,这样就使范围设置为将规则应用到两个网络中。
6、点击PCB Functions类的Membership Checks,双击Name单元的InNet。
7、在Query单元InNet( )的括号中间点击一下,以添加GND网络的名称。在PCB Objects List 类点击Nets,然后从可用网络列表中双击选择GND。Query单元变为InNet(‘12V’) or InNet(‘GND’)。
8、点击Check Syntax,然后点击OK关闭结果信息。如果显示错误信息应予以修复。
9、点击OK关闭Query Helper 对话框。在Full Query单元的范围就更新为新的内容。
10、在PCB Rules and Constraints Editor 对话框的底部单元,点击旧约束文本(10mil)并键入新值以将Minimum、Preferred 和 Maximum宽度栏改为25mil。注意你必须在修改Minimum值之前先设置Maximum宽度栏。现在新的规则已经设置,并当你选择Design Rules面板的其它规则或关闭对话框时将予以保存。

11、最后,双击最初的板子范围宽度规则名Width_1,将Minimum, Maximum and Preferred宽度栏均设为12mil。点击OK关闭PCB Rules and Constraints Editor 对话框。
当你用手工布线或使用自动布线器时,所有的导线均为12mils,除了GND和12V的导线为25mils。
在PCB中放置元件
现在我们可以放置右边的元件了。
1、按快捷键V、D将显示整个板子和所有元件。
2、现在放置连接器Y1,将光标放在连接器轮廓的中部上方,按下鼠标左键不放。光标会变成一个十字形状并跳到元件的参考点。
3、不要松开鼠标左键,移动鼠标拖动元件。
4、拖动连接时,按下SPACEBAR将其旋转90°,然后将其定位在板子的左边(确认整个元件仍然在板子边界以内),如图Figure 5所示。

5、元件定位好后,松开鼠标将其放下,注意飞线是怎样与元件连接的。
6、参照Figure 5所示放置其余的元件。当你拖动元件时,如有必要,使用SPACEBAR键来放置元件,这样飞线就如Figure 5所示。
元件文字可以用同样的方式来重新定位——按下鼠标左键不放来拖动文字,按SPACEBAR旋转。在重新定位文字之前,我要在教程以下部分使用Protel DXP强大的批量编辑功能来隐藏元件型号(值),因为这些在最终的板子是不需要的。
Protel DXP具有强大的而灵活的放置工具。让我们使用这些工具来保证四个电阻正确地对齐和间隔。
1、按住SHIFT键,左击选择每一个电阻。在每一个元件周围都将有一个在系统颜色设置的选择颜色的选择块。要改变选择颜色,选择Design » Board Layers。
2、点击元件放置工具中的Align Tops of Selected Components按钮。那么四个电阻就会沿着它们的上边对齐。
3、现在点击元件放置工具中的Make Horizontal Spacing of Selected Components Equal按钮。
4、在设计窗口的其它任何地方点击取消选择所有的电阻。这四个电阻现在就对齐了并且等间距。
修改封装
现在我们已经将封装都定位好了,但电容的封装却比我们要求的太大。让我们将电容的封装改成一小的。
1、首先我们要找到一个新的封装。点击Libraries面板,从库列表中选择Miscellaneous Deivices.IntLib。点击Footprints显示当前库中的可用封装。我们要的是一个小一些的radial 类型的封装,因此在过滤器栏键入rad。点击封装名就会看见与这些名字相联系的封装。其中封装RAD-0.1就是我们需要的。
2、双击电容,将Component 对话框的Footprint 栏改为RAD-0.1。
3、现在你的板子就如下图所示。

每个对象都定位放置好了,现在是放导线的时候了!
手工布线
布线就是放置导线和过孔在板子上将元件连接起来。Protel DXP提供了许多有用的手工布线工具,使得布线工作非常容易。
尽管自动布线器提供了一个容易而强大的布线方式,然而仍然有你需要去控制导线的放置的状况——或者你因为个人喜好而要进行手工布线。在这些状况下,你可以对你的板的部分或全部进行手工布线。在本教程的这部分,我们要将整个板作为单面板来进行手工布线,所有导线都在底层。
现在我们要使用预拉线来引导我们将导线放置在板的底层。
在Protel DXP中,PCB的导线是由一系列直线段组成的。每次方向改变时,新的导线段也会开始。在默认情况下,Protel DXP初始时会使导线走向为垂直、水平或45°角,以使很容易地得到专业的结果。这项操作可以根据你的需要自定义,但在本教程中我们仍然使用默认值。
1、从菜单选择Place » Interactive Routing(快捷键P,T)或点击放置(Placement)工具栏的Interactive Routing按钮。光标变成十字形状,表示你处于导线放置模式。
2、检查文档工作区底部的层标签。TopLayer标签当前应该是被激活的。按数字键盘上的*键切换到底层而不需要退出导线放置模式。这个键仅在可用的信号层之间切换。现在BottomLayer标签应该被激活了。
3、将光标放在连接器Y1的最下面一个焊盘上。左击或按ENTER固定导线的第一个点。
4、移动光标到电阻R1的下面一个焊盘。注意导线是怎样放置的。在默认情况下,导线走向为垂直、水平或45°角。再注意导线有两段。第一段(来自起点)是蓝色实体,是你当前正放置的导线段。第二段(连接在光标上)称作“look-ahead”段,为空心线,这一段允许你预先查看好你要放的下一段导线的位置以便你很容易地绕开障碍物,而一直保持初始的45°/90°导线。
5、将光标放在电阻R1下面的一个焊盘的中间,然后左击或按ENTER键。注意第一段导线变为蓝色,表示它已经放在底层了。往边上移动光标一点,你会看见你仍然有两段导线连接在光标上:一条在下次鼠点击时要放置的实心蓝色线段和一条帮助你定位导线的空心“look-ahead”线段。
6、将光标重新定位在R1的下面一个焊盘上,会有一条实心蓝色线段从前一条线段延伸到这个焊盘。左击放下这条实心蓝色线段。
你已经完成了第一个连接。
7、移动光标将它定位在电阻R4的下面一个焊盘上。注意一条实心蓝色线段延伸到R4。左击放下这条线段。
8、现在移动光标到电阻R3的下面一个焊盘上。注意这条线段不是实心蓝色,而是空心的表示它是一条“look-ahead”线段。这是因为你每次放置导线段时,起点模式就在以水平/垂直和45°之间切换。当前处于45°模式。按SPACEBAR键将线段起点模式切换到水平/垂直。现在这条线段是不实心蓝色的了。左击或按ENTER放下线段。
9、移动光标到电阻R2的下面一个焊盘。你需要再一次按SPACEBAR键来切换线段起点模式。左击或按ENTER放下线段。
10、你现在完成了第一个网络的布线。右击或按ESC键表示你已完成了这条导线的放置。光标仍然是一个十字形状,表示你仍然处于导线放置模式,准备放置下一条导线。按END键重画屏幕,这样你能清楚地看见已经布线的网络。
11、现在你可按上述步骤类似的方法来完成板子上剩余的布线。Figure 6显示了手工布线的板子。

12、保存设计。
在你放置导线时注意以下几点:
1、左击鼠标(或按ENTER键)放置实心颜色的导线段。空心线段表示导线的look-ahead部分。放置好的导线段用层颜色来显示。
2、按SPACEBAR键来切换你要放置的导线的horizontal/vertical 和 start 45° 起点模式。
3、在任何时候按END键来重绘画面。
4、在任何时候按快捷V、F来画面重绘为显示所有对象。
5、在任何时候按PAGEUP 和 PAGEDOWN键来以光标位置为中心放大或缩小。
6、按BACKSPACE键取消放置前一条导线段。
7、在你完成放置导线后或想要开始一条新的导线时右击或按ESC键。
8、你不能将不应该连接在一起的焊盘连接起来。Protel DXP将不停地分析板子的连接情况并阻止你进行错误的连接或跨越导线。
9、要删除一条导线段,左击选择,这条线段的编辑点出现(导线的其余部分将高亮显示)。按DELETE键删除被选择的导线段。
10、重新布线在Protel DXP中是很容易的——只要布新的导线段即可,在你右击完成后,旧的多余导线段会自动被移除。
11、在你完成PCB上的所有的导线放置后,右击或按ESC键退出放置模式。光标会恢复为一个箭头。
祝贺你!你已经手工布线完了你的板设计。
自动布线
要知道使用Protel DXP进行自动布线是如何的容易,完成以下步骤:
1、首先,从菜单选择Tools » Un-Route » All(快捷键U,A)取消板的布线。
2、选择从菜单选择Autoroute » All(快捷键A,A)。
3、自动布线完成后,按END键重绘画面。
多么简单呀!Protel DXP的自动布线器提供与一个有经验的板设计师的同等结果,这是因为Protel DXP在PCB窗口中对你的板进行直接布线,而不需要导出和导入布线文件。
4、选择File » Save(快捷键F,S)保存你的板。
注意自动布线器所放置的导线有两种颜色:红色表示导线在板的顶层信号层,而蓝色表示底层信号层。自动布线器所使用的层是由PCB板向导设置的Routing Layers设计规则中所指明的。你也会注意到连接到连接器的两条电源网络导线要粗一些,这是由你所设置的两条新的 Width 设计规则所指明的。
不要介意在你的设计中的布线与Figure 7所示的不一样;而元件的放置也会不一样,两者都不一样仍然会布线。

因为我们最初在PCB板向导中将我们的板定义为双面板,所以你可以使用顶层和底层来手工将你的板布线为双面板。要这样做,从菜单选择Tools » Un-Route » All(快捷键U,A)取消板的布线。象以前那样开始布线,但要在放置导线时用*键在层间切换。如果你需要改变层时Protel DXP会自动加入过孔。
验证你的板设计
Protel DXP提供一个规则驱动环境来设计PCB,并允许你定义各种设计规则来保证你的板的完整性。比较典型的是,在设计进程的开始你就设置好设计规则,然后在设计进程的最后用这些规则来验证设计。
在教程中我们很早就检验了布线设计规则并添加了一个新的宽度约束规则。我们也注意到已经由PCB板向导创建了许多规则。
为了验证所布线的电路板是符合设计规则的,现在我们要运行设计规则检查(Design Rule Check)(DRC):
1、选择Design » Board Layers(快捷键 L ),确认System Colors 单元的DRC Error Markers 选项旁的Show按钮被勾选,这样DRC error markers才会显示出来。
2、从菜单选择Tools » Design Rule Check(快捷键T,D)。在Design Rule Checker 对话框已经框出了on-line和一组DRC选项。点一个类查看其所有原规则。
3、保留所有选项为默认值,点击Run Design Rule Check按钮。DRC将运行,其结果将显示在Messages面板。当然,你会发现晶体管的焊盘呈绿色高亮,表示有一个设计规则违反。
4、查看错误列表。它列出了在PCB设计中存在的所有规则违反。注意在Clearance Constraint规则下列出了四个违反。在细节中指出晶体管Q1和Q2的焊盘违反了13mil安全间距规则。
5、双击Messages面板中一个错误跳转到它在PCB中的位置。
通常你会在设计板、对布线技术和器件的物理属性加以重视之前设置安全间距约束规则。让我们来分析错误然后查看当前的安全间距设计规则并决定如何解决这个问题。
找出晶体管焊盘间的实际间距:
1、在PCB文档激活的情况下,将光标放在一个晶体管的中间按PAGEUP键放大。
2、选择Reports » Measure Primitives(快捷键R,P)。光标变成十字形状。
3、将光标放在晶体管的中间一个焊盘的中间,左击或按ENTER。因为光标是在焊盘和与其连接的导线上,所以会有一个菜单弹出来让你选择需要的对象。从弹出菜单中选择晶体管的焊盘。
4、将光标放在晶体管的其余焊盘的其中一个的中间,左击或按ENTER。再一次从弹出菜单中选择焊盘。一个信息框将打开显示两个焊盘的边缘之间的最小距离是10.63mil。
5、关闭信息框,然后右击或按ESC退出测量模式,在且V、F快捷键重新缩放文档。

让我们看看当前安全间距设计规则。
1、从菜单选择Design » Rules(快捷键D,R)打开PCB Rules and Constraints Editor 对话框。双击Electrical类在对话框的右边显示所有电气规则。双击Clearance类型(列在右边)然后点击Clearance_1打开它。对话框底部区将包括一个单一的规则,指明整个板的最小安全间距是13mil。而晶体管焊盘之间的间距小于这个值,这就是为什么我们选择DRC时它们被当作违反。
2、在Design Rules面板选择Clearance类型,右击并选择New Rule添加一个新的安全间距约束规则。
3、双击新的安全间距规则,在Constraints单元设置Minimum Clearance为10mil。
4、点击Advanced (Query) 然后点击Query Builder,从Memberships Checks构建query ,或在Query栏键入HasFootprintPad(‘BCY-W3/D4.7’,’*’)。“*”表示名为BCY-W3/D4.7的“任何焊盘”。
5、点击OK关闭对话框。
6、你现在可以从Design Rules Checker 对话框(Tools » Design Rule Check)点击Run Design Rule Check按钮重新运行DRC。应该不会有违反了。
做得好!你已经完成了PCB设计,准备生成输出文档。
设置项目输出
项目输出,如打印和输出文件,是在Outputs for Project 对话框内设置的。
1、选择Project » Output Jobs。Project [project_name] 对话框出现。
2、点击你想要的输出进行设置。如果Configure按钮是激活的(不呈灰色),你就能修改该输出的设置。
3、完成设置后点击Close。
4、如果你要根据输出类型将输出发送到单独的文件夹,则选择Project » Project Options,点击Options标签,再点击Use separate folder for each output type,最后点击OK。

打印到Windows打印设备
一旦PCB的设计和布线都已完成,你就准备生成输出文档。这个文档应该包括一个描述制造信息的生产描图和一个描述元件位置信息的集合描图以及加载顺序(命令)。
要生成这些描图,Protel DXP包含一个精密的打印引擎,这会让你完成打印进程的控制。你可以在打印之前精确地定义你要打印的PCB层的组合、预览描图(称着打印输出)、设置比例、以及在纸上的位置。
现在我们要使用默认输出设置创建一个打印预览,然后修改设置。
1、从PCB菜单选择File » Print Preview。PCB将被分析并且以默认的输出显示在打印预览窗口。点击Close。
2、要检查输出中包括的PCB层的组合,选择Project » Output Jobs。Project [project_name] 对话框出现。从Documentation Outputs单元选择Composite Drawing,点击Configure按钮。PCB Printout Properties 对话框出现。你可以右击菜单选项添加或删除层。点击OK关闭对话框。
3、当我们仍然地Project [project_name] 对话框时,我们要为孔导向组合修改层的参数。选择Fabrication Outputs单元的Composite Drill Drawing,点击Configure按钮。在默认情况下,这个打印输出包括孔导向(一个每个钻孔处都有一个小十字的系统层),和打孔层(在每个钻孔处都有一个唯一表示每种钻孔大小的的特殊符号)。
在一般的打孔图中孔导向层是不需要的,因此删除它,在Printouts  Layers列右击DrillGuide层,从菜单中选择Delete。点击OK关闭对话框。

4、现在点击Print Preview查看打孔图。然后你可以点击Print显示打印机设置,最后点击OK将该图传送到指定的打印机。

5、点击Close关闭打印预览窗口。
6、要修改目标打印机、设置页位置和比例,你可以在Project [project_name] 对话框选择Page Setup(或从菜单选择File » Page Setup)。选择你喜欢的打印机并设置打印机页为Landscape。
7、完成设置后,关闭所有打开的对话框。
生产输出文件
PCB设计进程的最后阶段是生成生产文件。用于制造和生产PCB的文件组合包括底片(Gerber)文件、数控钻(NC drill)文件、插置(pick and place)文件、材料表和测试点文件。输出文件可以在Project [project_name] 对话框(Project » Output Jobs)或通过File » Fabrication Outputs菜单的单独命令来设置。生产文档的设置作为项目文件的一部分保存。
生成底片文件
每一个底片文件对应物理板的一个层——元件丝印、顶层信号层、底层信号层、阻焊层等等。在生成用于生产你的设计的底片(Gerber)和数控钻(NC drill)文件之前,比较合理的作法是向你的PCB制造商咨询以确认他们的要求。
为本教程的PCB创建生产文件:
1、将PCB文档激活,然后选择File » Fabrication Outputs »Gerber files。Gerber Setup 对话框出现。

2、点击OK接受默认设置。底片(Gerber)文件生成并且CAMtastic!打开以显示这些文件。底片文件保存在自动创建在你的项目文件所在文件夹里的Project Outputs文件夹。每个文件夹有与层名相对应的文件扩展名,例如Multivibrator.GTO对应于顶层丝印底片。
材料清单
1、要创建材料清单,首先设置你的报告。选择Project » Output Jobs,然后选择Project 对话框Report Outputs单元的Bill of Materials。
2、点击Create Report。在这个对话框,你可以在Visible和Hidden Column通过拖拽列标题来为你的BOM设置你需要的信息。

3、点击Report…显示你的BOM的打印预览。这个预览可以使用Print按钮来打印或使用Export按钮导出为一个文件格式,如Microsoft Excel 的.xls。
4、关闭对话框。
祝贺!你已经完成了PCB设计进程。
仿真设计
Protel DXP允许你从原理图直接运行一个大型电路仿真的阵列。在本教程的以下部分,我们将仿真由我们的多谐振荡器电路所产生的输出波形。
设置仿真
在我们运行仿真之前,我们需要添加一些物件到我们的电路中:振荡器的电压源;用于仿真的参考地和一些我们希望查看波形的电路点的网络标签。
1、点击窗口顶部的Multivibrator.SchDoc使原理图为当前文档。
2、我们必须再放一个有电压源的连接器。要删除连接器,在连接器体上点击一次选取它,然后按键盘上的DELETE键。
3、这时没有足够的空间来放置电压源,因此我们要移动导线的自由端点。要移动12V导线的垂直端,点击一次导线选取。当小方块编辑点出现时,点击一次导线的自由端的点,然后向上尽可能移动该点到导线改变方向的地方。再点击放下该点。
4、对GND导线的垂直端重复这个进程,将其移动到图纸的底部。
5、选择View » Toolbars » Simulation Sources显示仿真源工具栏。
6、点击仿真源工具栏的+12V source按钮。一个电源符号将悬浮在光标上。按键盘上的TAB键编辑其属性。在出现的对话框中,点击Attributes标签使其激活,并设置Designator为V1。点击OK按钮关闭对话框,然后将这个电源放在12V和GND导线的垂直端点之间。
7、使用你用于移动12V和GND导线部分的垂直端点的相同技巧,再将他们移动到电压源的两个端点,如图Figure 9所示。

我们在运行仿真之前最后的任务是在电路的合适的点放置网络标签,这样我们可以很容易地认出我们希望查看的信号。在本教程电路中,较好的点是两个晶体管的基极和集电极。
1、从菜单选择Place » Net Label(快捷键P,N)。按TAB键编辑网络标签的属性。在Net Label 对话框,设置Net栏为Q1B,然后关闭对话框。
2、将光标放在与Q1基极连接的导线上。参照Figure 9的网络标签的放置。左击或按ENTER将网络标签放在导线上。
3、按TAB键将Net栏改为Q1C。
4、将光标放在与Q2集电极连接的导线上,左击或按ENTER将网络标签放在导线上。
5、同样地,将Q2B 和 Q2C网络标签放在Q2的基极和集电极导线上。
6、完成网络标签的放置后,右击或按ESC退出放置模式。
7、保存准仿真电路为与原原理图不同的文件名,选择File » Save As在Save As 对话框键入Multivibrator simulation.SchDoc。
运行瞬态特性分析
你的原理图现在已经具备所有必备的条件了,因此让我们设置一个电路瞬态特性分析。在我们的教程电路中,RC时间常数为100k x 20n = 2 ms 。要查看到振荡的5个周期,我们就要设置看到波形的一个10ms部分。
1、选择菜单的Design » Simulate » Mix Sim显示Analyses Setup 对话框。所有的仿真选项均在此设置。

2、首先我们要设置你希望观察到的电路中的中心点。在Collect Data For栏,从列表中选择Node Voltage and Supply Current。这个选项定义了在仿真运行期间你想计算的数据类型。
3、在Available Signals栏,双击Q1B、 Q2B、 Q1C 和 Q2C信号名。在你双击每一个名称时,它会移动到Active Signals栏。
4、为这个分析勾选Operating Point Analysis 和 Transient/Fourier。如果Transient/Fourier Analysis Setup没有自动显示,点击Transient/Fourier analysis名称。
5、将Use Transient Defaults选项设为无效,这样瞬态特性分析规则可用。

6、要指定一个10ms的仿真窗口,将Transient Stop Time栏设为10m 。
7、现在设置Transient Step Time栏为10u,表示仿真可以每10us显示一个点。
8、在仿真其间,实际的时间间隔是自动随机获取的一簇。在Maximum Step栏限制时间间隔大小的随机性,设置Transient Max Step Time为10u 。
现在准备运行瞬态特性分析。
1、点击Analyses Setup 对话框底部的OK按钮运行仿真。
2、仿真执行后,你将看见与图Figure 10所示相似的输出波形。

祝贺你!你已经完成的电路仿真,并显示了它的输出波形。
如果你喜欢,你可以改变一些原理图中元件参数,再运行仿真看看其变化。试着将C1的值改为47n(双击C1编辑其属性),然后再运行瞬态特性分析。输出波形将显示一个不均匀的占空比波形。



作者: suncon    时间: 2003-4-8 05:39
标题: 单片机技术!!!
PROTEL 99 简明使用手册

Protel 99内容简介

  Protel 99采用全新的管理方式,即数据库的管理方式。Protel 99 是在桌面环境下第一个以独特的设计管理和团队合作技术为核心的全方位的印制板设计系统。所有Protel99设计文件都被存储在唯一的综合设计数据库中,并显示在唯一的综合设计编辑窗口。
  Protel 99软件沿袭了Protel以前版本方便易学的特点,内部界面与Protel 98大体相同,新增加了一些功能模块。Protel公司引进了德国INCASES公司的先进技术,在Protel99中集成了信号完整性工具,精确的模型和板分析,帮助你在设计周期里利用信号完整性分析可获得一次性成功和消除盲目性。Protel99容易使用的特性就是新的“这是什么” 帮助。按下任何对话框右上角的小问号,然后选择你所要的信息。现在可以很快地看到 特性的功能,然后用到设计中,按下状态栏末端的按钮,使用自然语言帮助顾问。

第一章 Protel 99的安装

  Protel 99 设计平台软硬件配置要求:
1、硬件配置     
  最低:ntium II 233MHZ
      内存-32M
     硬盘-300M 显示器-SVGA,15〃          
     显示分辩率-800×600
  建议配置:CPU-Pentium II 300 以上          
     内存-128M 硬盘-6G以上          
     显示器-SVGA,17〃以上     
     显示分辩率-256色,1280×768
  只要是1998年以后所成立的计算机教室,或个人购买的计算机,几乎都超过以上标准!而现在几乎不可能买到这么差的个人计算机了。所以,这个要求也不算太高嘛!当然,愈好的设备易展现Protel99的雄风。
2、操作系统
   Microsoft Windows NT 4.0 或以上版本(含中文版)。
   Microsoft Windows 98/95 或以上版本(含中文版)。          PROTEL99 安装方法非常简单,只需双击光盘目录下的Install.exe即可。

第二章 如何进行原理图设计

一、 新建设计数据库文件

  在WINDOWS 95/98或NT界面下双击Protel 99 图标,点击File(文件)中new项,新建设计 数据库。
  在Browse选项中选取需要存储的文件夹,然后点击OK即可建立自己的设计数据库。

1、设计组(Design Team)
  我们可以先在Design Team 中设定设计小组成员,Protel 99可在一个设计组中进行协同 设计,所有设计数据库和设计组特性都由设计组控制。定义组成员和设置他们的访问权 限都在设计管理器中进行,确定其网络类型和网络专家独立性不需要求助于网络管理员 。
  无限制数量的设计组成员能同时访问相同的设计数据库。每个组成员都能看到什么文件 当前是打开的以及谁在编辑,并能锁定文件以防止意外重写。
  访问设计数据库可以通过建立设计组成员和指定其权限来控制。设计组成员建立在成员 文件夹中。在成员文件夹中单击右键就会弹出浮动菜单,选择新成员。 为保证设计安全,为管理组成员设置一个口令。这样如果没有注册名字和口令就不能打 开设计数据库。
  提示:成员和成员权限只能由管理员建立。

2、回收站( Recycle Bin) 
  相当于Windows 中的回收站,所有在设计数据库中删除的文件,均保存在回收站中,可 以找回由于误造作而删除的文件.

3、设计管理器(Documents)   
   所有Protel99设计文件都被储存在唯一的综合设计数据库中,并显示在唯一的综合设计 编辑窗口。在Protel99中与设计的接口叫设计管理器。使用设计管理器,可以进行对设计文件的管理编辑、设置设计组的访问权限和监视对设计文件的访问。
  组织设计文件 过去组织和管理40个或更多的原理图、PCB、Gerber、Drill、BOM和DRC文件,要花 费几天的时间,而Protel99把设计文件全部储存在唯一的设计数据库。
  在设计数据库内组织按分层结构文件夹建立的文件 显示在右边的个人安全系统设计数据库有一文件夹叫设计文件,这个文件夹中是主设计文件(原理图和PCB),还有许多的子文件夹,包括了PCB装配文件、报告和仿真分析。这里对在设计数据库中创建文件夹的分 层深度没有限制。
  设计数据库对存储Protel设计文件没有限制 你能输入任何类型的设计文件进入数 据库,如在MS Word书写的报告、在MS Excel准备的费用清单和AutoCAD中制的机械图。简单双击设计数据库里的文件图标,在适当的编辑器打开文件,被更新的文件自动地保存到设计数据库。MS Word和Excel文件可以在设计管理器中直接编辑。
  提示:在文件夹上单击右键会显示浮动菜单,然后选择在设计数据库新建文件。   
  在综合设计数据库中用Protel99的设计管理器管理设计文件是非常轻松的。设计管 理器的工作就象MS Windows的文件管理器一样,可用它来导航和组织设计数据库里文件 。使用设计管理器在设计数据库创建分层结构的文件夹,使用标准文件操作命令来组织 这些文件夹内设计文件。
  设计管理器的心脏就是左边的导航面板。面板显示的树状结构是大家熟悉的Protel软件 特性。在Protel99中,这个树不仅仅显示的是一个原理图方案各文件间的逻辑关系,它 也显示了在设计数据库中文件的物理结构。    在导航树中活跃的文件夹是PCB装配文件夹。如同Windows文件管理器,设计管理器在右 边显示这个文件夹的内容。
  设计管理器与Windows文件管理器的不同之处是在右边还显示已经打开的文件。
  打开文件 只要在导航树中单击所要编辑的文件名,或者双击右边文件夹中的图标。
  在设计数据库中打开的各个文件用卡片分隔显示在同一个设计编辑窗口,使得非常容易 知道当前工作到哪里,特别在大的设计中。要一起观察不同的文件可以将设计编辑窗口拆分为多区域。

二、打开和管理设计数据库
  
  Protel 99 包括许多设计例子,我们下面可以举例说明。 选择文件打开菜单\Design Explorer 99\Example \folder,点击photoplotter.ddb文 件,左侧窗口呈现树状结构。
  点"+"呈现下一层子目录或文件,点"-"将关闭此文件夹.点Photohead.pcb 文件 ,PCB版图将出现,点Photohead.prj,原理图管理文件将被打开.关闭文件,可以用鼠标 右键,选择Close.也可以用CTRL+F4来关闭。

三、观看多个设计文档

  打开Photoplotte.ddb设计数据库,点"+"找到Electronics 和Photohead文件夹,打 开Photohead Parts list 设计窗口,用同样方法打开Photohead.pcb文件和Photohead. prj文件.在Photohead Parts List窗口下击鼠标右键,选择"Split Horizontal菜单 ,界面将被水平分割。在Photohead.prj设计窗口下点右键,选Split Vertical 菜单。 界面将被垂直分割.可以用鼠标调整分割窗口的大小。要想分割更多的窗口,可重复上 述操作。
  按Ctrl+Tab可循环切换打开的设计文件,按Shift+Tab可在导航板和设计窗口中有效文件 夹的内容间切换。

四、多图纸设计  

   一个原理图设计有多种组织图纸方案的方法。可以由单一图纸组成或由多张关联的图纸 组成,不必考虑图纸号,SCH99将每一个设计当作一个独立的方案。设计可以包括模块化 元件,这些模块化元件可以建立在独立的图纸上,然后与主图连接。作为独立的维护模 块允许几个工程师同时在同一方案中工作,模块也可被不同的方案重复使用。便于设计 者利用小尺寸的打印设备(如激光打印机)。下面举例说明:打开LCD Controller.ddb 设计文件,打开LCD Controller.prj原理图设计窗口。我们看到许多绿色矩形框,叫做 原理图模块,每一个原理图模块里包含一张图纸,一个总的原理图可以包含多个子原理 图。选择Design下的Create Sheet From Symbols 由符号生成图纸,如果已经画好 原理图,选择Design下的Create Symbol Form Sheet由图纸生成符号。利用工具条 上的↑↓点取输入端口,可以在总的原理图与子原理图之间切换。

五、原理图连线设计

  确定起始点和终止点,Protel99就会自动地在原理图上连线,从菜单上选择Place/Wir e后,按空格键切换连线方式,自动连线、任意角度、45°连线、90°连线,使得设计 者在设计时更加轻松自如。只要简单地定义AutoWire方式。自动连线可以从原理图的任 何一点进行,不一定要从管脚到管脚。

六、检查原理图电性能可靠性

  打开LCD Controller.ddb 设计数据库,点取LCD Controller 文件夹下的LCD Cont roller.prj原理图设计窗口,Protel99可以帮助我们进行电气规则检查.选择Tools下面 的ERC,在Rule Matrix种选择要进行电气检查的项目,设置好各项后,在Setup Ele ctrical Rlues Check对话框上选择OK即可运行电气规则检查,检查结果将被显示到 界面上。

七、同步设计

  在Protel99中使得原理图与PCB同步是容易的。Protel99包含一个强大的设计同步工具, 使得非常容易地在原理图和PCB之间转移设计信息。
  同步设计是更新目标文件的过程,它基于参考文件中上一次的设计信息。当你执行同步 时,通过以下选择告诉它要转换的方向:
  从原理图到PCB的更新
  从PCB到原理图的更新
  同步设计执行设计信息的初始化转移,还有正向和反向标注处理、替换创建的网络表-加 载网络表顺序、反向标注-在PCB设计中习惯使用的重标注顺序。
  同步器是如何工作的? 当执行同步设计时,同步器分析原理图和PCB,识别两者之间的差异。设计同步器创建一 个宏来解决所发现的每个差异。当需要时,这些宏能被预览。当按执行按钮时原理图和 PCB被自动地重新同步。
  要确保同步无误,设计同步器赋于原理图和PCB对应元件唯一的匹配标识符。这就意味着 可以任意对原理图和PCB分别进行标注。只要简单地从设计菜单运行更新命令,随时都可 以协调两边的工作。
  当选择从原理图更新,同步器做一个预分析检查,查找如:无封装的元件、重复或未指 定的元件以及可使用的PCB库。如果检测出问题,在更新设计对话框中将出现一个问题警 告表,注意它,并检查问题。
  注意:如果你输入已存在的设计,第一次同步时将出现确认元件对话框。一旦元件已赋 于匹配标识符,在以后的同步中将不再出现。   包含PCB设计要求的原理图   同步器也能将原理图中PCB设计要求信息转换到设计规则中。这允许设计工程师在原理图 中精确地指定重要网络的布线要求-当PCB设计者开始布线时,这些网络将自动地按照工 程师的设计要求执行。要在原理图包含设计信息只要简单给网络附加一个PCB设计指令。
  提示:指令的底部必须紧靠着网络。
  原理图与PCB的匹配 当你第一次执行同步器时你甚至不需要创建PCB文件。如果同步器不能找到合适的PCB, 它会自动地创建一个,整齐地在PCB工作区中间排放所有的元件,作好布局准备。如果在 设计数据库同名文件夹有PCB,将被使用。   

八、建立材料清单

  打开4Port Serial Interface.ddb 设计数据库,找到4 Port Serial Interface 文件夹下面的4 Port Serial Interface.prj文件设计窗口,选择Reports中的 Bill Of Material菜单,按照导向器所给选项选择,完成选择,一个Excel风格的材 料清单将被制成。   

九、原理图仿真

  Protel99的混合信号电路仿真引擎现在与3F5完全兼容,支持所有标准的SPICE模型。电 路仿真支持包含模拟和数字元件的设计。SimCode(类C语言)用于描述数字元件的描述 。
  Protel99提供了大量的仿真用元件,每个都链接到标准的SPICE模型。5800个仿真用元件 分别在Sim.Ddb数据库的28个库中。在Protel99中执行仿真,只要简单地从仿真用元件库中放置所需的元件,连接好原理图 ,加上激励源,单击仿真。
  提示:通用元件、电压和电流源,在Sim.Ddb的仿真模型库中。
  打开Bandpass Filter.ddb设计数据库,找到Design Explorer 99\Examples\Circu it Simulation文件夹.点击交流信号分析~,输入输出波行将显示到界面上。将鼠标 放到OUT上,击鼠标右键,选择View Single Cell菜单,观看单一的输出波形。激活 原理图设计窗口,选择View下的Fit All Objects选项,使图形全屏显示,找到元件 C1,并双击此元件,这个元件的类型和属性对话框将出现,将Part设置为0.2uF,然 后重复上述操作,设置C2器件。选择Simulate下的Setup菜单,在General对话 框上选择Keep Last Setup,然后运行分析菜单Run Analyses,波形将被改变。   

十、 在原理图上标注汉字或使用国标标题栏

  在原理图上放汉字,可以直接点击Place选乡下的Annotation放置汉字。 如果想要使用国标图纸做标题栏,选择Design下的Template里Set Template File,找到国标标题栏所在的目录,打开图纸的标题栏将被切换为国标形式。   

十一、 生成网络表

  当我们设计好原理图,在进行了ERC电气规则检查正确无误后,就要生成网络表,为PCB布线 做准备。网表生成非常容易,只要在Design下选取Create Netlist对话框,设置为 那种格式的网络表。网表生成后,就可以进行PCB设计了。    

第三章 PLD设计

  Protel Advanced PLD是融合于Protel集成开发环境的一个高效、通用的可编程逻辑器件设计工具,为逻辑器件设计提供了许多方便快捷的设计手段。
  Protel Advanced PLD包含三个专为PLD设计工作定制的EDA/Client服务器:文本专家─ 具有语法认识功能的文本编辑器;PLD─ 用来编译和仿真设计结果;Wave─ 用来观察 仿真波形。
  具体特点如下
  1、方便的文本专家和语法帮助器;
  2、支持多种设计描述方法: 布尔方程式、状态机和真值表;
  3、支持从原理图输入并直接编译;
  4、支持从原理图输入PLD设计,并对原理图直接进行编译,生成标准的JEDEC文件;
  5、与器件无关的高级CUPL硬件描述语言;
  6、快速强大的编译器;
  7、方便直观的仿真波形编辑器;
  8、产生JEDEC工业标准的下载文件;
  9、广泛的器件支持。   
  举例:打开\Design Explorer 99\Examples\pld\LCD Driver.ddb 设计数据库,找到LCD.s ch原理图文件并打开,这张原理图显示的是G22V10驱动电路。选择PLD下的Confi gure菜单,我们看到G22V10已经被选中在目标栏中。点OK即可。选择PLD下的C ompile,当编译完成后,我们可以选择View Files项检查编译结果,然后点取Close 关闭编译对话框输出文件。

第四章 PCB设计

一、板框导航

  当我们设计了原理图,生成了网表,下一步就要进行PCB设计。首先要画一个边框, 我们可以借助板框导航,来画边框。在File下选择New中的Wizards,在选取Prin ted Circuit Board Wizard,点击OK即可,按照显示对话框的每一步提示,完成板框 设计。   

二、建立PCB文件

  要进行PCB设计,必须有原理图,根据原理图才能画出PCB图。按照上述板框导航生成一 张IBM XT bus format形式的印制板边框。选择PCB设计窗口下的Design中的Add/R emove Library,在对话框上选择4 Port Serial Interface.ddb,在\Design Explo rer 99\Examples文件夹中选取,点取Add,然后OK关闭对话框。在左侧的导航树上 ,打开4 Port Serial Interface.prj原理图文件,选择Design下的Update PCB, 点取Apply,Update Design对话框被打开,点取Execute选项。对话框Confirm C omponent Associations对话框将被打开,网络连接表列出,选择应用Apply更新PCB 文件,由于Protel99采用同步设计,因此,不用生成网表也可以直接到PCB设计。这时, 一个新的带有网络表的PCB文件将生成。   

三、布局设计

  Protel 99可以进行自动布局,也可以进行手动布局。如果进行自动布局,运行Tools下 面的Auto Place,用这个命令,你需要有足够的耐心。布线的关键是布局,多数设计者 采用手动布局的形式。用鼠标选中一个元件,按住鼠标左键不放,拖住这个元件到达目 的地,放开左键,将该元件固定。Protel 99在布局方面新增加了一些技巧。新的交互式 布局选项包含自动选择和自动对齐。使用自动选择方式可以很快地收集相似封装的元件 ,然后旋转、展开和整理成组,就可以移动倒板上所需位置上了。当简易的布局完成后 ,使用自动对齐方式整齐地展开或缩紧一组封装相似的元件。
  提示:在自动选择时,使用Shift+X或Y和Ctrl+X或Y可展开和缩紧选定组件的X、Y方向。   

四、布线设计

  在布线之前先要设置布线方式和布线规则。Protel 99有三中布线方式:忽略障碍布线( Ignore obstacle),避免障碍布线(Avoid obstacle),推挤布线(Push obstacle)。 我们可以根据需要选用不同的布线方式,在Tools工具菜单下选择Preferences优选 项中选择不同的布线方式。也可以使用SHIFT+R快捷键在三种方式之间切换。
  接着选择布线规则,在Design下选择Rules对话框,选择不同网络布线的线宽,布线 方式,布线的层数,安全间距,过孔大小等。
  有了布线规则,就可进行自动布线或手动布线了。如果采用自动布线,选择Auto Rout e菜单,Protel 99支持多种布线方式,可以对全板自动布线,也可以对某个网络、某个 元件布线,也可手动布线。手动布线可以直接点击鼠标右键下拉菜单Place track,按 鼠标左键一下确定布线的开始点,按BACKSPACE取消刚才画的走线,双击鼠标左键确定 这条走线,按ESC退出布线状态。用Shift加空格键可以切换布线形式,45°90° 弧形布线等方式之间切换。
  Protel99提供了很好的在线检查工具Online DRC随时检查 布线错误(在工具菜单的优选项下面)。如果修改一条导线,只需重画一条线。   

五、电气规则检查

  当一块线路板已经设计好,我们要检查布线是否有错误,Protel99提供了很好的检查工具DRC 自动规则检查。只要运行Tools下的Design Rlue Check,计算机会自动将检 查结果列出来。   

六、信号完整性分析

  当PCB设计变得更复杂,具有更高的时钟速度、更高的器件开关速度以及高密度,在设计 加工前进行信号的完整性分析变得更尤为重要。       Protel99包含一个高级的信号完整性仿真器,它能分析PCB设计和检查设计参数的功能, 测试过冲、下冲、阻抗和信号斜率要求。如果PCB板任何一个设计要求(设计规则指定的 )有问题,可以从PCB运行一个反射或串扰分析,以确切地查看其情况。 信号完整性仿真使用线路的特性阻抗、通过传输线计算、I/O缓冲器宏模型信息,做为仿 真的输入。它是基于快速的反射和串扰模拟器,采用经工业证实的算法,产生非常精确 的仿真。
  设置信号完整性设计规则:打开LCD Controller.ddb设计数据库,在Design Explorer 99\Examples目录下,通 过左侧的导航树,打开LCD Controller.pcb文件。设置信号完整性设计规则,测试的 描述。必须包含层堆栈规则。在Tools下选择Preferences对话框中的Signal Inte grity选项,在这个对话框中,显示了所有元件的标号所代表的元件名称。例如 R代 表resistors,用Add增加,在Component Type对话框上,用R设置Designator Prefix,在Component Type中设置为Resistor,点击OK加入。重复上述操作设置 C-Capacitor&#59; CU-Capacitor&#59; Q-BJT&#59;D-Diode&#59; RP-Connector&#59;U-IC;J-Connector&#59;L-i nductor,当我们设置完成时,点取OK退出优选项对话框。
  从菜单中选择Design\Rules,然后按下设计规则对话框中的信号完整性钮。每个规则 包含了该规则测试的描述。
  一旦配置了信号完整设计规则,从菜单中选择Tools下的Design Rule Check,显示设计规则检查对话框。按对话框中央的信号完整性按钮,进行信号完整性设计规则检查 。
  必须包含一个层堆栈规则才能执行信号完整性分析。包含电源网络设计规则,指定每个电源网络和电压。从Rule Classes中选Overshoot Falling Edge点击Add,在谈出对话框中选择Fiter Kind设为Whole Board,并且 改变右侧Maximum(Volts)为0.5,点取OK,存入这条规则。重复刚才的步骤,设置 Undershoot-Falling Edge,两个强制信号完整性规则Layer Stack Supply Nets已经设置。
  运行设计规则检查DRC,然后在Report中运行Signal Integrity,找到网络名为FR AMA1,选重这个网络,在Edit中选Take Over从菜单中加入网络,对它进行分析。在 Simulation的Reflection菜单下可以观看波形。我们选种哪一个器件,那个器件的 曲线将被点亮。信号完整性分析菜单中还为我们提供消除干扰的方法。 如果设计不包含电源层分析将仍然执行,但是结果不能认为是准确的。 信号完整性分析器不考虑多边形敷铜。DRC测试是从所有可能输出脚对每个网络最坏情况 仿真,最坏结果就是DRC结果。 执行串扰分析至少需要从网表上确定二个网。然后指定其中一个为侵略者,或受害人。 侵略者被加入激励脉冲,受害人为接收串扰。当已经指定侵略者或受害人网络时,按Cr osstalk按钮执行仿真,结果将显示在Protel波形分析器上。可以从波形上直接执行许多测量,仅仅击一下波形右边列表上的节点,从分析菜单中选 择一个选项。如果你发现波形与设计规则检查给定的结果不匹配(例如:DRC给1.2伏特的过冲,但是波 形有小的振铃),它被大概因为用于反射分析的输出节点不是DRC报告的最坏节点。 除了执行反射和串扰分析,还可以执行一个信号完整性效果的网络筛选,例如过冲、延迟、阻抗等等。网络筛选产生类似电子表格的结果表,可以快速查出有问题的网络。 执行网络筛选,要指定许多网络(如果需要可选全部),按Net Screening按钮。当筛选结 果出现,使用工具条上按钮控制所要显示的内容(阻抗、电压等等),按下列名按结果类 型显示。   

七、建立新的PCB器件封装

  由于硬件厂家发展速度非常快,器件的不断更新,我们经常需要从库里增加器件封 装,或增加封装库。Protel 99提供了很好的导航器,帮助我们完成器件的添加。打开 LCD Controller.ddb设计数据库,选中LCD Controller.pcb并打开。在Design下选 择Make Libray,库编辑器被打开,建立一个新 5yt4w库文件lcd controller.lib,在这个新 库文件中建立器件封装。点击左侧导航树上的Browse PCBlib,可以浏览这个库里现有 的元件,创建一个新的元件选择Tools下的New Component,弹出一个器件封装模板 ,按照提示,可以迅速生成一个我们需要的器件封装。   

八、生成GERBER文件

  在我们将所有设计完成之后,需要把PCB文件拿到制版厂家去做印制版。如果厂家有Protel 98 或Protel 99,可以直接导出 PCB文件给厂家。如果厂家没有这两种版本文件,需生成GERBER给厂家。具体操作如下:
  首先我们打开一个设计好的PCB文件Z80 Microprocessor.ddb设计数据库中的Z80 Pr ocessor board.pcb文件,选择File主菜单下的Setup Printer,点亮第一项Prot el Gerber RS274 在Option弹出菜单中选择建立光圈文件,点击Aperture Library选项,在Apertures对话框中选Creater List From PCB,自动抽取光圈文件 。在Save to APT File中存一个文件名。返回Setup Printer菜单,点取Layers设 置输出光绘文件的层数,在所有用到的层前打对勾√,然后选择OK返回打印机设置 ,按下Print,就可生成光绘文件。
  设置光圈文件。
  设置光绘层数。
  在Report主菜单下选择NC Drill,运行后即可生成钻孔刀具和钻孔数据文件。 光圈文件的后缀为*.APT,GERBER文件的后缀为*.G*,钻孔文件的后缀为*.DRR和* .TXT。将所有文件导出到一个指定目录下,压缩后即可交给印制板厂生产。 如果我们想看生成的GERBER文件是否正确,请用导入的方法可以打开每一层文件。 设计者也可以用导入的方法查看其它低版本的文件,例如Protel 2.8格式,98格式,DOS格式等文件。
  
Protel绘图经验谈
苏锡锋
笔者使用protel多年,积累了一些用其绘制电路图的使用经验和技巧,现将这些经验和技巧成文,希望对大家用protel绘制电路图有所帮助。
经验一:
  因为protel是专业电路设计软件,可供电子类各专业设计人员和广大电子爱好者使用,所提供的零件库包含了相当全面的元器件符号图。所以零件库数量很多,零件的数量更多,使初学者不知该到哪个零件库中去寻找所需的元器件。根据笔者的经验,载入protel的Schematic中的DEVICE.LIB和SYMBOLS.LIB可满足一般用户需求,两个零件库中含有二极管、三极管、电阻、电容、电感等常用元件。
经验二:
  为了使用方便可将常用元件符号按汉字习惯名称命名。下面以电容为例说明具体命名方法:在元件编辑程序中找到电容的编号CAP,这时编辑区中可看到电容的电路符号图,group框中有电容的编号CAP,单击group框下的Add键出现命名新名对话框如图1所示。输入新名:电容,然后按OK键完成电容符号命名。可依同样方法完成三极管、二极管、电阻、电感等常用元件编号的重新命名。因为元件名称在元件库内容框中的排序是数字、字母、汉字,使用汉字命名元件名称可将新名称元件排列在元件内容的最后且在一起,寻找元件非常方便。返回Schematic环境前不要忘记存盘,否则前期命名工作将劳而无功。在电路图中放置元器件时,原来是通过单击Schlib标签或EDIT按钮转换到零件库编辑程序中查看编号所对应的电路符号,寻找所需元件。若你完成了常用元件的汉字命名工作就省略了此步,直接单击选中所需元件的汉字名称。由此可看出,采用前面介绍的元件编号的汉字重新命名方法可节省寻找时间,使摆放元件符号的效率提高数倍。
经验三:
  元件摆放完成后的工作是进行导线连接。软件提供格、点两种格式的栅格,这一格式使你摆放导线和元件时上下左右移动必须以一个栅格为最小移动单位,元件容易摆放整齐,使你画的图纸规范(导线横平竖直)。当然,栅格格式是可选项,其默认值是栅格状态,在连接导线和摆放元件时劝你不要试图取消此项功能,否则会自找麻烦,增加绘图难度。
经验四:
  通常绘制电路图的最后一项工作是编辑零件名称,包含放置元件的名称、序号、数值、管脚编号、管脚功能等,若要输入汉字名称可启动汉字输入法进行输入,根据笔者的使用经验,在你完成汉字名称输入后按OK键之前请先退出汉字输入法,否则经常会发生死机现象。这种现象的出现可能是英文版软件与汉字输入法不兼容而引起,如果绘制的图纸未存盘将前功尽弃,绘图工作不得不从头作起。所以奉劝读者养成绘图过程中随时存盘的习惯,尤其是在编辑零件名称前一定要进行存盘处理防止死机,节省绘图时间。
经验五:
  完成所有摆放元件的名称编辑时,你会发现一些名称的位置不合适并且无法放到合适的位置,原因是软件默认状态为栅格状态,所以零件名称的摆放位置只能以栅格为移动单位。当你需要放置到栅格中位置才能使图纸美观时,可将栅格状态暂时取消,摆放后恢复,方法是找到View菜单中的Snap Grid项用鼠标左键单击即可取消栅格状态,完成各零件名称编辑摆放工作后恢复栅格状态,该键为复选键,处于选中状态时单击一次为取消,再单击一次为选中。
经验六:
  电路图绘制完成后,读者可使用Schematic预置图纸格式打印,也可随需要自定义图纸格式打印。若要提高打印图纸的清晰度,可将栅格和底色清除,底色的清除方法是在Sheet项中设定图纸的底色为白色;去掉栅格的方法是将图2对话框Grids区块中Visible项清除(默认状态为选中)。这时就可打印出清晰并且带有图框、分区和标题栏的标准图纸。如选用标准图纸打印出的图纸尺寸大小不合适可用自定义方式设定图纸尺寸,不管是标准还是自定义图纸都可使用Schematic软件的自动缩放打印功能,选用了此项功能程序会将电路图缩放到刚好容纳于图纸中,在图3所示对话框中的Scale区块中的Scale to fit page 项就是自动缩放功能选择项,默认为选中。%号左边显示出电路图在图纸中占的比例,在这里读者应了解所占比例的含义,它包含了两种图纸尺寸的设定:电路图图纸尺寸与打印机纸张尺寸,当打印机纸张尺寸确定且选用了自动缩放功能,其所占比例大小只与两种图纸的宽高比例是否一致有关,与电路图图纸尺寸无关,当两种图纸的宽高比例一致时最大。
经验七:
  打印普通电路图(普通电路图指产品说明书、插图等,它不需图框和标题栏)时,将图2中Show Reference Zone、Show Border、Title Block项全选掉。其中Show Reference Zone为显示分区坐标项、Show Border为显示图框项、Title Block为显示标题栏项。这时观看所画电路图是否充满图纸,若恰好充满图纸就可选掉栅格和底色后直接打印或通过剪贴板加入文件中。但一般情况是所画电路图仅占图纸的一部分,如果直接打印就使电路图在图纸中所占比例很小,加入文件时位图较大。改进方法是在使用前将图纸中未画电路图的多余部分剪裁掉。具体做法是将图纸的底色设置为深颜色,如深绿色。电路图全选中以便整体移动电路图,图纸用深色是为了移动电路图时容易看清图纸,然后选用自定义图纸方式,调整图纸宽度和高度使所画电路图恰好充满图纸,调整图纸宽度和高度需反复几次才能完成,每次调整数值后以电路图与图纸不分离为限,若两者分离电路图将不能移进图纸。调整完成后取消栅格和底色就可打印出最大比例的电路图,并使加入文件时的位图最小。标准图纸格式的调整方法同上,只是加上了图框和标题栏,但在缩小图纸后应防止电路图与标题栏重合。
经验八:
  在电子产品电路图中绘出各关键点的信号波形图是电路图可读性与实用性的需要。由于电路中各种信号形态各异,历来是电路图绘制中的难题,如再考虑非线性失真状态下的不对称波形,更增加了绘画工作的难度。protel提供有一组普通绘画工具,但很少被电路图绘制者关注。而笔者使用该组工具不仅绘出了各种对称、非对称电信号波形,而且还结合软件中镜像、栅格、复制等功能为电工、电子、物理类教科书、实验指导书绘制了很多插图。下面就以正弦波、充放电波形为例介绍特殊波形电信号的绘制方法和经验。
  protel提供的普通工具组及功能按钮说明如图4所示。首先来画正弦波,正弦波应由曲线绘制,通常每一条曲线是由4个点所构成,选取4个点后即完成一条曲线。正弦波的画法有两种:一种是整体画,也就是正负半周一起画,具体操作是用鼠标左键单击画曲线工具按钮即进入画曲线状态,这时鼠标箭头上将多出一个十字状光标,移动光标依次选取4点,选取原则是依据栅格使1、4点在一条直线上(也可画一个坐标,1、4点同在水平坐标轴上),要根据正弦波波形对称与不对称来选取2、3点为对称点或不对称点。点的选取方法是将光标移到选定位置单击鼠标左键,选后如图5所示。若对所画波形不满意可用鼠标左键单击曲线任一部位使之出现操控点,用鼠标左键拖动操控点2或3上下左右移动到波形满意即可。此法的优点是画图简单,适用于正负半周波形差别不大的正弦波。另一种画正弦波的方法是正负半周分开画,以解决正负半周波形差别大但半周期相同的正弦波信号绘制问题,因前法拖动操控点2或3上下左右移动时相互间有牵连,会使半周期失去平衡。按这种方法选取4个点后如图6所示,从图中可看出除了点3、4合在一起外与前法相同,移动操控点2可使曲线符合要求,将分别绘制的正、负半周波形合在一起就能完成正、负半周期对称而波形差别较大的正弦波波形的绘制。比如图7为充放电波形,按该图下方的方法选取4个点后得到的一个波形,将它复制放置时利用镜像,即按Y键将波形图上下翻转后放于图中,即得到了充放电波形图。
  图书推荐:关于protel的具体使用方法,如安装步骤、电路原理图的设计与绘制、网络表的生成和印制板的设计等详细的知识,读者可参考《电路设计与制版—protel99入门与提高》和《protel99实用培训教程》,购书办法见本期第17页,读者还可访问 http://www.pptph.com.cn/ ,以查阅相关书籍的详情。


作者: iceingheart    时间: 2008-5-13 10:32
标题: 请教 suncon关于DXP仿真的问题
您好!
在仿真的时候,硬件电路要求加入汇编程序才能仿真,请问怎么办才能使电路和程序来联系起来,具体该怎么仿真?
谢谢!
作者: diaoke2417    时间: 2008-6-13 18:34

作者: zjj623623    时间: 2008-6-30 15:53






欢迎光临 光电工程师社区 (http://bbs.oecr.com/) Powered by Discuz! X3.2