2012-04-23 94 views
1

**为澄清和“更清晰”的代码进行了编辑。8086装配(TASM):将ASCII字符值显示为HEX

我试图从键盘(任何字符)接受一个字符,并将它的ASCII值转换为十六进制,然后显示它。

我知道如何从基地10转换为十六进制,但只是为了确保我没有使用不正确的术语:

如果我在为我的ASCII值输入“C”,它的十进制值是63。 63除以16(十六进制是16进制)= 3.9375。稍后保存3的商数。剩余*基数(.9375 * 16)= 15. 15是十六进制字符“F”。

商数除以基数(3/16)= 0.1875。商数为零,所以这是转换的最后一步。剩余*基数(.1875 * 16)= 3

从最后到第一个读取它们(如果考虑堆栈,请先读取“先进先出”),然后将“3F”数字“63”(这是ASCII为“c”)

这是正确的,是吗?

这是很简单的阅读,我希望。我只是从键盘(AL)获取字符,将BX设置为除数(基数为16),然后将AL除以BX,将余数存储在堆栈中,然后在堆栈中循环并尝试显示它。

我觉得我的问题是我的乘法和INT 21H/02H有问题。我不确定是否需要添加30h才能显示该字符或不...

最重要的是,我甚至不确定是否需要在该点(显示)仍然无论如何,因为我还没有想出如何将10-15转换为十六进制的AF。

我试着和我的老师说话,等了30分钟后,他完成了和我班上另一群学生的谈话(关于他班的另一个班级的事情,而不是这个......这让我非常厌烦一点),我得到的最多是“重新开始”。

当问到“使用SHR和SHL怎么办?”正如它向我指出的那样,但我被告知可以不这样做,并且我不能使用这些命令(它们在课堂上没有被覆盖)。

我在做什么错误的任何输入?谢谢!

