发 帖  
原厂入驻New

单片机指令系统:单片机自学(四)

2008-10-15 13:02:43  2525
分享

单片机指令系统:单片机自学(四)

通过上几课的学习我们对单片机的结构和一般的指令及汇编语句的格式已有了解,可以进行简单的程序设计,如:发光二极管的循环点亮,但要设计一个较好的程序,还要有方法;

程序设计的步骤与方法
一、汇编语言程序设计步骤
  程序是指令的有序集合。编写一个好的程序,正确性是主要的,但整个程序占内存的空间大小、每条指令的功能、长度、执行时间等都要考虑,使其较佳。
    一般常用的步骤:
    1、分析课题,确定算法或解题思路;
    2、根据算法或思路画出流程图;
    3、根据流程图编写程序;
    4、上机调试源程序,进而确定源程序。

 一个复杂的程序一般有:直接程序(监控程序)、分支程序、循环程序、特定功能的子程序等组成。
二、程序设计的一般方法
    1、对于一个复杂的程序可以按功能的不同分为不同的模块、按模块功能确定结构;
    2、分段编写程序,可采用:自底向上、自顶向下两种方式。

三、编写程序时还要用到伪指令;如上面写的ORG 0000H、DB 09H,78H;

    伪指令语句主要是为汇编程序服务的,在汇编过程中起控制作用。在程序编译时不产生目标代码;

    如:PLACE   DB   01H;它告诉汇编程序PLACE定义一个字节,所以汇编程序要为它分配一个存储地址,并把01H放入与PLACE相联系的存储单元中。
    如:THING : DW 1234H;它告诉汇编程序THING定义一个字,汇编程序把1234H放入THING单元中。DW伪指令的一般通式为: DW   Xi   
    Xi 为双字节的十进制或十六进制数,常用来定义地址表。
    如:ORG   4000H;它告诉汇编程序该程序编译成机器语言程序的起始地址。伪指令ORG的一般通式为:
    ORG   m ; m为十进制或十六进制数
    下面通过一个例子,说明伪指令的应用。
    例:           ORG  4000H
       (4000H)   MOV  A,#01H
       (4002H)   MOV  CA,@01H
        (4003H)    RET
        (4004H)    DB   01H  ;常数表
        (4005H)    DB   04H  ;常数表
        (4006H)    DW   1234H  ;地址表
    程序中括弧内数字表示出程序存放单元。


一个复杂的程序是由许多子程序组成的,而每个程序之间的联系有可能是交叉的这是就要控制程序的转移和返回;于是就用到了转移指令,下面我们就来学习“控制转移指令与分支程序”,网友要多读多做实验,因为一个完整的程序离不开它。

控制转移指令与分支程序
一、条件转移指令:

条件转移指令是指在满足一定条件时,程序将转向指定的目的地址(目的地址是以下一条指令的起始地址为中心的-128~+127共256个字节范围中),去执行相应的程序。


判A内容是否为0转移指令
 

JZ rel;rel为相对地址(标号,如:JZ  MAIN),如果(A)=0,则转移去“当前地址+rel”后为地址的目的地址去执行,rel如是标号,则直接转移到标号处,否则顺序执行

JNZ rel;A中的内容不为零时,转移;下面举一例说明:

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。

同理将上例中JZ换成JNZ时如何?你想一下??
以上两条指令不影响任何标志位,也不改变累加器A中内容。

 

比较转移指令
比较转移指令是MCS-51新增设的功能较强的指令,格式如下:

CJNE (目的字节), (源字节),rel;它的功能是对指令的目的字节和源字节二操作数进行比较,若它们的值不相等,则转移;本指令的四种寻址方式:

CJNE A,#data,rel

CJNE A,direct,rel

CJNE Rn,#data,rel

CJNE @Ri,#data,rel

