汇编语言程序设计技巧详解(附例题)

汇编语言程序设计技巧

四种基本结构:顺序结构分支结构循环结构和子程序

1、顺序结构

】将R0单元内的两位BCD码拆开并转换成ASCII码,存入RAM两个单元中R2 (存高位)和R1 (存低位)中 。

参考程序:

        ORG  2000H

                MOV  A,R0      ;取值

        ANL   A,#0FH  ;取低4位

        ADD  A,#30H   ;转换成ASCII码

        MOV  R1,A       ;保存结果

        MOV  A,R0       ;取值

        SWAP  A             ;高4位与低4位互换

        ANL  A,#0FH   ;取原来的高4位      

        ADD  A,#30H   ;转换成ASCII码

        MOV  R2,A       ;保存结果

        SJMP  $  

               END

2、分支结构

(1)先建立可供条件转移指令测试的条件。

(2)选用合适的条件转移指令。

(3)在转移的目的地址处设定标号。

】求R2中补码绝对值,正数不变,负数变补。

             MOV A,R2

             JNB ACC.7,NEXT;为正数?

             CPL A          ;负数变补

             INC A

             MOV R2,A

    NEXT:SJMP NEXT  ;结束

多重分支程序

a.多次使用条件转移指令,形成两个以上判断框。

 求符号函数Y=SGN(X)

                    +1  当 X>0

SGN(X)=      0  当 X=0

                     -1  当 X<0

SYMB: MOV  A,40H    ;取X

          JZ     STOR                     ;X=0,Y=X

       JB     ACC7,MINUS;X<0

       MOV  A,# 1      ;X>0,Y=+1

          SJMP  STOR

MINUS:MOV  A,#0FFH;X<0,Y= -1

STOR:  MOV  41H,A   ;保存Y

                RET

b.按分支号转移

如:分支号=0,程序转移到ADDR0处;当分支号=1,程序转移到ADDR1处;… 。

(1)用地址表法。设分支号已存入A。

MTJS:MOV   DPTR,#TAB  ;取表首地址

         CLR     C     

         RLC     A                      ;分支号×2

         MOV   R2,A

        INC      A

         MOVC A,@A+DPTR;取分支地址低位

         PUSH   ACC         ;入栈保存

         MOV    A,R2

         MOVC  A,@A+DPTR;取分支地址高位

         PUSH   ACC         ;入栈保存

         RET                     ;分支地址→PC,转移

TAB:  DW          ADDR0            ;分支地址表

            DW         ADDR1     

                     … 

ADDR0:      …                 ;程序段0  …

(2)转移表法。用分支转移指令 JMP @A+DPTR

】根据R0的值转向7个分支程序。R0<10,转向SUB0; R0<20,转向SUB1;… …R0<60,转向SUB5; R0>=60,转向SUB6;

分析:这里应该利用JMP @A+DPTR

指令直接给PC赋值,使程序实现转移

参考程序如下:

ORG    2000H

MOV DPTR,#TAB;取转移指令表首地址

MOV  A,R0           ;取数     

MOV      B,#10

     ……

DIV  AB                  ;A/10,商在A中       

CLR C

RLC    A                ;A←2A

JMP   @A+DPTR     ;PC ← A+DPTR

TAB: AJMP     SUB0  ;转移指令表

AJMP  SUB1

AJMP     SUB2

      ……

AJMP     SUB6

3、循环结构

循环程序结构是汇编语言程序中常见的一种程序结构。所谓循环,就是让计算机反复执行某一段程序。使用循环程序可以省略很多类似的代码,提高程序的代码密度。

循环程序主要包含以下三个方面:

(1)循环初始化

设置循环的初始状态,如工作单元的清零,循环次数的设置等。在设置初始条件时要小心,否则很容易让程序多执行(或少执行)一次。

(2)循环体

即循环程序的主体,是要求计算机重复执行的部分。这部分程序应该特别注意精简,因为要重复多次,所以这部分的精简程度决定了整个循环程序的执行效率。

(3)循环控制

包括对循环计数器的修改和循环结束条件的判断等内容。

