我有我的第一个汇编程序运行在ATmega16上,现在我想转换一个十进制数,这是保存在一个寄存器称为速度到一个十六进制数的二进制形式,可以显示在一个7段显示。例如,speed保存了十进制0101 0000(80),我想将其转换为十六进制形式0011 0010(50)。我如何做到这一点的任何小数保存在速度?谢谢你能提供的任何帮助。
qrjkbowd1#
二进制和十进制是两种不同的基数。寄存器中有整数的正常方法是纯二进制,不涉及十进制。该二进制数的十进制或十六进制表示形式便于人们查看,但这不会改变寄存器中的实际内容。在您的例子中,0b0101'0000是十进制80,十六进制0x50;你可以在C++源代码中用这三种方式中的任何一种来写常量。注意,高4位是0101,5的二进制,低4位是0000(0)。基数16是2的幂,因此4位组Map到十六进制数字。要获得ASCII codes,可以使用查找表,或者根据半字节值是否>= 10添加'0'或'A'。(或者为大于10的数字添加一个额外的7('A' - '0'),所以它只是一个if,而不是if/else)。要获得7段显示代码,可以使用由4位整数索引的查找表。在AVR汇编中,您可以使用and和swap指令将8位整数的两个4位半部分隔离,就像编译器从该源代码中生成的那样
0b0101'0000
80
0x50
0101
5
0000
0
'0'
'A'
7
'A' - '0'
and
swap
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位以模拟将它们移出。)
mov
andi
0011 0010
0b0101
0b1010
50
不要通过创建一个二进制整数来进行基数转换,该二进制整数的十进制数字是您想要用于其他基数的数字。这对于像0xa5这样的数字不起作用,因为十进制只允许最多9位的数字,对于像8或2这样的较小基数,你最多只能在32位整数中存储1111111111,所以只有10位。而且当你想用这些数字做任何事情的时候,它也不能让你很容易地把它们拿出来。
0xa5
8
2
1111111111
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字符数字。
2条答案
按热度按时间qrjkbowd1#
二进制和十进制是两种不同的基数。寄存器中有整数的正常方法是纯二进制,不涉及十进制。该二进制数的十进制或十六进制表示形式便于人们查看,但这不会改变寄存器中的实际内容。
在您的例子中,
0b0101'0000
是十进制80
,十六进制0x50
;你可以在C++源代码中用这三种方式中的任何一种来写常量。注意,高4位是0101
,5
的二进制,低4位是0000
(0
)。基数16是2的幂,因此4位组Map到十六进制数字。要获得ASCII codes,可以使用查找表,或者根据半字节值是否>= 10添加
'0'
或'A'
。(或者为大于10的数字添加一个额外的7
('A' - '0'
),所以它只是一个if,而不是if/else)。要获得7段显示代码,可以使用由4位整数索引的查找表。在AVR汇编中,您可以使用
and
和swap
指令将8位整数的两个4位半部分隔离,就像编译器从该源代码中生成的那样(Godbolt)
存储当然是可选的;如果你想立即使用这些值,你不需要一个数组来存储它们。这样就可以编写一个C函数来生成两个输出,这样我们就可以查看编译器生成的asm。
所以实际上只需要
mov
+swap
+2xandi
指令来隔离两个半字节,然后我们可以将其Map到十六进制数字。AVR一次只能移位1位,swap
除外,它旋转4位。(因此,我们必须屏蔽掉高4位以模拟将它们移出。)0011 0010
(十进制50)**:你可以通过将0b0101
乘以10(0b1010
)得到它,但是你可以将它再次分成5
和0
的唯一方法是除以10(0b1010
),这在计算上要困难得多。这是没有意义的,你有十六进制0x50
,而不是十进制50
。不要通过创建一个二进制整数来进行基数转换,该二进制整数的十进制数字是您想要用于其他基数的数字。这对于像
0xa5
这样的数字不起作用,因为十进制只允许最多9位的数字,对于像8
或2
这样的较小基数,你最多只能在32位整数中存储1111111111
,所以只有10位。而且当你想用这些数字做任何事情的时候,它也不能让你很容易地把它们拿出来。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字符数字。