从16位创建4个字节

3
我有16位。在每个位中,我可以设置一些属性并发送到COM端口(税务打印机)。 例如:如果勾选了0位,则在支票上显示徽标。
这16位需要转换为4个字节并发送到COM端口。 例如:如果勾选了0位,则4个字节将是0x30、0x31、0x30、0x30。 通过COM端口监视API,我可以得到字节结果。
我该怎么做才能从16位获取4个字节?
其他例子:
- 勾选1位 - 0x30、0x32、0x30、0x30 - 勾选2位 - 0x30、0x34、0x30、0x30 - 勾选0和2位 - 0x30、0x35、0x30、0x30 - 勾选0和9位 - 0x30、0x31、0x30、0x32 - 勾选0、1、2、3、4、5、9位 - 0x33、0x46、0x30、0x32

5
“0位校验 => 0x30,0x31,0x30,0x30”这个例子背后的逻辑是什么? - André Staltz
我使用Windows程序向打印机发送命令,并通过COM端口监视API捕获此示例。 - smie
1
我们无法理解它。能否展示更多可能的组合和例子? - adarshr
2
那么我猜您不知道该示例背后的逻辑?能否指向 API?给我们更多关于您问题的上下文。 - André Staltz
1位被检查 - 0x30、0x32、0x30、0x30; 2位被检查 - 0x30、0x34、0x30、0x30; 0和2位被检查 - 0x30、0x35、0x30、0x30; 0和9位被检查 - 0x30、0x31、0x30、0x32。 - smie
显示剩余2条评论
4个回答

2
请注意,ASCII码中的0x30等同于字符'0'。根据我看到的情况,你正在以十六进制的形式传输这16个比特位,并将其分为两个字节,其中第一个字节包含0-7位,第二个字节包含8-15位,即您要传输以下内容:
- 位于4-7的十六进制数字 - 位于0-3的十六进制数字 - 位于12-15的十六进制数字 - 位于8-11的十六进制数字
需要更多数据点才能确定,但这符合您上面的示例。
bit 0 set encodes to string "0100" = 0x30 0x31 0x30 0x30
bit 1 set                   "0200" = 0x30 0x32 0x30 0x30
bit 2 set                   "0400" = 0x30 0x34 0x30 0x30
0+2                         "0500" = 0x30 0x30 0x30 0x30
0+9                         "0102" = 0x30 0x31 0x30 0x32
0,1,2,3,4,5,9               "3F02" = 0x33 0x46 0x30 0x32

例如,在Java中,如果您的位(bits)存储在单个整数n中,您可能需要:

String output = Integer.toHexString((n >> 4) & 0xf)
              + Integer.toHexString(n & 0xf)
              + Integer.toHexString((n >> 12) & 0xf)
              + Integer.toHexString((n >> 8) & 0xf);
byte[] data = output.toUpperCase().getBytes("ASCII");

通过字符串,或者

byte[] data = new byte[4];
data[0] = (byte)((n >> 4) & 0xf);
data[1] = (byte)(n & 0xf);
data[2] = (byte)((n >> 12) & 0xf);
data[3] = (byte)((n >> 8) & 0xf);
for(int i = 0; i < 4; ++i) {
    data[i] += (data[i] < 10) ? '0' : ('A' - 10);
}

避免字符串。

要将这四个字节解析回一个int,您可以使用

int bits = (((data[0] & 0xf) + ((data[0] >= 'A') ? 9 : 0)) << 4)
           | ((data[1] & 0xf) + ((data[1] >= 'A') ? 9 : 0))
           | (((data[2] & 0xf) + ((data[2] >= 'A') ? 9 : 0)) << 12)
           | (((data[3] & 0xf) + ((data[3] >= 'A') ? 9 : 0)) << 8);

显然这里没有输入检查 - 我假设我们以预期的格式获取输入。括号中的主要部分只需从字符串中解析出一个十六进制数字 - 如果您想要,可以重构它或实现更稳健的内容。


