JavaFX读取Bilanciai D70A串口称重数据失败求助
问题描述
我尝试用JavaFX读取Bilanciai D70A秤的RS232串口数据并打印到标签,已按官方文档完成全部配置,但comPort.readBytes()始终返回0,无法获取有效数据。
附实现代码:
package com.togisoft.venetacollaudipeso; import com.fazecast.jSerialComm.SerialPort; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import net.sf.jasperreports.engine.JREmptyDataSource; import net.sf.jasperreports.engine.JasperFillManager; import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JasperPrintManager; import javax.print.PrintServiceLookup; import javax.print.PrintService; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class AppController { private SerialPort comPort; @FXML private Label weightLabel; @FXML public void initialize() { // COM Portunu bul ver aç comPort = SerialPort.getCommPort(Helper.getComPort()); comPort.setNumDataBits(7); comPort.setBaudRate(Helper.getBaudRate()); comPort.setParity(Helper.getComParity()); comPort.setNumStopBits(Helper.getStopBit()); ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); if (comPort.openPort()) { System.out.println("Port başarıyla açıldı."); executor.scheduleAtFixedRate(this::readFromSerial, 0, 300, TimeUnit.MILLISECONDS); } else { System.out.println("Port açılırken hata oluştu!."); Platform.runLater(() -> weightLabel.setText("PORT Errore!")); } } private void readFromSerial() { while (comPort.isOpen()) { byte[] readBuffer = new byte[8]; int numRead = comPort.readBytes(readBuffer, readBuffer.length); if (numRead > 0) { StringBuilder receivedData = new StringBuilder(); for (int i = 0; i < numRead; i++) { // Son biti (en anlamsız biti) düşürerek 7 bitlik veriyi elde et int sevenBitData = readBuffer[i] & 0x7F; receivedData.append((char) sevenBitData); // Veriyi String olarak birleştir } String weight = extractWeightFromData(receivedData.toString()); updateUIWithWeight(formatWeight(weight)); } } } private String formatWeight(String weightData) { if (weightData == null || !weightData.contains(".")) { return "0.0"; } int significantDigits = 0; for (char c : weightData.toCharArray()) { if (Character.isDigit(c)) { significantDigits++; } } if (significantDigits >= 5) { try { float weight = Float.parseFloat(weightData); if (weight == (int) weight) { // Ondalık kısmı sıfır ise, ondalık kısmı gösterme return String.format("%.0f", weight); } else { // Ondalık kısmı sıfırdan farklı ise, ondalık kısmı göster return String.format("%.1f", weight); } } catch (NumberFormatException e) { System.out.println(e.getLocalizedMessage());// Hata durumunda işlemler } } return "0.0"; // Varsayılan olarak 0 döndür } private String extractWeightFromData(String data) { if (data.length() >= 8 && data.startsWith("$(24H")) { return data.substring(2, 7); // 3–7 karakterleri alarak ağırlık bilgisini çıkar } return ""; } private void updateUIWithWeight(String weight) { Platform.runLater(() -> weightLabel.setText(weight)); } @FXML void onStamp() { System.out.println(weightLabel.getText()); try { String sourceFileName = "weight.jasper"; Map<String, Object> parameters = new HashMap<>(); parameters.put("kilo", weightLabel.getText() + " KG"); // Örnek parametre JasperPrint print = JasperFillManager.fillReport(sourceFileName, parameters, new JREmptyDataSource()); PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null); PrintService selectedPrintService = null; for (PrintService printService : printServices) { if (printService.getName().equalsIgnoreCase(Helper.getPrinter())) { selectedPrintService = printService; break; } } if (selectedPrintService != null) { JasperPrintManager.printReport(print, false); } else { System.out.println("Belirtilen yazıcı bulunamadı."); } } catch (Exception ex) { System.out.println(ex.getMessage()); } } @FXML public void onEnterPressed(KeyEvent event) { if (event.getCode() == KeyCode.ENTER) { System.out.println("Enter pressed"); onStamp(); } } @Override protected void finalize() { if (comPort != null && comPort.isOpen()) { comPort.closePort(); System.out.println("Port closed."); } } }
排查与修复建议
1. 确认串口参数完全匹配
根据Bilanciai D70A官方文档,核对以下参数是否与Helper类返回值一致:
- 波特率:默认9600(以文档为准)
- 数据位:7位
- 奇偶校验:偶校验(SerialPort.EVEN_PARITY)
- 停止位:1位
- 流控制:无
初始化时添加参数打印,验证配置正确性:
System.out.println("BaudRate: " + comPort.getBaudRate()); System.out.println("DataBits: " + comPort.getNumDataBits()); System.out.println("Parity: " + comPort.getParity()); System.out.println("StopBits: " + comPort.getNumStopBits());
2. 修复读取线程逻辑
当前readFromSerial()被定时调度且包含while循环,会导致多线程冲突。改为启动单线程持续读取:
if (comPort.openPort()) { System.out.println("Port başarıyla açıldı."); // 设置读取超时,避免无限阻塞 comPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 100, 0); // 启动独立线程读取串口 new Thread(this::readFromSerial).start(); }
3. 验证数据帧格式
先打印原始字节数据,确认是否接收正确:
int numRead = comPort.readBytes(readBuffer, readBuffer.length); if (numRead > 0) { System.out.println("Raw bytes: " + Arrays.toString(Arrays.copyOf(readBuffer, numRead))); // 后续处理逻辑... }
核对文档中的数据帧前缀、长度,调整extractWeightFromData()的匹配规则,比如文档中可能的帧前缀为$(2而非$(24H。
4. 硬件连接排查
- 确认使用**交叉RS232线(Null Modem)**连接秤与电脑
- 检查串口转USB适配器(若使用)的驱动是否正常,设备管理器中是否识别到对应串口
- 用串口调试工具(如PuTTY)测试,确认秤能正常输出数据,排除硬件故障
5. 优化资源释放
替换不可靠的finalize()方法,在应用关闭时关闭串口:
public void initialize() { // ... 现有初始化代码 ... Platform.runLater(() -> { Platform.getWindows().get(0).setOnCloseRequest(event -> { if (comPort != null && comPort.isOpen()) { comPort.closePort(); System.out.println("Port closed."); } }); }); }
内容的提问来源于stack exchange,提问作者Tolga ÇAĞLAYAN
相关产品推荐
相关产品推荐

