【问题标题】:Create 4 bytes from 16 bits从 16 位创建 4 个字节
【发布时间】:2012-04-05 08:43:35
【问题描述】:

我有 16 位。在每个位中,我可以设置一些属性并发送到 COM 端口(财务打印机)。 例如:如果选中 0 位,则在选中时显示 logo。

我需要将这 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

【问题讨论】:

  • 您的“0位检查=> 0x30, 0x31, 0x30, 0x30”示例背后的逻辑是什么?
  • 我使用 win 程序,向打印机发送命令,并从 COM 端口监控 API 捕获此示例。
  • 我们无法理解。你能告诉我们更多可能的组合和例子吗?
  • 所以我猜你不知道这个例子背后的逻辑是什么?将我们指向 API 怎么样?向我们提供您问题的更多背景信息。
  • 已检查 1 位 - 0x30、0x32、0x30、0x30; 2 位检查 - 0x30、0x34、0x30、0x30;检查 0 和 2 位 - 0x30、0x35、0x30、0x30;检查 0 和 9 位 - 0x30、0x31、0x30、0x32

标签: java serial-port type-conversion byte


【解决方案1】:

请注意,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 中,如果你有一个整数 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
  • 是的,这仍然适合:那是“3F02”作为字符串,所以它使用大写十六进制。
  • 对不起,我不明白如何使用这段代码。我的代码:int n = 0000001000111111;字节[]数据=新字节[4];数据[0] = (字节) ((n >> 4) & 0xf);数据[1] = (字节) (n & 0xf);数据[2] = (字节) ((n >> 12) & 0xf);数据[3] = (字节) ((n >> 8) & 0xf); for(int i = 0; i
  • 对,对不起 - 我的意思是 n 是一个整数,而不是二进制位的字符串。您可以使用n = Integer.parseInt("0000001000111111", 2);,也可以自己组装:n = (1 &lt;&lt; 0) | (1 &lt;&lt; 1) | (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4) | (1 &lt;&lt; 5) | (1 &lt;&lt; 9); 或者,如果您使用的是 Java 7,则有一个二进制常量前缀:n = 0b0000001000111111;
  • Rup,它的工作!谢谢!也许你可以说如何解开这个?从0x33、0x46、0x30、0x32到0000001000111111?
【解决方案2】:

不知道你的意思:

你有 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...

【讨论】:

    【解决方案3】:

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

    基本上是这样的

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

    但是请注意,这基本上只是拆分,不会提供您在问题中描述的结果。正如已经指出的那样,尚不清楚应该检查什么“0”位以及如何获得那些 0x30 0x31 0x30 0x30 值(仅将 16 位拆分为 4 和将它们分别放入一个字节中)。

    【讨论】:

      【解决方案4】:

      这个问题有点容易解释,我假设你的意思是:

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

      假设需要检查的位以 Java int 的形式出现,即高 16 位始终为 0 的 32 位整数。我建议使用 BitSet 来检查位和数组用于定义在设置位时发送的内容:

      私有静态最终字节[][] BYTES_TO_SEND = 新字节[][] { { 0x30, 0x31, 0x30, 0x30 }, // 如果位 #0 被检查,则要发送的数据 { 0x42 }, // 如果第 1 位被选中,则要发送的数据 // ... 如果位 #2、#3、... 被选中,则要发送的数据 };

      私有 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 端口。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-24
        • 1970-01-01
        • 2011-09-25
        相关资源
        最近更新 更多