】把内部RAM中从ST1地址开始存放的数据传送到以ST2开始的存储区中,数据块长度未知,但已知数据块的最后一个字节内容为00H,而其它字节均不为0。并设源地址与目的地址空间不重叠。 

    分析:显然,我们可以利用判断每次传送的内容是否为 0 这一条件来控制循环。利用判A转移控制的循环流程图如下图所示。

参考程序如下:

START:MOV      R0,#ST1

       MOV       R1,#ST2

 LOOP: MOV    A, @R0      

         JZ      ENT

       MOV  @R1,A

         INC    R0         

         INC    R1                        

         SJMP LOOP                                   

        ENT:  RET       

例:求n个单字节数据的累加,设数据串已在43H起始单元,数据串长度在42H单元,累加和不超过2个字节。

编辑

              MOV      A,@R0

              MOV      R2,A      ;循环计数器←n

              CLR A       ;结果单元清0

              MOV      R3,A

ADD1:INC   R0     ;修改指针

              ADD       A,@R0  ;累加

              JNC   NEXT    ;处理进位

              INC R3     ;有进位,高字节加1

NEXT:     DJNZ     R2,ADD1 ;循环控制:数据是否加完?

              MOV      40H,A  ;循环结束,保存结果

              MOV      41H,R3

              RET

多重循环循环体中套循环结构

例将内存一串单字节无符号数升序排序。

步骤:

每次取相邻单元的两个数比较,决定是否需要交换数据位置。

第一次循环,比较N-1次,取到数据表中最大值。

第二次循环,比较N-2次,取到次大值。

    …

第N-1次循环:比较一次,排序结束。

编辑

SORT:  MOV    A,#N-1    ;N个数据排序

                MOV  R4,A         ;外循环次数

LOOP1: MOV   A,R4

                MOV  R3,A         ;内循环次数

                MOV  R0,#TAB   ;设数据指针

LOOP2: MOV   A,@R0      ;取二数

                MOV  B,A

                INC    R0

                MOV  A,@R0

                CJNE A,B,L1 ;比较

L1:         JNC    UNEX          ;A≥B,不交换

                DEC    R0        ;否则交换数据

                XCH   A ,@R0

                INC    R0

                MOV  @R0,A

UNEX:  DJNZ R3,LOOP2    ;内循环结束?

                DJNZ R4,LOOP1   ;外循环结束?

                RET

4、子程序

能完成某项特定功能的独立程序段,可被反复调用。

子程序设计

(1)子程序入口用标号作为子程序名。

(2)调用子程序之前设置好堆栈

(3)用返回指令RET结束子程序,并保证堆栈栈顶为调用程序的返回地址。

(4)子程序嵌套须考虑堆栈容量。

(5)提供足够的调用信息:

如:子程序名、子程序功能、入口参数和出口参数、子程序占用的硬件资源、子程序中调用的其他子程序名。

选用不同的参数传递方式。

1.寄存器传送参数

2.存储器传送参数

3.堆栈传送参数

【例】将R4R5R6中三个字节数据对半分解,变成6个字节, 存入显示缓冲区(DISMEM0~DISMEM5)。

1)子程序UFOR1的功能:将A累加器中单字节数据,对半分解成两个字节,存入R0所指向的相邻两个单元

UFOR1:MOV  @R0,#0

               XCHD A,@R0   ;保存低半字节

               INC  R0      ;修改指针

               MOV  @R0,#0

               SWAP A

               XCHD A,@R0   ;保存高半字节

               RET

2)调用子程序UFOR1之前,将待分解的内容送A,存放地址送R0。

】利用MCS-51仿真实验板,外部扩展四个双色发光二极管HL1、HL2、HL3和HL4分别模拟北(HL1)、西(HL2)、东(HL3)、南(HL4)四个方向交通灯,连接电路如下图所示:

编辑 分析:双色发光二极管有一个阴极,两个阳极G和R,当G极为高电平时,发光二极管呈现绿色,当R极为高电平时,发光二极管呈现红色,当G和R极都为高电平时,发光二极管呈现黄色,根据题意要求和图3.19的电路连接情况可以知道P1口的控制状态如下表所示:

