您的位置: 网站首页 > 电子与嵌入式 > 单片机原理与应用 > 第4章 汇编语言程序设计 > 【4.6 程序设计举例】

4.6 程序设计举例

 

MCS-51的基本运算指令是针对8位二进制数的,带有很大的局限性,但通过软件设计,可以完成各种各样的运算。本节主要讨论常用的程序设计方法,以进一步熟悉MCS-51指令系统,掌握汇编语言程序设计方法和技巧。

4.6.1  查表程序

在许多情况下,本来通过计算才能解决的问题也可以改用查表方法解决,而且要简便得多。因此,在实际单片机应用中,常常需要编制查表程序以缩短程序长度和提高程序执行效率。

所谓查表是根据存放在ROM中数据表格的项数来查找和它对应的表中的值。例如:查y=x2(设x09)的平方表时,我们可以预先计算出x09时的y值作为数据表格存放在起始地址为DTABROM存储器中,并使x的值和数据表格的项数(所查数据的实际地址对DTAB的偏移量)一一对应。这样,我们就可以根据DTAB+x来找到和x对应的y值。

采用MCS-51汇编语言进行查表尤为方便,它有两条专门的查表指令:

MOVC A, @A+DPTR

MOVC A, @A +PC

第一条查表指令采用DPTR存放数据表格的起始地址,其查表过程比较简单。查表前需要把数据表格起始地址存入DPTR,然后把所查表的项数送入累加器A,最后使用MOVC A@A+DPTR指令完成查表。

采用MOVC A@a+PC指令查表,所需操作有所不同,其步骤分为3步:

1)使用传送指令把所查数据表格的项数送入累加器A

2)使用ADD A#data指令对累加器A进行修正。data值由下式确定。

PC + data=数据表始址DTAB

其中,PC是查表指令MOVC A@A+PC的下一条指令码的起始地址。因此,data值实际上等于查表指令和数据表格之间的字节数。

3)采用查表指令MOVC A@A+PC完成查表。

查表程序主要用于代码转换、代码显示、实时值查表计算和按命令号实现转移等。

【例4-21 已知R04位有一个十六进制数(09AF中的一个),请编出能把它转换成相应ASCII码并送入R0的程序。

解:本题给出3种求解方案,两种是计算求解,一种是查表求解,请比较它们的优劣。

1)计算求解1。由ASCII码字符表可知09ASCII码为30H39HAF的确ASCII码为41H46H。因此,计算求解的思路是,若R09,则R0内容只需加30H;若R09,则R0需加37H

相应程序如下:

       ORG         0400H

        MOV     A,R0                ;取转换值到A

        ANL     A,#0FH              ;屏蔽高4

        CJNE    A,#10NEXT1        ;A10比较

NEXT1:  JNC         NEXT2               ;A9,则转NEXT2

        ADD     A,#30H              ;A10,AA+30H

        SJMP    DONE                ;DONE

NEXT2:  ADD     A,#37H              ;AA+37H

DONE:   MOV         R0,A                ;存结果

        SJMP    $                  

        END

2)计算求解2。本方案先把R0中内容加上90H,并作十进制调整,然后再用ADDC指令使R0中内容加上40H,也作十进制调整,所得结果即为相应ASCII码。

本方案实际上和第一种方案类似,只是使用了十进制调整指令。当R010时,经过上述处理相当于R0中内容加了30H;当R0=0AH时,加90H并进行十进制调整后,低4位的半进位位加到高4位后变为A0H,对高4位进一步调整便得到00H,最后使用ADDC指令(C=1)加上40H实际上相当于加上41H

相应程序如下:

        ORG         0400H

        MOV     A,R0        ;取转换值到A

        ANL     A,#0FH      ;屏蔽高4

        ADD     A,#90H      ;A中内容加90H

        DA       A           ;十进制调整

        ADDC    A,#40H      ;A中内容加40H

        DA       A           ;十进制调整

        MOV         R0,A        ;存转换结果

        SJMP    $           ;结束

        END

3)查表求解。查表求解时,两条查表指令均可以使用。现以MOVC A@A+PC指令为例,给出相应程序如下:

        ORG     0400H

        MOV     A,R0        ;取转换值到A

        ANL     A,#0FH      ;屏蔽高4

        ADD     A,#03H      ;地址调整

        MOVC    A,  @A+PC   ;查表

        MOV     R0,A       ;存结果

ASCTAB:DB  '0','1','2','3','4'

         DB  '5','6','7','8','9'

        DB  'A','B','C','D','E','F'

         END

【例4-22 设有一起始地址为DTATAB的数据表格,表中存放有1024个元素,每个元素为两个字节。请编出能根据R5R4中元素序号查找对应元素并放入R5R4R5中为高8位和R4中为低8位)的程序。

