You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 02:55:57