Java串口通信,实现读写功能

最近开发用到了串口通信,因为我用的是java,所以通信部分也只能用Java来实现了,虽然有点大材小用,但是呢还是来总结一下,希望能帮到和我一样遇到问题的朋友。

因为我开发用的是Springboot框架,而且我自己对通信也确实不太懂,所以直接把通信写在了启动类里面:

  1. 确定从站地址,波特率,以及连接端口:

端口确认,我的电脑,点击右键选择管理,进入后选择设备管理器,右侧栏目下查看端口,我这里的端口是COM3

然后确定从站地址,device id就是从站地址,对应我代码中的SLAVE_ADDRESS:

最后确定波特率,也就是对应我代码中的BAUD_RATE:

代码设置:

// 设定MODBUS网络上从站地址
    private final static int SLAVE_ADDRESS = 201;
    //串行波特率
    private final static int BAUD_RATE = 9600;
  1. 因为我读出来的数据要写进数据库,所以并没有直接在启动类中实现读取功能,而是进行了二次封装:

/**
     * 读保持寄存器上的内容
     * @param master 主站
     * @param slaveId 从站地址
     * @param start 起始地址的偏移量
     * @param len 待读寄存器的个数
     */
    private static String readHoldingRegistersTest(ModbusMaster master, int slaveId, int start, int len) {
        String data = "";
        try {
            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse)master.send(request);
            if (response.isException()) {
                System.out.println("Exception response: message=" + response.getExceptionMessage());
            } else {
                data = Arrays.toString(response.getShortData());
                System.out.println("read success"+ Arrays.toString(response.getShortData()));
            }
        } catch (ModbusTransportException e) {
            e.printStackTrace();
        }
        return data;
    }
  1. 调用读取功能,并对读取的数据进行操作后写进数据库:

