1. 程式人生 > >使用Java實現串列埠通訊

使用Java實現串列埠通訊

轉自:https://blog.csdn.net/kong_gu_you_lan/article/details/52302075

1.介紹

2.RXTXcomm

內含32位與64位版本 
使用方法: 
拷貝 RXTXcomm.jar 到 JAVA_HOME\jre\lib\ext目錄中; 
拷貝 rxtxSerial.dll 到 JAVA_HOME\jre\bin目錄中; 
拷貝 rxtxParallel.dll 到 JAVA_HOME\jre\bin目錄中; 
JAVA_HOME為jdk安裝路徑

3.串列埠通訊管理

SerialPortManager實現了對串列埠通訊的管理,包括查詢可用埠、開啟關閉串列埠、傳送接收資料。

package
com.yang.serialport.manage; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import
java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.TooManyListenersException; import com.yang.serialport.exception.NoSuchPort; import com.yang.serialport.exception.NotASerialPort; import com.yang.serialport.exception.PortInUse; import
com.yang.serialport.exception.ReadDataFromSerialPortFailure; import com.yang.serialport.exception.SendDataToSerialPortFailure; import com.yang.serialport.exception.SerialPortInputStreamCloseFailure; import com.yang.serialport.exception.SerialPortOutputStreamCloseFailure; import com.yang.serialport.exception.SerialPortParameterFailure; import com.yang.serialport.exception.TooManyListeners; /** * 串列埠管理 * * @author yangle */ public class SerialPortManager { /** * 查詢所有可用埠 * * @return 可用埠名稱列表 */ @SuppressWarnings("unchecked") public static final ArrayList<String> findPort() { // 獲得當前所有可用串列埠 Enumeration<CommPortIdentifier> portList = CommPortIdentifier .getPortIdentifiers(); ArrayList<String> portNameList = new ArrayList<String>(); // 將可用串列埠名新增到List並返回該List while (portList.hasMoreElements()) { String portName = portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /** * 開啟串列埠 * * @param portName * 埠名稱 * @param baudrate * 波特率 * @return 串列埠物件 * @throws SerialPortParameterFailure * 設定串列埠引數失敗 * @throws NotASerialPort * 埠指向裝置不是串列埠型別 * @throws NoSuchPort * 沒有該埠對應的串列埠裝置 * @throws PortInUse * 埠已被佔用 */ public static final SerialPort openPort(String portName, int baudrate) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse { try { // 通過埠名識別埠 CommPortIdentifier portIdentifier = CommPortIdentifier .getPortIdentifier(portName); // 開啟埠,設定埠名與timeout(開啟操作的超時時間) CommPort commPort = portIdentifier.open(portName, 2000); // 判斷是不是串列埠 if (commPort instanceof SerialPort) { SerialPort serialPort = (SerialPort) commPort; try { // 設定串列埠的波特率等引數 serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { throw new SerialPortParameterFailure(); } return serialPort; } else { // 不是串列埠 throw new NotASerialPort(); } } catch (NoSuchPortException e1) { throw new NoSuchPort(); } catch (PortInUseException e2) { throw new PortInUse(); } } /** * 關閉串列埠 * * @param serialport * 待關閉的串列埠物件 */ public static void closePort(SerialPort serialPort) { if (serialPort != null) { serialPort.close(); serialPort = null; } } /** * 向串列埠傳送資料 * * @param serialPort * 串列埠物件 * @param order * 待發送資料 * @throws SendDataToSerialPortFailure * 向串列埠傳送資料失敗 * @throws SerialPortOutputStreamCloseFailure * 關閉串列埠物件的輸出流出錯 */ public static void sendToPort(SerialPort serialPort, byte[] order) throws SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure { OutputStream out = null; try { out = serialPort.getOutputStream(); out.write(order); out.flush(); } catch (IOException e) { throw new SendDataToSerialPortFailure(); } finally { try { if (out != null) { out.close(); out = null; } } catch (IOException e) { throw new SerialPortOutputStreamCloseFailure(); } } } /** * 從串列埠讀取資料 * * @param serialPort * 當前已建立連線的SerialPort物件 * @return 讀取到的資料 * @throws ReadDataFromSerialPortFailure * 從串列埠讀取資料時出錯 * @throws SerialPortInputStreamCloseFailure * 關閉串列埠物件輸入流出錯 */ public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure { InputStream in = null; byte[] bytes = null; try { in = serialPort.getInputStream(); // 獲取buffer裡的資料長度 int bufflenth = in.available(); while (bufflenth != 0) { // 初始化byte陣列為buffer中資料的長度 bytes = new byte[bufflenth]; in.read(bytes); bufflenth = in.available(); } } catch (IOException e) { throw new ReadDataFromSerialPortFailure(); } finally { try { if (in != null) { in.close(); in = null; } } catch (IOException e) { throw new SerialPortInputStreamCloseFailure(); } } return bytes; } /** * 新增監聽器 * * @param port * 串列埠物件 * @param listener * 串列埠監聽器 * @throws TooManyListeners * 監聽類物件過多 */ public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners { try { // 給串列埠新增監聽器 port.addEventListener(listener); // 設定當有資料到達時喚醒監聽接收執行緒 port.notifyOnDataAvailable(true); // 設定當通訊中斷時喚醒中斷執行緒 port.notifyOnBreakInterrupt(true); } catch (TooManyListenersException e) { throw new TooManyListeners(); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214

4.程式主視窗

/*
 * MainFrame.java
 *
 * Created on 2016.8.19
 */

package com.yang.serialport.ui;

import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.awt.Color;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import com.yang.serialport.exception.NoSuchPort;
import com.yang.serialport.exception.NotASerialPort;
import com.yang.serialport.exception.PortInUse;
import com.yang.serialport.exception.SendDataToSerialPortFailure;
import com.yang.serialport.exception.SerialPortOutputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortParameterFailure;
import com.yang.serialport.exception.TooManyListeners;
import com.yang.serialport.manage.SerialPortManager;
import com.yang.serialport.utils.ByteUtils;
import com.yang.serialport.utils.ShowUtils;

/**
 * 主介面
 * 
 * @author yangle
 */
public class MainFrame extends JFrame {

    /**
     * 程式介面寬度
     */
    public static final int WIDTH = 500;

    /**
     * 程式介面高度
     */
    public static final int HEIGHT = 360;

    private JTextArea dataView = new JTextArea();
    private JScrollPane scrollDataView = new JScrollPane(dataView);

    // 串列埠設定面板
    private JPanel serialPortPanel = new JPanel();
    private JLabel serialPortLabel = new JLabel("串列埠");
    private JLabel baudrateLabel = new JLabel("波特率");
    private JComboBox commChoice = new JComboBox();
    private JComboBox baudrateChoice = new JComboBox();

    // 操作面板
    private JPanel operatePanel = new JPanel();
    private JTextField dataInput = new JTextField();
    private JButton serialPortOperate = new JButton("開啟串列埠");
    private JButton sendData = new JButton("傳送資料");

    private List<String> commList = null;
    private SerialPort serialport;

    public MainFrame() {
        initView();
        initComponents();
        actionListener();
        initData();
    }

    private void initView() {
        // 關閉程式
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        // 禁止視窗最大化
        setResizable(false);

        // 設定程式視窗居中顯示
        Point p = GraphicsEnvironment.getLocalGraphicsEnvironment()
                .getCenterPoint();
        setBounds(p.x - WIDTH / 2, p.y - HEIGHT / 2, WIDTH, HEIGHT);
        this.setLayout(null);

        setTitle("串列埠通訊");
    }

    private void initComponents() {
        // 資料顯示
        dataView.setFocusable(false);
        scrollDataView.setBounds(10, 10, 475, 200);
        add(scrollDataView);

        // 串列埠設定
        serialPortPanel.setBorder(BorderFactory.createTitledBorder("串列埠設定"));
        serialPortPanel.setBounds(10, 220, 170, 100);
        serialPortPanel.setLayout(null);
        add(serialPortPanel);

        serialPortLabel.setForeground(Color.gray);
        serialPortLabel.setBounds(10, 25, 40, 20);
        serialPortPanel.add(serialPortLabel);

        commChoice.setFocusable(false);
        commChoice.setBounds(60, 25, 100, 20);
        serialPortPanel.add(commChoice);

        baudrateLabel.setForeground(Color.gray);
        baudrateLabel.setBounds(10, 60, 40, 20);
        serialPortPanel.add(baudrateLabel);

        baudrateChoice.setFocusable(false);
        baudrateChoice.setBounds(60, 60, 100, 20);
        serialPortPanel.add(baudrateChoice);

        // 操作
        operatePanel.setBorder(BorderFactory.createTitledBorder("操作"));
        operatePanel.setBounds(200, 220, 285, 100);
        operatePanel.setLayout(null);
        add(operatePanel);

        dataInput.setBounds(25, 25, 235, 20);
        operatePanel.add(dataInput);

        serialPortOperate.setFocusable(false);
        serialPortOperate.setBounds(45, 60, 90, 20);
        operatePanel.add(serialPortOperate);

        sendData.setFocusable(false);
        sendData.setBounds(155, 60, 90, 20);
        operatePanel.add(sendData);
    }

    @SuppressWarnings("unchecked")
    private void initData() {
        commList = SerialPortManager.findPort();
        // 檢查是否有可用串列埠,有則加入選項中
        if (commList == null || commList.size() < 1) {
            ShowUtils.warningMessage("沒有搜尋到有效串列埠!");
        } else {
            for (String s : commList) {
                commChoice.addItem(s);
            }
        }

        baudrateChoice.addItem("9600");
        baudrateChoice.addItem("19200");
        baudrateChoice.addItem("38400");
        baudrateChoice.addItem("57600");
        baudrateChoice.addItem("115200");
    }

    private void actionListener() {
        serialPortOperate.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if ("開啟串列埠".equals(serialPortOperate.getText())
                        && serialport == null) {
                    openSerialPort(e);
                } else {
                    closeSerialPort(e);
                }
            }
        });

        sendData.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                sendData(e);
            }
        });
    }

    /**
     * 開啟串列埠
     * 
     * @param evt
     *            點選事件
     */
    private void openSerialPort(java.awt.event.ActionEvent evt) {
        // 獲取串列埠名稱
        String commName = (String) commChoice.getSelectedItem();
        // 獲取波特率
        int baudrate = 9600;
        String bps = (String) baudrateChoice.getSelectedItem();
        baudrate = Integer.parseInt(bps);

        // 檢查串列埠名稱是否獲取正確
        if (commName == null || commName.equals("")) {
            ShowUtils.warningMessage("沒有搜尋到有效串列埠!");
        } else {
            try {
                serialport = SerialPortManager.openPort(commName, baudrate);
                if (serialport != null) {
                    dataView.setText("串列埠已開啟" + "\r\n");
                    serialPortOperate.setText("關閉串列埠");
                }
            } catch (SerialPortParameterFailure e) {
                e.printStackTrace();
            } catch (NotASerialPort e) {
                e.printStackTrace();
            } catch (NoSuchPort e) {
                e.printStackTrace();
            } catch (PortInUse e) {
                e.printStackTrace();
                ShowUtils.warningMessage("串列埠已被佔用!");
            }
        }

        try {
            SerialPortManager.addListener(serialport, new SerialListener());
        } catch (TooManyListeners e) {
            e.printStackTrace();
        }
    }

    /**
     * 關閉串列埠
     * 
     * @param evt
     *            點選事件
     */
    private void closeSerialPort(java.awt.event.ActionEvent evt) {
        SerialPortManager.closePort(serialport);
        dataView.setText("串列埠已關閉" + "\r\n");
        serialPortOperate.setText("開啟串列埠");
    }

    /**
     * 傳送資料
     * 
     * @param evt
     *            點選事件
     */
    private void sendData(java.awt.event.ActionEvent evt) {
        // 輸入框直接輸入十六進位制字元,長度必須是偶數
        String data = dataInput.getText().toString();
        try {
            SerialPortManager.sendToPort(serialport,
                    ByteUtils.hexStr2Byte(data));
        } catch (SendDataToSerialPortFailure e) {
            e.printStackTrace();
        } catch (SerialPortOutputStreamCloseFailure e) {
            e.printStackTrace();
        }
    }

    private class SerialListener implements SerialPortEventListener {
        /**
         * 處理監控到的串列埠事件
         */
        public void serialEvent(SerialPortEvent serialPortEvent) {

            switch (serialPortEvent.getEventType()) {

            case SerialPortEvent.BI: // 10 通訊中斷
                ShowUtils.errorMessage("與串列埠裝置通訊中斷");
                break;

            case SerialPortEvent.OE: // 7 溢位(溢位)錯誤

            case SerialPortEvent.FE: // 9 幀錯誤

            case SerialPortEvent.PE: // 8 奇偶校驗錯誤

            case SerialPortEvent.CD: // 6 載波檢測

            case SerialPortEvent.CTS: // 3 清除待發送資料

            case SerialPortEvent.DSR: // 4 待發送資料準備好了

            case SerialPortEvent.RI: // 5 振鈴指示

            case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 輸出緩衝區已清空
                break;

            case SerialPortEvent.DATA_AVAILABLE: // 1 串列埠存在可用資料
                byte[] data = null;
                try {
                    if (serialport == null) {
                        ShowUtils.errorMessage("串列埠物件為空!監聽失敗!");
                    } else {
                        // 讀取串列埠資料
                        data = SerialPortManager.readFromPort(serialport);
                        dataView.append(ByteUtils.byteArrayToHexString(data,
                                true) + "\r\n");
                    }
                } catch (Exception e) {
                    ShowUtils.errorMessage(e.toString());
                    // 發生讀取錯誤時顯示錯誤資訊後退出系統
                    System.exit(0);
                }
                break;
            }
        }
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MainFrame().setVisible(true);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318

5.寫在最後

歡迎同學們吐槽評論,如果你覺得本篇部落格對你有用,那麼就留個言或者頂一下吧(^-^)