0,1,2,3,4,5,9 位被检查 - 0x33 0x46 0x30 0x32 - smie
是的,这仍然适用:它作为一个字符串是“3F02”,因此它使用大写十六进制。 - Rup
抱歉,我不明白如何使用这段代码。我的代码是:int n = 0000001000111111; byte[] data = new byte[4]; data[0] = (byte) ((n >> 4) & 0xf); data[1] = (byte) (n & 0xf); data[2] = (byte) ((n >> 12) & 0xf); data[3] = (byte) ((n >> 8) & 0xf); for(int i = 0; i < 4; ++i) { data[i] += (data[i] < 10) ? '0' : ('A' - 10); } … 结果:{0x34},{0x39},{0x39},{0x32}。 - smie
对不起,我是指将n作为整数而不是二进制位的字符串。你可以使用n = Integer.parseInt("0000001000111111", 2);,或者你可以自己组装:n = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 9); 或者,如果你使用的是Java 7,有一个二进制常量前缀:n = 0b0000001000111111; - Rup
Rup,它工作了!谢谢!也许你能说一下如何将0x33、0x46、0x30、0x32转换成0000001000111111? - smie

0

不确定您的意思:

您有16位,即仅为2个字节,因此您可以将前2个字节保留为0,并在最后2个字节中使用您的16位...

Byte1: 0000 0000
Byte2: 0000 0000
Byte3: first 8 bits of your 16 bits
Byte4: second 8 bits of your 16 bits

编辑:我不明白你是如何得到0x30、0x30、0x31、0x30的。

0x代表十六进制。

0x30十六进制 = 0011 0000 二进制。 所以我不明白为什么要使用0x30而不是只用0x00...


0

这个问题有点开放性,我假设你的意思是:

我必须检查一个16位数据类型的每一位是否被设置。如果设置了,则必须向COM端口发送数据。我需要发送的数据取决于被设置的位。顺便说一下,我需要发送的数据始终为4个字节。

假设需要检查的位作为Java int输入,即一个32位整数,其中高16位始终为0。我建议使用BitSet来检查位,并使用数组定义如果设置了位要发送的内容:

private static final byte[][] BYTES_TO_SEND = new byte[][] { { 0x30, 0x31, 0x30, 0x30 }, // 如果检查到第0位,则发送的数据 { 0x42 }, // 如果检查到第1位,则发送的数据 // ... 如果检查到第2位、第3位等,则发送的数据 };

private OutputStream com;

private static final byte[][] BYTES_TO_SEND = new byte[][] {
    { 0x30, 0x31, 0x30, 0x30 }, // data to send if bit #0 is checked
    { 0x42 }, // data to send if bit #1 is checked
// ... data to send if bit #2, #3, ... is checked
};

private OutputStream com;

public void initializeCOMFromBits(int bits) throws IOException {
  for (byte[] toSendIfSet : BYTES_TO_SEND) {
    if ((bits & 0x1) == 0x1) { // check if the lowest bit is set
      com.write(toSendIfSet);
    }
    bits >>>= 1; // shift all bits by one to the left
    // now the lowest bit if the bit that was second-to-lowest previously
  }
  assert bits == 0 : "There should be at most " + BYTES_TO_SEND.length + " bits set in the incoming bit set";
}

如果您的位是在一个 BitSet 中,那么将循环改为带有索引的 for 循环,并使用 .get(i) 检查第 i 位 - 如果已设置,则将 BYTES_TO_SEND[i] 发送到 COM 端口。

0

16位是2个字节。因此,如果将这2个字节分成两半,您将得到4个字节。

基本上就是这样。

byte b = ...;

byte firstHalf = (byte)((b & 0x0F) >> 4);
byte secondHalf = (byte)(b & 0xF0);

请注意,这基本上只是拆分操作,并不能提供您在问题中描述的结果。正如已经指出的那样,不清楚应该检查哪个“0”位以及如何获得那些0x30 0x31 0x30 0x30值(您无法仅通过将16位拆分为每个字节的4个数据包并将它们放入其中一个字节中来获得这些值)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接