Java读取称重机串口数据乱码问题求助(jSerialComm、Java 8)
解决Java+jSerialComm读取称重机串口乱码问题
嘿,我来帮你搞定这个串口读取乱码的问题!结合你的场景和代码来看,大概率是串口参数不匹配或者字符编码选错了,咱们一步步来排查:
1. 先确认串口核心参数是否完全匹配
串口通信的波特率、数据位、停止位、奇偶校验这几个参数,必须和称重机的配置完全一致,不然读取到的二进制数据本身就是错乱的,再怎么转编码都会出现乱码。
你可以通过jSerialComm的API设置这些参数,示例代码如下(记得替换成称重机手册上的实际参数):
thisPort.setBaudRate(9600); // 常见波特率有9600、19200等 thisPort.setNumDataBits(8); // 大多是8位数据位 thisPort.setNumStopBits(1); // 1位停止位 thisPort.setParity(SerialPort.NO_PARITY); // 无校验
2. 排查字符编码问题
你当前用的UTF-8编码,很多工业设备(比如称重机)其实用的是ASCII、GBK或者ISO-8859-1这类编码。尤其是ASCII,是工业串口设备最常用的编码。
建议你先直接读取原始字节,再尝试用不同编码解析,这样能直观看到问题所在:
InputStream is = thisPort.getInputStream(); byte[] buffer = new byte[1024]; int bytesRead; while (true) { try { if ((bytesRead = is.read(buffer)) > 0) { // 打印原始字节,对比正确数据的字节值(比如"N + 60 kg"的ASCII字节是[78,32,43,32,54,48,32,107,103]) System.out.println("原始字节: " + Arrays.toString(Arrays.copyOf(buffer, bytesRead))); // 尝试不同编码解析 String asciiStr = new String(buffer, 0, bytesRead, "ASCII"); String gbkStr = new String(buffer, 0, bytesRead, "GBK"); String isoStr = new String(buffer, 0, bytesRead, "ISO-8859-1"); System.out.println("ASCII解析结果: " + asciiStr); System.out.println("GBK解析结果: " + gbkStr); System.out.println("ISO-8859-1解析结果: " + isoStr); } } catch (Exception e) { System.err.println(e.getMessage()); if (e.getMessage().contains("shutdown or disconnected")) break; } }
从输出里找到能正确显示N + X kg的编码,之后就用这个编码来解析数据。
3. 避免依赖readLine()读取数据
readLine()是通过换行符(\n或\r\n)来判断一行结束的,但很多工业设备发送数据时可能不带换行符,或者用\r作为结束标志,这会导致readLine()一直等待,或者读取到不完整的片段,进而出现乱码。
更可靠的方式是读取字节数组,自己判断完整数据包的结束标志(比如你的称重机数据以 kg结尾),示例逻辑如下:
StringBuilder dataBuilder = new StringBuilder(); // 读取字节片段后拼接 dataBuilder.append(chunk); // 检查是否是完整数据包 if (dataBuilder.toString().endsWith(" kg")) { String fullData = dataBuilder.toString(); System.out.println("完整数据: " + fullData); // 这里可以提取重量数值 dataBuilder.setLength(0); // 重置构建器,准备下一个数据包 }
4. 清空串口缓冲区
打开串口后,缓冲区可能残留之前的旧数据,导致第一次读取出现乱码。你可以在打开串口后添加这行代码清空读缓冲区:
thisPort.clearPortBuffers(SerialPort.BUFFER_READ);
整合后的完整示例代码
import com.fazecast.jSerialComm.SerialPort; import java.io.InputStream; import java.util.Arrays; public class ScaleSerialReader { public static void main(String[] args) { // 替换成你的串口名,比如Windows的COM3,Linux的/dev/ttyUSB0 SerialPort thisPort = SerialPort.getCommPort("COM3"); // 设置串口参数,必须和称重机一致 thisPort.setBaudRate(9600); thisPort.setNumDataBits(8); thisPort.setNumStopBits(1); thisPort.setParity(SerialPort.NO_PARITY); if (!thisPort.openPort()) { System.err.println("无法打开串口,请检查串口是否被占用"); return; } // 清空读缓冲区,避免旧数据干扰 thisPort.clearPortBuffers(SerialPort.BUFFER_READ); InputStream is = thisPort.getInputStream(); byte[] buffer = new byte[100]; int bytesRead; StringBuilder dataBuilder = new StringBuilder(); while (true) { try { if ((bytesRead = is.read(buffer)) > 0) { // 用ASCII解析(如果测试后是其他编码,替换成对应编码) String chunk = new String(buffer, 0, bytesRead, "ASCII").trim(); dataBuilder.append(chunk); // 检查是否收到完整的数据包(以" kg"结尾) String currentData = dataBuilder.toString(); if (currentData.endsWith(" kg")) { System.out.println("读取到完整数据: " + currentData); // 提取重量数值 if (currentData.startsWith("N + ")) { String weightStr = currentData.substring(4, currentData.indexOf(" kg")); try { double weight = Double.parseDouble(weightStr); System.out.println("当前重量: " + weight + " kg"); } catch (NumberFormatException e) { System.err.println("解析重量失败: " + e.getMessage()); } } // 重置构建器,准备接收下一个数据包 dataBuilder.setLength(0); } } } catch (Exception e) { System.err.println("读取异常: " + e.getMessage()); if (e.getMessage().contains("shutdown or disconnected")) { System.out.println("串口已断开,退出读取"); break; } } } // 关闭串口 thisPort.closePort(); } }
按照上面的步骤排查,应该就能解决乱码问题啦!
内容的提问来源于stack exchange,提问作者Samuel Munyili
相关产品推荐
相关产品推荐