解:由于数据表格内的每个元素为二字节,故R5R4中元素序号应扩大两倍后再和DPTR中数据表格起始地址DTATAB相加,以获得数据元素的绝对地址。

根据这一思想,相应参考程序如下:

             ORG         0500H

    START:  MOV     DPTR,#DTATAB        ;数据表格起始地址送DPTR

             MOV         A,R4                ;元素序号低字节送A

             CLR     C                   ;CY清零

             RLC     A                   ;2×元素序号低字节

             XCH     A,R5                ;存入R5,元素序号高字节送A

            RLC     A                   ;2×元素序号高字节

             XCH     A,R5,                   

ADD     A,DPL               ;2×元素序号低字节+DPL

             MOV     DPL,A               ;存入DPL

             MOV     A,DPH              

             ADDC    A,R5                ;2×元素序号高字节+DPH

             MOV     DPHA              ;存入DPH

           CLR     A                   ;清零A

             MOVC    A,@A+DPTR           ;查表得元素高字节

             MOV     R5,A                ;存入R5

             MOV     A,#01H              ;查表得元素低字节

             MOVC    A,@A+DPTR          

             MOV         R4,A                ;存入R4

             RET                       ;返回主程序

    DTATAB:                        DW……;元素表格,高字节在前

                             DW……

                        ……

                END

本程序是以子程序形式编写的,可为主程序调用。程序使用了DPTR作为基地址寄存器,故它可以在64KB范围内查表。

4.6.2  算术运算程序

运算程序可以分为浮点数运算程序和定点数运算程序两大类。浮点数就是小数点不固定的数,其运算通常比较麻烦,常由阶码运算和数值运算两部分组成;定点数就是小数点固定的数,通常包括整数、小数和混合小数等,其运算比较简单,但在数位相同时定点数的表示范围比浮点数的小。本教材只介绍定点数运算程序设计问题,若无特别说明,所有程序均指定点数运算程序。

MCS-51单片机提供了单字节运算指令,但在实际应用中经常需要编写一些多字节运算程序,这些运算程序通常编成子程序形式,以供主程序在需要时调用。

1.加减运算程序设计

加减运算程序可以分为无符号多字节数加减运算程序和带符号多字节数加减运算程序两种。现分述如下。

1)无符号多字节加减运算程序。

无符号多字节加法运算程序的编制已在前面作过介绍,现以多字节减法程序为例加以介绍。

【例4-23 已知:以BLOCK1BLOCK2为起始地址的存储区中分别有5个字节无符号被减数和减数(低位在前,高位在后),请编一减法子程序令它们相减并把差放入以BLOCK1为起始地址的存储单元中。

解:本程序算法很简单,只要用减法指令从低字节开始相减即可。

相应程序如下:

            ORG  0A00H

SBYTESUB:   MOV R0,#BLOCK1           ;被减数始址送R0

            MOV R1,#BLOCK2           ;减数始址送R1

            MOV R2,#05H              ;字长送R2

             CLR C                    ;CY清零

LOOP:       MOV A,@R0                ;被减数送A

             SUBB A,@R1               ;相减,形成C

             MOV @R0,A                ;存差

             INC R0                   ;修改被减数地址指针

             INC R1                   ;修改减数地址指针

             DJNZ R2,LOOP             ;若未完,则LOOP

4-18  双字节无符号乘法

程序流程图

            RET

            END

2)带符号单字节加减运算程序。

带符号单字节加减运算程序和无符号加减运算程序类似,只是符号位处理上有所差别。

2.乘除运算程序设计

【例4-24 双字节无符号数乘法。

解:编程说明。MCS-51指令系统中只有单字节乘法指令,因此双字节相乘需分解为4次单字节相乘。若被乘数ab)和乘数cd)分别表示为az+zb)和cz+zd)。其中,abcd都是8位数,z表示8位“0”,其乘积表示为:

(az+zb)(cz+zd)=zz+zz+zz+zz

式中,为相应的两个8位数的乘积,占16位,可用4次乘法指令并求和,以便得到两个双字节数的乘积。

当被乘数R5高)、R4低)、乘数R3高)、R2低)时,其算法如下。

流程图如图4-18所示,参考程序如下

功能:   双字节无符号数乘法。

入口:   R5(高),R4(低),被乘数;

R3(高),R2(低),乘数。

出口:   R1=积的低位字节地址指针。

MULBIN:MOV A,R1                 ;将积的指针暂存在R6

MOV R6,A                 

MOV R7,#04H             ;积有4个单元

CLEAR:  MOV @R1,#00H            ;积单元清零

INC R1                   

