m1mac使用Java下JSerialComm包进行串口通信获取信息不完整。

环境macbook pro m1pro,javad jdk17,使用JSerialComm包使用RS232连接虚拟仿真设备WT310进行串口通信时,发送命令获取数据,为什么只能获取到62个字节,应该获取65个字节,代码如下:


package org.test;

import com.fazecast.jSerialComm.SerialPort;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class DSerialPort1 {
    public void main() throws IOException, InterruptedException {
        String path = "/Users/cc/workspace/Idea/DSerialPort/serialPortOutput.txt";
        File result = new File(path);
        //判断文件是否存在,如果不存在,则创建一个
        if(!result.exists()){
            result.createNewFile();
        }

        //获取当前工作路径
//        System.out.println(System.getProperty("user.dir"));
        //查找所有串口
        SerialPort[] serialPorts = SerialPort.getCommPorts();
        SerialPort usbSerialPort = null;

        for(int i = 0; i<serialPorts.length; i++){
            if(serialPorts[i].getSystemPortName().equals("cu.usbserial-FTDEBWBU")){
//                System.out.println(serialPorts[i].getSystemPortName());
                usbSerialPort = serialPorts[i];
                break;
            }
        }
        if (usbSerialPort != null) {
            System.out.println(usbSerialPort.getSystemPortName());
        }else{
            System.out.println("接口不存在!");
            return;
        }

        //设置串口参数
        //serialPort.setComPortParameters(112500, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
        //一次性设置所有的串口参数,第一个参数为波特率,默认9600;第二个参数为每一位的大小,默认8,可以输入5到8之间的值;第三个参数为停止位大小,只接受内置常量,可以选择(ONE_STOP_BIT, ONE_POINT_FIVE_STOP_BITS, TWO_STOP_BITS);第四位为校验位,同样只接受内置常量,可以选择 NO_PARITY, EVEN_PARITY, ODD_PARITY, MARK_PARITY,SPACE_PARITY。
        usbSerialPort.setBaudRate(9600);
        usbSerialPort.setNumDataBits(8);
        usbSerialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);


        //打开串口
        if(!usbSerialPort.isOpen()){
            boolean isCommOpened = usbSerialPort.openPort();//判断串口是否打开,如果没打开,就打开串口。打开串口的函数会返回一个boolean值,用于表明串口是否成功打开了
            if(isCommOpened) System.out.println("打开串口成功!");
            else System.out.println("打开串口失败!");
        }

        //测试串口发送接收数据
        if(usbSerialPort.isOpen()){
//            usbSerialPort.flushIOBuffers();
            //要发送的命令
            String writeData = "NUMeric:NORMal:VALue?\r\n";
            //将字符串转换为字节数组
            byte[] bytes = writeData.getBytes();
            //将字节数组全部写入串口
            usbSerialPort.writeBytes(bytes,bytes.length);

            //休眠0.1秒,等待下位机返回数据。如果不休眠直接读取,有可能无法成功读到数据
            Thread.sleep(20);
//            System.out.println("接收数据大小:"+usbSerialPort.bytesAvailable());
            String readData = "";
            InputStream is = usbSerialPort.getInputStream();
            System.out.println("可读取的字节大小:"+is.available());
            //循环读取所有的返回数据。如果可读取数据长度为0或-1,则停止读取
            while(is.available()>0) {
                byte[] newData = new byte[is.available()];//创建一个字节数组,长度为可读取的字节长度
                //将串口中可读取的数据读入字节数组,返回值为本次读取到的字节长度
                int numRead = is.read(newData);
                //将新数据转为字符串
                String newDataString = new String(newData);
                //组合字符串
                readData = readData + newDataString;
                //休眠0.02秒,等待下位机传送数据到串口。如果不休眠,直接再次使用port.bytesAvailable()函数会因为下位机
                //还没有返回数据而返回-1,并跳出循环导致数据没读完。休眠时间可以自行调试,时间越长,单次读取到的数据越多。
                Thread.sleep(1000);
                System.out.println("剩余字符串大小"+is.available());
                usbSerialPort.flushIOBuffers();
            }

            //对获取到的数据进行处理
            //根据分隔符","进行分隔,获取数组
            System.out.println(readData);
            String[] datas = readData.split(",");
            System.out.println(datas.length);
            System.out.println(Arrays.toString(datas));
            //创建最终结果的数组
            double[] finalData = new double[datas.length];

            //对每个数组中的数据进行处理
            for(int i = 0; i<datas.length; i++){
                //将字符串进行划分
                String baseNumber = datas[i].substring(0,6);
                String indexSignal = datas[i].substring(7,8);
                String index = datas[i].substring(8,10);

                finalData[i] = transform(baseNumber, indexSignal, index);
                System.out.println(finalData[i]);
            }

            System.out.println("readString:"+readData);
            //获取当前时间
            SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
            Date date = new Date(System.currentTimeMillis());
            String time = formatter.format(date);
            System.out.println("当前时间为:"+time);

            //IO写入文件
            Writer writer = null;
            try{
                writer = new FileWriter(result);
                writer.append(time);
                writer.append("     ");
                writer.append(Arrays.toString(finalData));
                writer.append("\n");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(writer != null){
                    try{
                        writer.close();
                    }catch(IOException e){
                        System.out.println("文件关闭失败!!");
                    }
                }
            }
        }

        //关闭串口
        usbSerialPort.closePort();
    }
    
    //数据处理函数,将字符串转换为double
    private static double transform(String baseNumber, String indexSignal, String index){
        int signal = 0;
        if(indexSignal.equals("+")) signal = 1;
        double number = pushIndex(signal, Double.parseDouble(baseNumber), Integer.parseInt(index));
        return number;
    }

    //数据处理函数,底数乘指数
    private static double pushIndex(int signal, double number, int index){
        //0代表指数为负数,1代表指数为正数
        if(signal == 0){
            for(int i = 0; i<index; i++){
                number = number/10;
            }
        }else{
            for(int i = 0; i<index; i++){
                number = number*10;
            }
        }
        return number;
    }
}

【以下回答由 GPT 生成】

问题分析: 根据提供的代码,可以看出在读取串口数据时,设置了读取缓冲区的大小为100字节(byte[] readBuffer = new byte[100];),然后使用inputStream.read(readBuffer)方法读取数据,最后打印出实际读取到的字节数。

根据问题描述,实际应该获取到65个字节的数据,但只获取到了62个字节。这可能是由于读取缓冲区大小的设置问题或者数据传输延迟导致的。

解决方案: 1. 调整读取缓冲区的大小:将读取缓冲区的大小增大到可容纳65个字节的大小。

修改代码为:

byte[] readBuffer = new byte[65];
int numRead = inputStream.read(readBuffer);
System.out.println("读取到的字节数:" + numRead);
  1. 添加延迟等待数据传输完成:由于串口通信存在传输延迟,可以在读取数据之前添加一个延迟等待。

修改代码为:

Thread.sleep(1000); // 延迟1秒等待数据传输完成
byte[] readBuffer = new byte[65];
int numRead = inputStream.read(readBuffer);
System.out.println("读取到的字节数:" + numRead);

请注意,以上提供的解决方案是基于对问题的初步分析,如果问题仍然存在,请确保虚拟仿真设备WT310正常工作并且向串口发送了完整的65个字节的数据。另外,还可以通过调试和日志记录来进一步排查问题。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^