编辑

编辑

编辑

编辑

参考程序如下:

             ORG 1000H

START:MOV  R0,#0

             MOV  R1,#0   ;南北绿灯亮5秒钟,东西红灯亮

             MOV  P1,#10010110B ;南北绿灯亮红灯灭,东西红灯亮绿灯灭,为状态1

SNDL5:  MOV R1, #10

            ACALL   DL500ms    ;调用延时500ms程序10次,实现延时5秒

            DJNZ  R1, SNDL5   ;南北绿灯闪烁3次,每次1秒(亮0.5秒,灭0.5秒)

SS1:    MOV  P1,#10011111B;南北绿灯和红灯都灭,东西红灯亮绿灯灭,为状态2

            ACALL  DL500ms        ;延时500ms

            MOV  P1,# 10010110B  ;南北绿灯亮红灯灭,东西红灯亮绿灯灭,为状态1

            ACALL  DL500ms       ;延时500ms

            INC         R0

            CJNE      R0,#03H,SS1   ;闪烁3次,南北黄灯亮2秒

            MOV      P1,#00000110B  ;南北黄灯亮,东西红灯亮绿灯灭,为状态3

SNDL2:  MOV R1, #4

             ACALL   DL500ms ;调用延时500ms程序4次,实现延时2秒

             DJNZ  R1, SNDL2       ;东西绿灯亮5秒钟,南北红灯亮

             MOV P1,#01101001B  ;东西绿灯亮红灯灭,南北红灯亮绿灯灭,为状态4

EWDL5:  MOV R1, #10

             ACALL   DL500ms  ;调用延时500ms程序10次,实现延时5秒

             DJNZ  R1, EWDL5 ;东西绿灯闪烁3次,每次1秒(亮0.5秒,灭0.5秒)

SS2:  MOV P1,#01101111B ;东西绿灯和红灯都灭,南北红灯亮绿灯灭,为状态5

             ACALL  DL500ms       ;延时500ms

           MOV  P1,# 01101001B ;东西绿灯亮红灯灭,南北红灯亮绿灯灭,为状态4

             ACALL  DL500ms        ;延时500ms

              INC  R0

             CJNE    R0,#03H,SS2   ;闪烁3次,东西黄灯亮2秒

              MOV  P1,#00001001B  ;东西黄灯亮,南北红灯亮绿灯灭,为状态6

SNDL2:  MOV R1, #4

            ACALL   DL500ms       ;调用延时500ms子程序4次,实现延时2秒

            DJNZ  R1, SNDL2

            SJMP  START          ; 500ms 秒延时子程序

DL1500mS: MOV  R7,#5 ;500ms 秒延时子程序,假定为6MHz晶振

   DL2: MOV  R6,#200

   DL1: MOV  R5,#250

             DJNZ    R5,$

             DJNZ    R6,DL1

             DJNZ    R7,DL2

             RET          

             END


模块化设计

模块化设计是指把一个具体的功能分解成多个小的模块,各个模块之间相互独立,而又可以相互传递参数。分解成的小模块程序功能单一,易于调试和修改,而在模块内部要注意多使用子程序调用,一个子程序可以被多次调用,节省空间而且便于阅读。在程序中应该尽量使用循环结构,这样可以节省内存,提高执行效率,不过要注意循环的初始值和循环的结束条件。

注意:由于中断是随机产生的,因此在处理中断程序时,一定要注意保存程序现场(保护标志寄存器和中断处理程序用到的寄存器),以便执行完毕后恢复。在进行子程序调用时,经常使用累加器A(参数多时还可以使用寄存器或存储器)进行参数传递。

#汇编语言#
全部评论
膜拜一下大佬
1 回复 分享
发布于 2022-09-01 10:23 江苏

相关推荐

joe2333:怀念以前大家拿华为当保底的日子
点赞 评论 收藏
分享
ProMonkey2024:5个oc?厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了(别的帖子偷来的,现学现卖😋)
点赞 评论 收藏
分享
点赞 3 评论
分享
牛客网
牛客企业服务