Java串口通信:从十六进制字符串到字节数组的正确转换与发送

简介: Java串口通信:从十六进制字符串到字节数组的正确转换与发送

在嵌入式开发、物联网、自动化控制等领域,串口通信作为一种常见且可靠的通信方式,扮演着重要角色。本文将聚焦于Java环境中串口通信的核心环节——如何正确地将十六进制字符串转换为字节数组,并通过串口发送。我们将探讨常见的误区、正确处理流程、相关代码实现及应用场景,帮助开发者避免混淆,提升串口数据传输的准确性和效率。

一、内容

1. 十六进制字符串与字节数组的关系

在串口通信中,数据通常以字节形式传输。有时,为了便于人眼阅读和编写,这些字节值会被编码为十六进制字符串。例如,字节序列“53 A8 C0 00 00 20 41 00…”代表一组待发送的字节数据。

2. 错误的处理方式与问题

在实际编程过程中,开发者可能会遇到如下两种典型错误:

错误一:直接调用 getBytes() 方法

String hexString = "53 A8 C0 00 00 20 41 00...";
byte[] data = hexString.getBytes();

因为Java的 getBytes() 方法不会直接接受十六进制字符串作为输入并将其转换为字节数组,而是将十六进制字符串视作普通文本,将每个字符转换为其对应的ASCII值,而非字节值。输出结果与预期不符。

错误二:未正确处理带空格的十六进制字符串

String hexString = "53 A8 C0 00 00 20 41 00...";
byte[] data = hexString.replaceAll("\\s", "").getBytes(StandardCharsets.UTF_8);

虽然去除了空格,但使用 getBytes() 方法依然会将字符转换为ASCII值。此外,UTF-8编码可能导致非预期的字节序列。

3. 正确的十六进制字符串转字节数组方法

private static byte[] hexStringToByteArray(String s) {
    String[] hexParts = s.split(" ");
    byte[] data = new byte[hexParts.length];
    for (int i = 0; i < hexParts.length; i++) {
        data[i] = (byte) Integer.parseInt(hexParts[i], 16);
    }
    return data;
}

此方法首先使用 split(" ") 将十六进制字符串按照空格分割成多个部分,然后逐个将每个部分转换为字节并放入数组中。


注意:如果字符串中的空格不规则,或者有额外的非十六进制字符,还需要进一步的预处理步骤来确保输入的有效性和准确性。

4.Java中字节溢出问题

Java中的byte类型是有符号的,其值域范围为-128到127。当处理十六进制数值时,如果该数值对应的十进制值超过127,转换为byte类型时会触发字节溢出,导致结果以负数形式呈现。


举例说明:十六进制A8转为十进制

以十六进制数A8为例,其对应的十进制数为168。然而,当我们将A8视作一个有符号的8位字节(即byte类型)时,其解释会发生变化。

  1. 十六进制转二进制A8对应的二进制形式为10101000
  2. 识别符号位:在8位带符号整数中,最高位(最左边的位)为符号位。对于10101000,最高位为1,表明这是一个负数。
  3. 计算负数绝对值:对于负数,其补码表示方法为:取反加一得到原码的补码。A8的补码为01010111,转换为十进制为87
  4. 得出最终负数:根据补码计算规则,负数的值等于-(-87 + 1),即-88。因此,在8位有符号整数的表示下,十六进制数A8对应着十进制的-88

综上所述,A8在Java的byte类型中表现为-88,而非其原本的十进制值168。这是由于byte类型的有符号特性以及其有限的值域范围(-128到127)导致的。为清晰展示字节数据的真实数值,可以先将其转换为无符号整数类型再进行打印或处理。

5.Java不支持无符号类型

Java编程语言并未像C或C++那样提供直接的无符号整数类型,如unsigned char。在Java中,所有的基本整数类型(如byteshortintlong)均是有符号的,意味着它们既能表示正数,也能表示负数。


当需要处理无符号字节数据时,可以采用特定方法模拟其行为。例如,当从串口接收一个字节并希望将其作为无符号8位整数对待时,可以将byte转换为int类型,并确保正确解析其正数值。以下是一个具体的转换示例:


byte signedByte = (byte) 0xA8; // 假设为从串口接收到的有符号字节数据
int unsignedInt = signedByte & 0xFF; // 通过位运算将字节转换为无符号整数
System.out.println(unsignedInt); // 输出:168


这里,使用位与操作符(&)与常量0xFF(二进制全1,相当于十进制的255)进行位运算。由于byte只有8位,其余高位均为0,与0xFF进行位与运算相当于保留其原有的8位二进制值,同时将高位补足为0,从而得到一个无符号的int值。


尽管原始的十六进制数A8(对应十进制168)在Java的byte类型中可能表现为负数(如-88),通过上述转换,我们能够准确地以无符号整数形式展示其原始数值168。这种转换方法在处理串口通信、网络协议、文件读写等涉及字节数据操作的场景中尤为有用,有助于消除因有符号溢出导致的负数表示带来的混淆,确保数据的正确解析。

二、总结

  • 区别:错误的处理方式将十六进制字符串视为普通文本,导致输出的是字符的ASCII值而非原始字节。正确的方法则是将每个十六进制字符对转换为对应的字节值。
  • 应用场景:串口设备配置、传感器数据采集、通信协议实现等场景均涉及十六进制字符串到字节数组的转换。


目录
相关文章
|
2天前
|
Java
Java获取字符串最后一位
【5月更文挑战第9天】Java获取字符串最后一位
26 5
|
2天前
|
监控 Java 物联网
Java串口通信技术探究1:深入理解RXTX库
Java串口通信技术探究1:深入理解RXTX库
32 2
|
1天前
|
Java 索引
String字符串常用函数以及示例 JAVA基础
String字符串常用函数以及示例 JAVA基础
|
1天前
|
Java
Java中两个字符串进行大小比较
Java中两个字符串进行大小比较
17 5
|
2天前
|
存储 Java 索引
【JAVA基础篇教学】第十一篇:Java中字符串操作详解
【JAVA基础篇教学】第十一篇:Java中字符串操作详解
|
2天前
|
Java
代码实例演示Java字符串与输入流互转
代码实例演示Java字符串与输入流互转
|
2天前
|
存储 缓存 前端开发
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
44 3
|
2天前
|
安全 IDE Java
Java串口通信技术探究2:RXTX库单例测试及应用
Java串口通信技术探究2:RXTX库单例测试及应用
29 4
|
2天前
|
存储 XML 缓存
Java字符串内幕:String、StringBuffer和StringBuilder的奥秘
Java字符串内幕:String、StringBuffer和StringBuilder的奥秘
26 0
|
8月前
|
Java 容器
Java可变字符串StringBuffer、StringBuilder
Java可变字符串StringBuffer、StringBuilder
61 0