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
4

4 回答 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

n即在Java中,如果你有你可能想要的单个整数中的位

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);

显然这里没有输入检查——我假设我们得到了预期格式的输入。括号中的主要位应该只解析字符串中的一个十六进制数字 - 如果需要,您可以重构它或实现更健壮的东西。

于 2012-04-05T09:19:23.480 回答
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 和将它们分别放入一个字节中)。

于 2012-04-05T08:57:40.663 回答
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 ...

于 2012-04-05T09:00:19.913 回答
0

这个问题有点容易解释,我假设您的意思如下:

如果设置了 16 位数据类型,我必须检查它的每一位。如果已设置,则必须将数据发送到 COM 端口。我需要发送什么数据取决于设置的位。顺便说一句,我需要发送的数据总是 4 个字节长。

让我们假设需要检查的位以 Java 的形式出现int,即一个 32 位整数,其中高 16 位始终为 0。我建议使用 BitSet 来检查位,使用数组来定义如果发送的内容该位已设置:

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

私人输出流 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 循环,并使用 - 检查第 i 位,.get(i)如果已设置,则发送BYTES_TO_SEND[i]到 COM 端口。

于 2012-04-05T09:17:54.497 回答