第一条指令的功能是将A中的值和立即数data比较,如果两者相等,就顺序执行(执行本指令的下一条指令),如果不相等,就转移,同样地,我们可以将rel理解成标号,即:CJNE A,#data,标号。这样利用这条指令,我们就可以判断两数是否相等,这在很多场合是非常有用的。如果两数不相等,则CPU还会反映出哪个数大,哪个数小,这是用CY(进位位)来实现的。如果前面的数(目的字节)大,则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当中的值和直接地址中的值比较,第三条则是将直接地址中的值和立即数比较,第四条是将间址寻址得到的数和立即数比较,

循环转移指令
循环转移指令DJNZ,在前面的流水灯实验中用到过,下面的Rn,direct称为操作数,

DJNZ Rn,rel

DJNZ direct,rel

循环转移指令是指程序每执行一次本指令,都会将操作数的字节量减1,并判断操作数的值是否为0,若不为0,则转移目的地址(或标号)rel处,继续执行循环程序段。若为0,则结束循环程序向下执行。

具体例子参照第二课。

4。无条件转移指令

AJMP ADDR11;ADDR11是11位的转移目标地址,常用标号如:AJMP MAIN ;程序运行到该条指令时,程序将无条件转向“MAIN:XXXXX”为标号的地方继续执行。
LJMP MAIN;长转移指令
SJMP MAIN;短转移指令,指以当前地址为基址所能转向的字节范围。

3.子程序的调用与返回指令

(1)主程序与子程序

    在前面的流水灯的实验中,我们已用到过了子程序,只是我们并没有明确地介绍。就是延时的程序(DELAY),子程序是干什么用的,为什么要用子程序技术呢?其实很简单,子程序是完成某个独立的功能为主程序服务的,举个例子,我们老师布置了10道算术题,经过观察,每一道题中都包含一个(3*5+2)*3的运算,我们可以有两种选择,第一种,每做一道题,都把这个算式算一遍,第二种选择,我们可以先把这个结果算出来,也就是51,放在一边,然后要用到这个算式时就将51代进去。这两种方法哪种更好呢?不必多言。设计程序时也是这样,有时一个功能会在程序的不同地方反复使用,我们就可以把这个功能做成一段程序,每次需要用到这个功能时就“调用”(ACALL或LCALL)一下,避免重复编写也节省程序存储空间,子程序的最后都要放一条返回指令既“RET”。

(2)调用及返回过程:主程序调用了子程序,子程序执行完之后必须再回到主程序继续执行,不能“一去不回头”,那么回到什么地方呢?是回到调用子程序的下面一条指令继续执行的。参考下图:

 

 

 

调用指令
 

LCALL addr16 ;长调用指令

ACALL addr11 ;短调用指令

上面两条指令都是在主程序中调用子程序,两者有一定的区别,但在初学时,可以不加以区分,而且可以用LCALL 标号,ACALL 标号,来理解,即调用子程序。

(5)返回指令 :

ret指令

4.空操作指令

nop

空操作,就是什么事也不干,停一个周期,一般用作短时间的延时。

位及位操作指令

通过前面那些流水灯的例子,我们已经知道“位”,一位就是一盏灯的亮和灭,我们知道送往P1口的数值后并不能马上知道哪个灯亮和灭,而是要化成二进制才知道。工业中有很多场合需要处理这类开关输出,继电器吸合,用字节来处理就显示有些麻烦,所以在8051单片机中特意引入一个位处理机制。

 

位寻址区
 

在8051中,有一部份RAM和一部份SFR是具有位寻址功能的,也就是说这些RAM的每一个位都有自已的地址,可以直接用这个地址来对此进行操作。是从20H-2FH的16个单元的128个位,凡是字节地址能被8整除的特殊寄存器都具有位地址,具体的特殊寄存器以后介绍。以下是RAM区可位寻址的地址映象:

字节地址
 位地址
 
2FH
 7FH
             78H
 
2EH
 77H
             70
 
2DH
 6FH
             68H
 
2CH
 67H
             60H
 
2BH
 5FH
             58H
 
2AH
 57H
             50H
 