public static void modbus(String[] args){

        SerialPortWrapper serialParameters = new
                SerialPortWrapperImpl("COM3", BAUD_RATE, 8, 1, 0, 0, 0);
         //创建ModbusFactory工厂实例
        ModbusFactory modbusFactory = new ModbusFactory();
         //创建ModbusMaster实例
        ModbusMaster master = modbusFactory.createRtuMaster(serialParameters);
         //初始化
        try {
            //设置超时时长和尝试次数
            /*master.setTimeout(3000);
            master.setRetries(3);*/
            master.init();
            try (Connection conn = DriverManager.getConnection
                    (DB_URL, DB_USER, DB_PASSWORD)){

                String sql = "update tracker_tracking set TARGET_ANGLE = ?,MEASURED_ANGLE = ?,ERROR_ANGLE = ? where COMMUNICATION_BOX_NAME='NCU1'";
                //预编译
                PreparedStatement stmt = conn.prepareStatement(sql);

                String sql1 = "update tracker_tracking set TRACKING_DATE = ? where  COMMUNICATION_BOX_NAME='NCU1'";
                PreparedStatement stmt1 = conn.prepareStatement(sql1);

                // 读取串口数据,并将其写入数据库
                while (true) {
                    readHoldingRegistersTest(master, SLAVE_ADDRESS, 115, 1);

                    //目标角度,实际角度
                    String data =readHoldingRegistersTest(master, SLAVE_ADDRESS, 259, 2);  // 读取串口数据
                    System.out.println("---------TARGET_ANGLE---------" + data);
                    ArrayList Arr = retData(data);
                    Double da = Double.parseDouble(Arr.get(0).toString()) * 0.01;
                    Double ta = Double.parseDouble(Arr.get(1).toString()) * 0.01;
                    Double ch = da - ta;
                    stmt.setDouble(1, da);  // 将数据设置为SQL语句的参数
                    stmt.setDouble(2, ta);  // 将数据设置为SQL语句的参数
                    stmt.setDouble(3, ch);
                    stmt.executeUpdate();  // 执行SQL语句,将数据插入到数据库中

                    //时间
                    String data1 = readHoldingRegistersTest(master, SLAVE_ADDRESS, 261, 6);  // 读取串口数据
                    String Timedate = Date(data1);
                    stmt1.setString(1, Timedate);
                    stmt1.executeUpdate();

                    System.out.println("---------TARGET_ANGLE---------" + da);
                    System.out.println("---------MEASURED_ANGLE---------" + ta);

                    //分控箱当前角度
                    String data2 = readHoldingRegistersTest(master, SLAVE_ADDRESS, 11, 32);  // 读取串口数据

                    System.out.println("---------data2---------" + data2);
                    /*String Timedate = Date(data1);
                    stmt1.setString(1, Timedate);
                    stmt1.executeUpdate();*/

                    break;
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        } catch (ModbusInitException e) {
            e.printStackTrace();
        } finally {
            master.destroy();
        }
    }
  1. 读取出来的数据格式不能直接操作,所以对于我的数据格式还进行了操作,Date是对我读出来的日期的格式进行了处理,我读出来的日期格式是这样的:

public static ArrayList retData(String data){
        ArrayList Arr = new ArrayList();
        String[] dat = data.replace("[","").replace("]","").replace(",",",").replace(" ","").split(",");
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < dat.length; i ++ ){
            stringBuilder.append(dat[i]);
            Arr.add(dat[i]);
        }
        return Arr;
    }

public static String Date(String data){
        String[] dat = data.replace("[","").replace("]","").replace(",",",").replace(" ","").split(",");
        String str="";
        if (dat[0].length() == 2){
            str = 20 + dat[0] + "-";
        }
        if (dat[1].length() == 1){
            str = str + 0 + dat[1] + "-";
        }else{
            str = str + dat[1] + "-";
        }
        if(dat[2].length() == 1){
            str = str + 0 +dat[2] + " ";
        }else {
            str = str + dat[2] + " ";
        }
        if (dat[3].length() == 2){
            str = str + dat[3] + ":";
        }else {
            str = str + 0 + dat[3] + ":";
        }
        if (dat[4].length() == 2){
            str = str + dat[4] + ":";
        }else {
            str = str + 0 + dat[4] + ":";
        }
        if(dat[5].length() == 1){
            str = str + 0 +dat[5];
        }else {
            str = str + dat[5];
        }
        return str;
    }
  1. 启动类中调用modbus,因为我读取的数据更新频率不用太高,所以设置了每5秒读取一次

public static void main(String[] args) {
        SpringApplication.run(VersolApplication.class, args);
        try {
            Runtime.getRuntime().exec("cmd /c start http://localhost:8080/login");
            final long timeInterval = 5000;// 5秒运行一次
            new Thread(() -> {
                while (true) {
                    // 要运行的程序
                    modbus(args);
                    try {
                        Thread.sleep(timeInterval);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  1. 因为串口通信是单线程,读取的时候不能同时对他进行写入操作,所以我上面设置的每5秒读取一次,然后杀掉进程,就为写入的进程留出了通道,但是我的写进程是放在service层的,当我对数据库操作完成后在进行调用写的进程:

写进程二次封装:

// 设定MODBUS网络上从站地址
    private final static int SLAVE_ADDRESS = 201;
    //串行波特率
    private final static int BAUD_RATE = 9600;
/**
     * 批量写数据到保持寄存器
     *
     * @param master  主站
     * @param slaveId 从站地址
     * @param start   起始地址的偏移量
     * @param values  待写数据
     */
    public static void writeRegistersTest(ModbusMaster master, int slaveId, int start, short[] values) {
        try {
            WriteRegistersRequest request = new WriteRegistersRequest(slaveId, start, values);
            WriteRegistersResponse response = (WriteRegistersResponse) master.send(request);
            if (response.isException()) {
                System.out.println("Exception response: message = " + response.getExceptionMessage());
            } else {
                System.out.println("write success " + response);
            }
        } catch (ModbusTransportException e) {
            e.printStackTrace();
        }
    }

调用写进程:

public static void modbus(int START,String LENG) {

        SerialPortWrapper serialParameters = new
                SerialPortWrapperImpl("COM3", BAUD_RATE, 8, 1, 0, 0, 0);
        /* 创建ModbusFactory工厂实例 */
        ModbusFactory modbusFactory = new ModbusFactory();
        /* 创建ModbusMaster实例 */
        ModbusMaster master = modbusFactory.createRtuMaster(serialParameters);
        /* 初始化 */
        try {
            master.init();
            //处理写入的数据
            short LEN = Short.parseShort(LENG);
            short[] list = {LEN};
            //写入
            writeRegistersTest(master, SLAVE_ADDRESS, START,list);

        } catch (ModbusInitException e) {
            e.printStackTrace();
        } finally {
            master.destroy();
        }
    }

调用modbus:

 @Override
    public int openAutomatic(String name) {
        int result = 0;
        result += vsdao.openAutomatic(name);
        if (result == 1){
            /*传递写的位置START,写的值name*/
            modbus(115,name);
        }
        return result;
    }

启动程序就发现,读取功能实现了:

写入功能需要前端操作成功后,后台再调用 。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java可以通过串口通信实现与外部设备的数据交互。下面是Java实现串口通信的基本步骤: 1. 导入扩展包和依赖库,例如RXTXcomm.jar和RXTXcomm.dll等。 2. 配置串口参数,例如波特率、数据位、停止位、校验位等。 3. 打开串口并获取输入输出流。 4. 通过输入输出流进行数据读写操作。 5. 关闭串口。 下面是一个简单的Java串口通信示例代码: ```java import gnu.io.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class SerialPortTest implements SerialPortEventListener { private SerialPort serialPort; public void init() { try { // 获取系统中可用的串口列表 CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier("COM1"); // 打开串口,并设置串口参数 serialPort = (SerialPort) portIdentifier.open("SerialPortTest", 2000); serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // 获取串口的输入输出流 InputStream inputStream = serialPort.getInputStream(); OutputStream outputStream = serialPort.getOutputStream(); // 监听串口数据 serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); // 发送数据 outputStream.write("Hello, Serial Port!".getBytes()); } catch (NoSuchPortException | PortInUseException | UnsupportedCommOperationException | IOException | TooManyListenersException e) { e.printStackTrace(); } } @Override public void serialEvent(SerialPortEvent serialPortEvent) { if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { // 读取串口数据 InputStream inputStream = serialPort.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = inputStream.read(buffer)) != -1) { System.out.println(new String(buffer, 0, len)); } } catch (IOException e) { e.printStackTrace(); } } } public void close() { // 关闭串口 if (serialPort != null) { serialPort.removeEventListener(); serialPort.close(); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值