DJNZ R7,CLEAR           ;4个单元清零

MOV A,R6               

MOV R1,A                ;恢复积的指针R1

MUL1:   MOV A,R2                ;R2×R4

MOV B,R4               

MUL AB                 

ACALL ADDM              ;调用加部分积子程序

MOV A,R2                ;R2×R5

MOV B,R5

MUL AB

ACALL ADDM              ;调用加部分积子程序

MOV A,R3                ;R3×R4

MOV B,R4

MUL AB

DEC R1                  ;指针调回

ACALL ADDM              ;调用加部分积子程序

MOV A,R3                ;R3×R5

MOV B,R5                   

MUL AB

ACALL ADDM              ;调用加部分积子程序

MOV A,R6                ;恢复地址指针

MOV R1,A

RET

子程序如下:

ADDM:   ADD A,@R1               ;加部分积,A为部分积低位

MOV @R1,A               ;保存积的低位

MOV A,B                 ;部分积高位送A

INC R1                  ;指针加1

ADDC A,@R1                  ;加高位部分积

MOV @R1,A               ;保存积

INC R1                  ;指针加1

MOV A,@R1               ;更高位加上一次的进位

ADDC A#0               ;加进位

MOV @R1,A               ;送回结果

DEC R1                  ;指针减1

RET                     ;返回

4.6.3  数字滤波程序

在单片机应用系统的信号中,常含有各种噪声和干扰,影响了信号的真实性,因此应采取适当的方法消除噪声和干扰。数字滤波就是一种有效的方法。常用的数字滤波方法有算术平均值法、滑动平均值法等。下面以算术平均值法为例讲述数字滤波程序问题。

【例4-25 片外RAM中从ADIN处开始存放16个字节的数据信号,编程实现用算术平均值法进行滤波,结果存放在累加器A中。

解:算术平均值法就是用求16个字节数据信号的算术平均值的方法进行滤波。

参考程序如下:

功能:   16字节算术平均值。

入口:   ADIN指针,指向16字节外部数据。

出口:   (R5)=16字节外部数据的算术平均值。

AVl6D:  MOV R7,#16          ;设置计数器

MOV DPTR,#ADIN      ;指向数据区

MOV R5,#0           ;(R6,R5)用于存放累加结果

MOV R6,#0          

LOOP:   MOVX A,@DPTR        ;取外部数据

ADD A,R5            ;加部分和低位

MOV R5,A            ;送回

MOV A,R6            ;取高位

ADDC A,#0           ;加低位的进位

MOV R6,A            ;送回

INC DPTR            ;调整外部数据指针

DJNZ R7,LOOP        ;共加16个数

MOV R7,#4           ;右移4次,相当于除以16

LOOP1:  CLR C               ;清进位

MOV A,R6            ;先移高4

RRC A               ;带进位右移1

MOV R6,A            ;送回

MOV A,R5            ;后移低4

RRC A               ;带进位右移1

MOV R5,A            ;送回

DJNZ R7,LOOP1       ;共移4

RET

在算术平均值滤波程序中,数据个数m的取值一般为2m,这样便于计算,顺序累加和右移m次即可。为确保精度,本程序采用双字节数加法,采取右移4次的方法达到求平均数的目的。

4.6.4  定时应用程序

MCS-51系列单片机中,有两个16位的定时器/计数器,它们是可编程的。在对它们进行初始化编程时,一般包括以下几个步骤。

1)确定工作方式,对TMOD进行赋值。

2)置定时器/计数器的初值,写入TH0TL0TH1TL1中。

3)根据需要开放中断。

4)启动定时器/计数器。

下面举例说明定时器/计数器的使用。

【例4-26 设晶振为6MHz,应用定时器T0产生一个宽度为1ms,周期为4ms的矩形波,由P1.0口输出。波形如图4-19所示。

4-19  P1.0输出波形图

选用定时器0工作方式1,定时时间1ms,其初值计算为:

10-3=12216-X/6×106

X=0FE0CH

程序清单如下:

START: MOV      R5,     #01H       

             MOV     TMOD,   #01H        ;设置定时器0工作方式1

             MOV     TL0,    #0CH        ;定时器0置数

             MOV     TH0,    #0FEH       ;定时器0置数

             SETB    TR0                 ;启动定时器0

LOOP:   JNB     TF0,    $           ;等待定时器0定时到

             CLR     TF0                 ;时间到,清除定时器0溢出标志

             MOV     TL0,    #0CH       

             MOV     TH0,    #0F0H

             DJNZ    R5,     LOOP

             MOV     R5,     #0H

             CPL     P1.     0

             JB      P1.     0, LOOP

             MOV         R5,     #03H

             AJMP    LOOP