1. 程式人生 > >Java程式與串列埠的通訊實現及除錯

Java程式與串列埠的通訊實現及除錯

Java序列通訊是資料傳輸處理和軟硬體介面常用的知識,最=最近設計軟體的過程中涉及到軟硬體介面部分的知識,也就是中層Java程式向底層c語言發出指令,要求硬體層感測器測量資料並返回相應的數值,下面這篇部落格實現了資料傳遞,也是我在csdn中見到為數不多可以直接執行並有效果的程式,基於以後會涉及到軟硬體介面方面的文章,故而將文章轉發並儲存。

https://blog.csdn.net/update_java/article/details/46898937

下面為大家介紹一下小編最近一個專案中,牽扯到與串列埠通訊部分的實現及除錯。

串列埠通訊原理

  • 串列埠通訊指串列埠按位(bit)傳送和接收位元組。儘管比按位元組(byte)的並行通訊慢,但是串列埠可以在使用一根線傳送資料的同時用另一根線接收資料。

  • 串列埠是計算機上一種非常通用的裝置通訊協議(不要與通用序列匯流排Universal SerialBus或者USB混淆)

  • 典型地,串列埠用於ASCII碼字元的傳輸。通訊使用3根線完成:(1)地線,(2)傳送,(3)接收。由於串列埠通訊是非同步的,埠能夠在一根線上傳送資料同時在另一根線上接收資料。其他線用於握手,但是不是必須的。串列埠通訊最重要的引數是位元率、資料位、停止位和奇偶校驗。對於兩個進行通訊的埠,這些引數必須匹配

  • RS-232(ANSI/EIA-232標準)是IBM-PC及其相容機上的序列連線標準、RS-422(EIA RS-422-AStandard)是Apple的Macintosh計算機的串列埠連線標準。RS-485(EIA-485標準)是RS-422的改進。
    在一臺電腦完成串列埠通訊及除錯所需的準備工作

  • 由於筆記本或桌上型電腦上基本上都沒有成對的串列埠提供給我們除錯使用,我們就需要下載虛擬串列埠軟體來實現串列埠除錯。

  • 下載虛擬串列埠軟體 http://pan.baidu.com/s/1hqhGDbI, (這裡提供的還是比較好用)。下載安裝完成後先不要急著執行,把壓縮包中的vspdctl.dll檔案複製到安裝目錄下如:我的目錄為–>D:\SoftWareInstall\Virtual Serial Port Driver 7.2 替換原有檔案即可成功啟用。
    開啟軟體新增虛擬串列埠,一般都是成對新增的(新增COM3、COM4)後如圖所示:

在這裡插入圖片描述

  • 新增完成後到裝置管理器中檢視,發現多了兩個虛擬串列埠如圖:
    在這裡插入圖片描述

  • 下載串列埠除錯軟體 http://pan.baidu.com/s/1c0AVaXq ,這裡提供的是比較老的除錯軟體了,但還是比較好用的哦。直接解壓點選開啟就ok了。
    可以直接先開啟兩個除錯視窗,分別用來表示COM3和COM4串列埠。兩個串列埠的引數一定要設定的一樣才可以正常的收發資料。(若除錯可以正常收發資料後,可以關掉一個偵錯程式,而用java程式代替)如圖:

在這裡插入圖片描述

**

* 程式程式碼編寫