CHAR2HEX PROC     ; Accept a character, print it's ascii value in hex. 

     MOV DX, OFFSET AskChar  ; Display prompt 
     MOV AH, 09H 
     INT 21H 

     MOV AX, 0     ; Clear AX 

     MOV AH, 07H     ; Get keyboard input w/ no echo (AL) 
     INT 21H 

     MOV BX, 16     ; Set up the divisor (base 16) 
     MOV CX, 0     ; Initialize the counter 
     MOV DX, 0     ; Clear DX 

     Divide:       
            ; Dividend (what's being divided) in DX/AX pair, Quotient in AX, Remainder in DX. 
      DIV BX     ; Divide (will be word sized). 
      PUSH AX     ; Save DX (the remainder) to stack. 

      ADD CX, 1    ; Add one to counter 

      MOV DX, 0    ; Clear Remainder (DX) 
      CMP AX, 0    ; Compare Quotient (AX) to zero 
      JNE Divide    ; If AX not 0, go to "Divide:" 

     Multiply: 
            ; Multiply remainder (from stack) by 16 to get hex value.    
      MOV DX, 0    ; Clear DX   
      POP AX     ; Get remainder from stack into AX. 

      MUL BX     ; Multiply AX * BX. (DX= high order bits, AX = low order bits) 
      MOV DX, AX 

      SUB DL, 30h    ; ADD 30h to DL 
      MOV AH, 02h    ; 02h to display AH (DL) 
      INT 21H     ; Send to DOS 

      LOOP Multiply   ; If more to do, Multiply again 
            ; LOOP subtracts 1 from CX. If non-zero, loop. 
      RET 
    CHAR2HEX ENDP 
END START 

EDITED **

我终于得到它!我能够让程序返回键盘上按下的ascii字符的十六进制值,但只有当每个余数是0到9时才起作用。它不会显示A到F,而是使用冒号,分号等...

我在网上查看了一个Ascii/Deicmal/Hex图表,并注意到字符0到9是从30h到39h。但字符A(十六进制为10)直到40h才开始。所以我改变了程序,所以如果这个值大于39h,它会在DL上加7h,然后显示它。

CHAR2HEX PROC     ; Accept a character, print it's ascii value in hex. 

     MOV DX, OFFSET AskChar  ; Display prompt 
     MOV AH, 09H 
     INT 21H 

     MOV AH, 07H     ; Get keyboard input w/ no echo (AL) 
     INT 21H 

     MOV CL, AL     ; Copy user input (AL) to CL 
     MOV AX, 0     ; Clear AX (get rid of HO bits) 
     MOV AL, CL     ; Copy user input back into AL 

     MOV BX, 16     ; Set up the divisor (base 16) 
     MOV CX, 0     ; Initialize the counter 
     MOV DX, 0     ; Clear DX 

     Div2:       
            ; Dividend (what's being divided) in DX/AX pair, Quotient in AX, Remainder in DX. 
      DIV BX     ; Divide (will be word sized). 
      PUSH DX     ; Save DX (the remainder) to stack. 

      ADD CX, 1    ; Add one to counter 
      MOV DX, 0    ; Clear Remainder (DX) 
      CMP AX, 0    ; Compare Quotient (AX) to zero 
      JNE Div2    ; If AX not 0, go to "Div2:" 

     getHex2: 
      MOV DX, 0    ; Clear DX. 
      POP DX     ; Put top of stack into DX. 
      ADD DL, 30h    ; Conv to character. 

      CMP DL, 39h 
      JG MoreHex2 

     HexRet2:   

      MOV AH, 02h    ; 02h to display AH (DL) 
      INT 21H     ; Send to DOS 

      LOOP getHex2   ; If more to do, getHex2 again 
            ; LOOP subtracts 1 from CX. If non-zero, loop. 
      JMP Skip2 
     MoreHex2: 
      ADD DL, 7h 
      JMP HexRet2    ; Return to where it left off before adding 7h. 
     Skip2: 
      RET 
    CHAR2HEX ENDP 
+0

我可以让我的程序从ASCII转换为十六进制,但只有当每个值为9或更小。 因此,例如,使用“a”作为输入会导致在屏幕上打印“61”。 “b”导致“62”。但如果我输入“K”,结果为“4;”,并且实际上并没有将最后一位数字转换为“A-F”... 这就是我目前无法弄清楚的。这东西很难! – SalarianEngineer 2012-04-25 22:27:20

+0

你想要编写'if(a <= 9)a + = 0x30 else a + = 0x41'(假设a总是在0到15之间)来获得这些数字。这不是很难,但很乏味。 :) – vhallac 2012-04-26 10:01:13

回答

1

您的基地10转换逻辑看起来不错:每个从除以10,会给你一个数字余,他们会从最低显著数字最显著一个排序,所以你需要扭转在打印之前获得数字。将它们推入堆栈并在完成时弹出它们,将以非常紧凑的方式进行反转。

对于转换为十六进制,操作是相同的:除以16,得到余数,反转和打印。但是,有几点需要注意:除以16将右移4位。其余的是value AND 0fH,所以你实际上并不需要任何算术运算。位移和AND操作就足够了。而且,你甚至不需要涉及堆栈。您可以从最重要的半字节(四位)到最不重要的一个,并在计算它们时进行打印。你似乎正在努力的第二件事是将一个半字节转换为十六进制数字。仅仅添加30h是不够的。对于小数点来说已经足够了,但对于十六进制值,您也可以得到10到15的数字。这些需要被添加到41h(ASCII中的'A')减10。或者,您可以在表格中将数字“0”设置为“9”和“A”设置为“F”,并将它们索引为要打印的半字节值。

您可能还想写一个例程,从输入中读取一个数字。读取每个数字,直到您读取换行符,将字符转换为十进制值,并更新一个累加器,以保留您读取的数字。你将需要使用它来同时使用十六进制和十进制输出函数。

+0

Vhallac,我很抱歉,如果这是多余的,但我在原帖中发布了新的代码(带有编辑)......我不确定它是否通知您这个或没有,但如果您有你能看一下吗? – SalarianEngineer 2012-04-25 20:38:26

+0

特别困难的是,当你写到“value AND 0fh”时......我对这个时间根本不熟悉。 – SalarianEngineer 2012-04-25 20:53:17

+0

你似乎试图把整个程序放在一起,而没有确定每件作品都很好。如果我是你,我会从每个子程序开始,首先打印十进制或十六进制值,然后用常量数据(不是从键盘读取)进行测试。一旦你有了这些构建模块,你就可以从键盘上添加阅读,等等。下面的dwelch的答案是非常明智的:你首先使用你熟悉的语言对算法进行分类。 – vhallac 2012-04-26 09:52:22

1

先用C或其他语言编写程序。不要使用语言库,例如,不要使用printf(“%x \ n”,数字)来显示十六进制,但可以按照您的建议将该数字重复除以10,并将它们保存在某处。现在请记住,除以十之后的余数(模)是0-9之间的某个值,以便在ascii中显示此处,您需要像上面提到的那样添加0x30。 123变为12剩余3,然后12变为1剩余2,并且1变为0剩余1,1 + 0x30 = 0x31显示2 + 0x30变为0x32显示,3 + 0x30变为0x33显示。

十六进制没有什么不同,基数是16而不是10.由于vhallac提到,虽然你可以掩码和移位,而不是使用除法运算符。使用基本操作(add,sub,divide,shift等)的低级别,然后用汇编语言重新编写该代码。

最终,您可能会达到不需要用其他语言证明您的程序并以asm开头的地步。

+0

嗯...不太清楚如何在回复中发布代码,所以我只是在我自己的帖子上发表评论,我猜?底线: 我在C#中编写了一个控制台应用程序,要求输入一个数字。然后我把这个数字除以10,将余数和商数保存在不同的变量中,将余数输出到列表(我的“堆栈”)。毕竟完成后,我有一个循环遍历列表,并为每个值添加30,附加一个“h”,并打印出来。我不确定这是否是一个“捷径”(添加“h”),因为我不确定如何在C#中使用Hex做任何事情。 – SalarianEngineer 2012-04-23 22:12:49