29H
 4FH
             48H
 
28H
 47H
             40H
 
27H
 3FH
             38H
 
26H
 37H
             30H
 
25H
 2FH
             28H
 
24H
 27H
             20H
 
23H
 1FH
             18H
 
22H
 17H
             10H
 
21H
 0FH
             08H
 
20H
 07H
 06H
 05H
 04H
 03H
 02H
 01H
 00H
 

可以位寻址的特殊功能寄存器
 

8051中有一些SFR是可以进行位寻址的,如A累加器,B寄存器、PSW、IP(中断优先级控制寄存器)、IE(中断允许控制寄存器)、SCON(串行口控制寄存器)、TCON(定时器/计数器控制寄存器)、P0-P3(I/O端口锁存器)。

 

位操作指令
 

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及端口都可以有两种用法。

 

位传送指令
 

MOV C,BIT

MOV BIT,C

这组指令的功能是实现位累加器(CY)和其它位地址之间的数据传递。

 

位修正指令
 


位清0指令
 

CLR C ;使CY=0

CLR bit ;使指令的位地址等于0。例:CLR P1.0 ;即使P1.0变为0


位置1指令
 

SETB C ;使CY=1

SETB bit ;使指定的位地址等于1。例:SETB P1.0 ;使P1.0变为1

 

位取反指令
 

CPL C ;使CY等于原来的相反的值,由1变为0,由0变为1。

CPL bit ;使指定的位的值等于原来相反的值,由0变为1,由1变为0。

例:CPL P1.0

以我们做过的实验为例,如果原来灯是亮的,则执行本指令后灯灭,反之原来灯是灭的,执行本指令后灯亮。

 

位逻辑运算指令
 

 

位与指令
 

ANL C,bit ;CY与指定的位地址的值相与,结果送回CY

ANL C,/bit ;先将指定的位地址中的值取出后取反,再和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 ;将做完的结果送P1.1,结果应当是P1.1上的灯亮,而P1.0上的灯还是不亮。

 

位或指令
 

ORL C,bit

ORL C,/bit

位条件转移指令

判CY转移指令
 

JC rel

JNC rel

第一条指令的功能是如果CY等于1就转移,如果不等于1就顺序执行。那么转移到什么地方去呢?我们可以这样理解:JC  ----   标号,如果等于1就转到标号处执行。

第二条指令则和第一条指令相反,即如果CY=0就转移,不等于0就顺序执行,当然,我们也同样理解: JNC   -----   标号

 

判位变量转移指令
 

JB bit,rel;如果指定的bit位中的值是1,则转移,否则顺序执行

JNB bit,rel;指令和第一相反BIT位中的值是0,则转,否则顺序向下
上两条指令在口的状态的判断上很有用如:P1、P0、P3、P3.6\

下面我们举个例子说明:

ORG 0000H  ;MCS-51上电复位后程序计数器(PC)将被装入0000,所以程序都是从0号地址开始运行的

LJMP  START

ORG   30H;为何从30H的地址开始呢,00H-30H之间为MCS-51的中断入口地址

START:
   MOV SP,#5FH

     MOV P1,#0FFH

MOV P3,#0FFH

L1: JNB P3.2,L2 ;P3.2上接有一只按键,它按下时,P3.2=0

JNB P3.3,L3 ;P3.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,如此循环不已。

 

    到此单片机51系列汇编指令以作较详细介绍可多看几遍多上机在实验板上看一下效果,有利于理解领会。

0
2008-10-15 13:02:43   评论 分享淘帖
5 个讨论
好乱呀                              
2013-8-17 12:32:55 评论

举报

{:1:}{:1:}
2013-8-17 13:12:33 评论

举报

这是什么东西啊啊啊
真的不错呀!谢谢楼主的分享
2013-8-17 16:50:18 评论

举报

不错的资料,值得收藏
2017-3-8 10:33:48 评论

举报

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发表新帖
快速回复 返回顶部 返回列表