**
這一部分將是我們的重點,要與串列埠通訊首先要在專案新增RXTXcomm.jar包(放在專案中的lib目錄下,並新增到build Path中)(win64位下載地址:http://pan.baidu.com/s/1o6zLmTc) ; 安裝完成之後;
拷貝 RXTXcomm.jar 到 JAVA_HOME\jre\lib\ext目錄中;
拷貝 rxtxSerial.dll 到 JAVA_HOME\jre\bin目錄中;
拷貝 rxtxParallel.dll 到 JAVA_HOME\jre\bin目錄中;
JAVA_HOME為jdk安裝路徑
在執行程式碼之前,需要將RXTXcomm.jar匯入到程式包中。

package comm;

import java.io.*;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import gnu.io.*;

public class ContinueRead extends Thread implements SerialPortEventListener { // SerialPortEventListener
    // 監聽器,我的理解是獨立開闢一個執行緒監聽串列埠資料
    static CommPortIdentifier portId; // 串列埠通訊管理類
    static Enumeration<?> portList; // 有效連線上的埠的列舉
    InputStream inputStream; // 從串列埠來的輸入流
    static OutputStream outputStream;// 向串列埠輸出的流
    static SerialPort serialPort; // 串列埠的引用
    // 堵塞佇列用來存放讀到的資料
    private BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();

    @Override
    /**
     * SerialPort EventListene 的方法,持續監聽埠上是否有資料流
     */
    public void serialEvent(SerialPortEvent event) {//

        switch (event.getEventType()) {
        case SerialPortEvent.BI:
        case SerialPortEvent.OE:
        case SerialPortEvent.FE:
        case SerialPortEvent.PE:
        case SerialPortEvent.CD:
        case SerialPortEvent.CTS:
        case SerialPortEvent.DSR:
        case SerialPortEvent.RI:
        case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
            break;
        case SerialPortEvent.DATA_AVAILABLE:// 當有可用資料時讀取資料
            byte[] readBuffer = new byte[20];
            try {
                int numBytes = -1;
                while (inputStream.available() > 0) {
                    numBytes = inputStream.read(readBuffer);

                    if (numBytes > 0) {
                        msgQueue.add(new Date() + "真實收到的資料為:-----"
                                + new String(readBuffer));
                        readBuffer = new byte[20];// 重新構造緩衝物件,否則有可能會影響接下來接收的資料
                    } else {
                        msgQueue.add("額------沒有讀到資料");
                    }
                }
            } catch (IOException e) {
            }
            break;
        }
    }

    /**
     * 
     * 通過程式開啟COM4串列埠,設定監聽器以及相關的引數
     * 
     * @return 返回1 表示埠開啟成功,返回 0表示埠開啟失敗
     */
    public int startComPort() {
        // 通過串列埠通訊管理類獲得當前連線上的串列埠列表
        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {

            // 獲取相應串列埠物件
            portId = (CommPortIdentifier) portList.nextElement();

            System.out.println("裝置型別:--->" + portId.getPortType());
            System.out.println("裝置名稱:---->" + portId.getName());
            // 判斷埠型別是否為串列埠
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                // 判斷如果COM4串列埠存在,就開啟該串列埠
                if (portId.getName().equals("COM4")) {
                    try {
                        // 開啟串列埠名字為COM_4(名字任意),延遲為2毫秒
                        serialPort = (SerialPort) portId.open("COM_4", 2000);

                    } catch (PortInUseException e) {
                        e.printStackTrace();
                        return 0;
                    }
                    // 設定當前串列埠的輸入輸出流
                    try {
                        inputStream = serialPort.getInputStream();
                        outputStream = serialPort.getOutputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                        return 0;
                    }
                    // 給當前串列埠新增一個監聽器
                    try {
                        serialPort.addEventListener(this);
                    } catch (TooManyListenersException e) {
                        e.printStackTrace();
                        return 0;
                    }
                    // 設定監聽器生效,即:當有資料時通知
                    serialPort.notifyOnDataAvailable(true);

                    // 設定串列埠的一些讀寫引數
                    try {
                        // 位元率、資料位、停止位、奇偶校驗位
                        serialPort.setSerialPortParams(9600,
                                SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                                SerialPort.PARITY_NONE);
                    } catch (UnsupportedCommOperationException e) {
                        e.printStackTrace();
                        return 0;
                    }

                    return 1;
                }
            }
        }
        return 0;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            System.out.println("--------------任務處理執行緒運行了--------------");
            while (true) {
                // 如果堵塞佇列中存在資料就將其輸出
                if (msgQueue.size() > 0) {
                    System.out.println(msgQueue.take());
                }
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ContinueRead cRead = new ContinueRead();
        int i = cRead.startComPort();
        if (i == 1) {
            // 啟動執行緒來處理收到的資料
            cRead.start();
            try {
                String st = "哈哈----你好";
                System.out.println("發出位元組數:" + st.getBytes("gbk").length);
                outputStream.write(st.getBytes("gbk"), 0,
                        st.getBytes("gbk").length);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else {
            return;
        }
    }
}
 

java程式與串列埠通訊除錯
程式除錯截圖:

在這裡插入圖片描述

總結

  1. 串列埠通訊在很多地方都要用到,特別是嵌入式開發、簡訊模組開發以及為各種硬體產品定製軟體等都需要用到。其中最經常用的通訊協議為RS-232通訊協議,要想成為真正的串列埠通訊開發高手就需要全面的瞭解串列埠的通訊協議(本人還是菜鳥一枚。。。希望高手指點)。
  2. 串列埠通訊的另一個重點在於接收到資料後,如何判斷資料的型別以及有效資料的提取等,這些都需要根據相應的協議進行程式碼編寫。