11.码制转换十、二进制数、ASCII码之间的互相转换。①BCD数→2进制数算法:Dn-1*10n-1+……+D0*100=(…(Dn-1*10+Dn-2)*10+…)*10+D0=(…((0*10+Dn-1)*10+Dn-2)*10+…)*10+D0即:新的中间结果=中间结果*10+本位数字(中间结果初值为0)4.5常见程序设计举例2程序1:将≤65535的非压缩BCD数转换成2进制数。程序如下:;数据段定义mydataSEGMENTdecnumDB5,3,0,1,9;BCD数53019binnumDW?mydataENDS3progSEGMENTASSUMECS:prog,DS:mydatabegin:MOVAX,mydataMOVDS,AXMOVSI,OFFSETdecnumMOVCX,5;5位BCD数MOVBX,10XORAX,AX;中间结果初始值为0Next:MULBX;中间结果*10+本位数字ADDAL,[SI]ADCAH,0INCSI;指向下位BCD数LOOPnextMOVbinnum,AX;保存结果MOVAH,4CHINT21HprogENDSENDbegin4程序2:把≤255的非压缩BCD数转换成2进制数decnumDB1,5,9;BCD数159binnumDB?……MOVAX,decnumXCHGAH,AL;百位在AH,十位在ALAAD;百位数*10+十位数MOVAH,AL;中间结果送AHMOVAL,decnum+2AAD;中间结果*10+个位数MOVbinnum,AL……5例:从键盘输入两个整数,并求其和。因键入为整数,故要进行如下转换:ASCII→BCD→二进制数ASCII→BCD码很简单,高4位清零即可得到非压缩的BCD码。BCD→二进制数在本例中采用用以下方法:((((0+千位数)*10+百位数)*10)+十位数)*10+个位数②ASCII码→二进制数(用于输入)第一次中间结果第二次中间结果第三次中间结果最终结果6开始两个数分别转换成二进制数键入两个数相加结束返回DOS如有溢出则提示开始取第一个ASCII码是负号吗?数字符个数-1,指针+1指针定位字符个数-1=0?取数字,与中间结果相加,再乘以10指向下一个数字字符加个位数是负数则求补存结果结束NYYN转换子程序7程序如下:DATASEGMENTSTR1DB10,?,10DUP(?);第1个数的输入缓冲区STR2DB10,?,10DUP(?);第2个数的输入缓冲区NUMDW?,?;存转换后的二进制数SUMDW0;存和OVERDB‘Overflow!’,13,10,’$’DATAENDS;CODESEGMENTASSUMECS:CODE,DS:DATAMAINPROCFAR8START:MOVAX,DATAMOVDS,AXMOVAH,0AHLEADX,STR1INT21H;输入第一个数字串(设为26)MOVAH,0AHLEADX,STR2INT21H;输入第二个数字串(设为33)LEABX,STR1;串1的首地址送BXLEADI,NUM;存二进制首地址送DICALLCHANGE;将串1ASCII码→二进制LEABX,STR2;串2的首地址送BX9LEADI,NUM+2;指向CALLCHANGE;将串2ASCII码→二进制MOVAX,NUM;(AX)=[NUM]=001AHADDAX,NUM+2;两数相加,(AX)=003BHMOVSUM,AX;存和JNONEXT;无溢出,转NEXTLEADX,OVERMOVAH,9INT21H;显示’Overflow!’NEXT:MOVAH,4CHINT21H;返回DOSMAINENDP10CHANGEPROCMOVCL,[BX+1];实际字符数送CLMOVAL,[BX+2];第一个字符送ALMOVCH,AL;暂存在CHCMPAL,’-’;第一个字符是负号吗?JNZNEXT1;不是,转NEXT1DECCL;字符数减1INCBXNEXT1:ADDBX,2;指向第一个数字字符MOVAX,0;清零AX,存二进制数LP1:DECCLJZNEXT2;若(CL)=0,转NEXT2MOVDL,[BX];取字符ANDDL,0FH;转换成BCD码ADDAL,DL;加到中间结果上ADCAH,011MOVDX,10MULDX;*10INCBX;指向下一个字符JMPSHORTLP1NEXT2:MOVDL,[BX];取个位数ANDDL,0FH;个位ASCII→未组合BCDADDAX,DX;加个位数,(AX)=001AHCMPCH,’-’;是’-’?JNZNEXT3;该数非负,转NEXT3NEGAX;若为负,求补NEXT3:MOV[DI],AX;存二进制结果RETCHANGEENDP;CODEENDSENDSTART12020A32360D…020A33330D…001A21003B00STR1STR2NUMSUM10个10个‘O’……OVER??040A313234…STR1若键入‘1234’330D‘1’‘2’‘3’‘4’…设键入第1个数为26,第2个数为33,则在内存各变量分配如下:13本例题重点掌握:*如何从键盘输入一个字符串*ASCII→未组合BCD→二进制*有符号数的运算,对负数和溢出如何处理思考题:若键入第一个数26,第二个数为-4,填写各变量结果。14方法1计算二进制数中所包含的1000的个数、100的个数、10的个数和1的个数。方法2除10取余。下面举例介绍第一种方法。流程图如下:③二进制数→BCD15YN二进制数AX令(DL)=0(AX)-10000?(DL)+1(AX)+1000(AX)DL存至缓冲区令(DL)=0YN(AX)-100?(DL)+1(AX)+10(AX)存DL存AL返回DOS求100的个数,结构同上A16汇编程序如下:DATASEGMENTBNUMDB270FHDNUMDB4DUP(?);存放BCD码的缓冲区DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATABINBCDPROCFARBEGIN:MOVAX,DATAMOVDS,AXMOVAX,BNUM;取二进制数LEABX,DNUM;BCD码缓冲区首地址送BX17;计算百位的个数MOVDL,0;千位的个数计数器AGAIN1:SUBAX,1000;(AX)-1000JCNEXT1;若≤0,则退出循环INCDL;(DL)+1JMPAGAIN1NEXT1:ADDAX,1000;(AX)←(AX)+1000MOV[BX],DL;存千位的个数;计算百位的个数MOVDL,0;百位的个数计数器AGAIN2:SUBAX,100;(AX)-100JCNEXT2INCDLJMPAGAIN2NEXT2:ADDAX,100MOV[BX+1],DL;存百位的个数18MOVDL,0;十位的个数计数器AGAIN3:SUBAX,10;(AX)-10JCNEXT3INCDLJMPAGAIN3NEXT3:ADDAX,10MOV[BX+2],DL;存十位的个数MOV[BX+3],AL;存个位的个数MOVAH,4CHINT21HBINBCDENDP;CODEENDSENDBEGIN19④BCD→ASCII前面举例介绍过,略。⑤二进制串转换为ASCII码一个二进制位串若要送显示或打印,需把串中每一位(0或1)化为ASCII码。思路:先将目标串全部预置为30H,再把每个二进制位逐位左移至CF,然后判CF=0?若是,取下一位;若不是,将31H送此单元。流程图如下:20初始化用’0’填满串取要转换的数左移1位存入‘1’结束CF=1?转换完?调整指针NN21汇编程序如下:DATASEGMENTNUMDW6F78HSTRINGDB16DUP(?)DATAENDS;CODESEGMENTASSUMECS:CODE,DS:DATABINCAPROCFARBEGIN:MOVAX,DATAMOVDS,AXMOVES,AXCLDLEADI,STRINGMOVCX,16;串的长度22MOVAL,30HREPSTOSB;串中全部填充为‘0’MOVCX,16LEADI,STRINGMOVAL,’1’MOVBX,NUM;(BX)=6F78HAGAIN:RCLBX,1;含进位位循环左移JNCNEXT;若为0,转MOV[DI],AL;若为1,对应位送入’1’NEXT:INCDILOOPAGAIN23MOVAH,4CHINT21HBINCAENDPCODEENDSENDBEGIN242.子程序的参数传递编写子程序时,很重要的一个工作是如何把参数传给子程序,这个过程叫参数传送。传送方法有:把参数放在CPU内部寄存器中把参数放在变量中把参数放在地址表中利用堆栈传送参数25下面举例介绍第4种方法,它通常在主程序中把参数或参数地址保存在堆栈中,而在子程序中将参数从堆栈取出来。例:把一个用十六进制表示的字→ASCII码,然后送到屏幕上显示。汇编程序如下:DATASEGMENTNUMDW25AFH;要显示的数STRINGDB4DUP(?),13,10,’$’DATAENDS26STACKSEGMENTDB100DUP(?)TOPEQU$STACKENDS;CODESEGMENTASSUMECS:CODE,DS:DATA,ES:DATA,SS:STACKBEGIN:MOVAX,DATAMOVDS,AXMOVES,AXMOVAX,STACKMOVSS,AXMOVSP,TOPLEABX,STRING;取变量偏址PUSHBX;将偏址压栈PUSHNUM;将变量压栈00020064H0062H(SP)25AF0060H堆栈27CALLBINHEX;(SP)=005EHCS:0113LEADX,STRING;(DX)=0002HMOVAH,9INT21HMOVAH,4CHINT21H;***********************BINHEXPROCPUSHBP;(SP)=005CHMOVBP,SP;(BP)=005CHPUSHAX;(SP)=005AHPUSHDI;(SP)=0058HPUSHCX;(SP)=0056HPUSHDX;(SP)=0054H00020064H0062H25AF0060H005EH0113005CH(SP)返回地址(IP)原(BP)2800020064H0062H25AF0060H005EH0113xxxx005CH(BP)PUSHF;(SP)=0052HMOVAX,[BP+4];(AX)=25AFHMOVDI,[BP+6];(DI)=0002HADDDI,LENGTHSTRING-4;(DI)=0005HMOVDX,AX;(DX)=25AFHMOVCX,4STD;从后往前存AGAIN:ANDAX,0FH;第一次(AX)=000FHCALLHEXD;转换为ASCII码STOSBPUSHCXMOVCL,4SHRDX,CL;逻辑右移4位MOVAX,DX;第1次(AX)=025AHPOPCXLOOPAGAIN;(CX)-1=0?不等,转+429POPFPOPDXPOPCXPOPDIPOPAXPOPBPRET4BINHEXENDP;********************HEXDPROCCMPAL,0AHJLLPADDAL,7LP:ADDAL,30HRETHEXDENDPCODEENDSENDBEGIN0064H0062H0060H005EH005CH000225AF0113xxxx(SP)30从本例可知,通过堆栈传递的两个参数分别为:变量NUM的内容25AFH和变量STRING的偏移地址。这两个参数在调用子程序之前压入堆栈,当CALL指令返回时,其(SP)=0060H,不是初值0064H。故采用带参数返回指令RET4。本例重点掌握:*进一步了解堆栈的使用*学会RETn的应用*子程序嵌套31其他例子宏的使用例子逻辑尺的例子查表法求立方值作业:p1944.6(1),4.10,4.17,4.18(用逻辑尺)