assembly 如何将二进制十进制转换为二进制十六进制?

9rnv2umw  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(200)

我有我的第一个汇编程序运行在ATmega16上,现在我想转换一个十进制数,这是保存在一个寄存器称为速度到一个十六进制数的二进制形式,可以显示在一个7段显示。例如,speed保存了十进制0101 0000(80),我想将其转换为十六进制形式0011 0010(50)。我如何做到这一点的任何小数保存在速度?
谢谢你能提供的任何帮助。

qrjkbowd

qrjkbowd1#

二进制和十进制是两种不同的基数。寄存器中有整数的正常方法是纯二进制,不涉及十进制。该二进制数的十进制或十六进制表示形式便于人们查看,但这不会改变寄存器中的实际内容。
在您的例子中,0b0101'0000是十进制80,十六进制0x50;你可以在C++源代码中用这三种方式中的任何一种来写常量。注意,高4位是01015的二进制,低4位是00000)。
基数16是2的幂,因此4位组Map到十六进制数字。要获得ASCII codes,可以使用查找表,或者根据半字节值是否>= 10添加'0''A'。(或者为大于10的数字添加一个额外的7'A' - '0'),所以它只是一个if,而不是if/else)。要获得7段显示代码,可以使用由4位整数索引的查找表。
在AVR汇编中,您可以使用andswap指令将8位整数的两个4位半部分隔离,就像编译器从该源代码中生成的那样

void foo(unsigned char in, unsigned char *out)
{
    out[0] = in>>4;       // high hex digit is first in printing order
    out[1] = in & 0x0f;   // low hex digit.
//  Actually just 0..15 integers, not mapped to ASCII or 7-segment codes
}

(Godbolt)

foo(unsigned char, unsigned char*):
        mov r30,r22
        mov r31,r23        # output pointer
        mov r25,r24        # copy the first input

        swap r25
        andi r25, 15   # emulate >> 4  with SWAP + ANDI with 0xf
        st Z,r25

        andi r24, 15   # isolate the low 4 bits
        std Z+1,r24

        ret

存储当然是可选的;如果你想立即使用这些值,你不需要一个数组来存储它们。这样就可以编写一个C函数来生成两个输出,这样我们就可以查看编译器生成的asm。
所以实际上只需要mov + swap +2x andi指令来隔离两个半字节,然后我们可以将其Map到十六进制数字。AVR一次只能移位1位,swap除外,它旋转4位。(因此,我们必须屏蔽掉高4位以模拟将它们移出。)

    • 您永远不希望寄存器中的第一位是0011 0010(十进制50)**:你可以通过将0b0101乘以10(0b1010)得到它,但是你可以将它再次分成50的唯一方法是除以10(0b1010),这在计算上要困难得多。这是没有意义的,你有十六进制0x50,而不是十进制50

不要通过创建一个二进制整数来进行基数转换,该二进制整数的十进制数字是您想要用于其他基数的数字。这对于像0xa5这样的数字不起作用,因为十进制只允许最多9位的数字,对于像82这样的较小基数,你最多只能在32位整数中存储1111111111,所以只有10位。而且当你想用这些数字做任何事情的时候,它也不能让你很容易地把它们拿出来。

    • 脚注1:**计算机以位存储所有内容,因为它们使用二进制逻辑,开或关,而不是10或16个电压电平。你可以使用这些位的另一种方式是BCD,二进制编码十进制。在这种格式中,每个十进制数字使用4位,并且在添加时必须手动对大于10的数字进行 Package 和进位。或解压缩BCD,其中每个字节存储一个十进制数字,从而节省解压缩工作。
j8ag8udp

j8ag8udp2#

例如,speed保存了十进制0101 0000(80),我想将其转换为十六进制形式0011 0010(50)。我如何做到这一点的任何小数保存在速度?
数字8010是相同的数字并且等于5016,5016也是相同的数字并且等于010100002 -它们都表示相同的精确数值。数字基数不会改变数值-改变数字基数改变数字字符串而不是它的数值。
让我们看看其他基数中的数字:5010也是3216,与001100112相同。
8010和5010之间的关系是一个错误的等价-没有相等关系-这些只是不同的数字。8010只是5016。
我们在十进制中并没有十六进制的概念,无论是二进制还是其他,这就是原因。例如,考虑7910,它在十六进制/进制16中与4F 16相同,在二进制中是010011112。现在,我们不能简单地将4F表示为十进制数,无论是否等价,因此问题是您希望7910的基数为2?
如果你想将数字转换为十六进制字符串,你必须考虑数字范围是0-9加上A-F,因为基数16有16个不同的1字符数字。

相关问题