8086汇编(TASM):将ASCII字符值显示为HEX

时间:2012-04-23 20:49:01

标签: assembly hex x86-16 tasm

**编辑澄清和“清洁”代码。

我正在尝试接受键盘上的字符(任何字符)并将其ASCII值转换为十六进制,然后显示它。

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

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

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

从上到后读取它们(“先进先出”,如果考虑堆栈),我得到“3F”作为十进制数“63”的十六进制值(这是“c”的ASCII )

这是对的,是吗?

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

我认为我的问题是我的乘法和我的INT 21H / 02H出了问题。我不确定是否需要添加30小时才能显示角色......

最重要的是,我甚至不确定我是否需要在那个时候(显示),因为我仍然没有弄清楚如何将10-15转换为A-F换十六进制。

我试着和我的老师说话,等了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

已编辑**

我终于明白了!我能够让程序返回键盘上推送的ascii char的十六进制值,但只有当每个余数为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

2 个答案:

答案 0 :(得分:1)

你的10号转换的逻辑看起来很好:除以10的每个余数都会给你一个数字,它们将从最低有效数字到最重要的数字排序,所以你需要在打印前反转获得的数字他们。将它们推入堆栈并在完成后弹出它们将以一种漂亮而紧凑的方式进行反转。

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

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

答案 1 :(得分:1)

首先用C语言或其他语言编写程序。不要使用语言库,例如不要使用printf(“%x \ n”,数字)来显示十六进制,但是按照你的建议将数字重复除以10s,将它们保存在某个地方。现在记住,除以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提到的那样,你可以屏蔽和移动而不是使用除法运算符。

一旦你的“程序”使用C语言或其他语言工作,使用基本操作(添加,子级,除法,移位等等)处于低级别,然后用汇编语言重写该代码。

最终,您可能会达到不需要用其他语言证明您的程序并从asm开始的程度。