Java串口通信--------基於RXTX (附帶資源地址)


最近幫老師做了一個小項目,一個牧場公司想用傳感器收集一些環境信息,記錄到數據庫里去,然后加以分析查看。這里面和傳感器通信用到了串口通信,我也是接觸了一下,把用到的東西分享出來。

准備工作:

  RXTX:封裝了Java對串口操作的類庫,具體的話大家自己百度一下吧。 資源地址:http://pan.baidu.com/s/1nuLZex7 密碼 m358  

  VSPD(Virtual Serial Port Driver):可以建立兩個虛擬的串口,我們用這兩個虛擬串口模擬測試。 資源地址:http://pan.baidu.com/s/1dEQtfPn 密碼 nhnc

  串口調試助手:可以模擬兩個串口之間的通信,作為我們的測試環境。  資源地址 :http://pan.baidu.com/s/1hs0eNxM 密碼 009k

 

  下載RXTX資源,解壓壓縮包,里面應該有三個文件,兩個dll文件,一個jar文件,三個文件都拷貝到你項目的lib目錄,build path。然后在你項目的configure build path里面 找到Native library location,edit 把目錄定位到你存放之前那兩個dll文件的文件夾,也就是lib文件夾。 ok,如下圖,准備工作完畢。

 

具體代碼:

  

  1 import java.io.BufferedInputStream;
  2 import java.io.BufferedOutputStream;
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.io.OutputStream;
  6 import java.util.Enumeration;
  7 import java.util.Properties;
  8 import java.util.TooManyListenersException;
  9 
 10 import org.springframework.beans.factory.annotation.Autowired;
 11 
 12 import com.dodo.detection.service.Services;
 13 
 14 import gnu.io.CommPortIdentifier;
 15 import gnu.io.PortInUseException;
 16 import gnu.io.SerialPort;
 17 import gnu.io.SerialPortEvent;
 18 import gnu.io.SerialPortEventListener;
 19 
 20 public class ReadSerialPort implements Runnable, SerialPortEventListener {
 21 
 22     private String appName = "dodo傳感器測試";
 23     private int timeout = 2000;//open 端口時的等待時間
 24     private int threadTime = 0;
 25     private String sport;
 26     private CommPortIdentifier commPort;
 27     private SerialPort serialPort;
 28     private InputStream inputStream;
 29     private OutputStream outputStream;
 30     
 31     private Services service;
 32     
 33     @Autowired
 34     public void setService(Services service) {
 35         this.service = service;
 36     }
 37     /**
 38      * @方法名稱 :listPort
 39      * @功能描述 :列出所有可用的串口
 40      * @返回值類型 :void
 41      */
 42     @SuppressWarnings("rawtypes")
 43     public void listPort(){
 44         CommPortIdentifier cpid;
 45         Enumeration en = CommPortIdentifier.getPortIdentifiers();
 46         
 47         System.out.println("now to list all Port of this PC:" +en);
 48         
 49         while(en.hasMoreElements()){
 50             cpid = (CommPortIdentifier)en.nextElement();
 51             if(cpid.getPortType() == CommPortIdentifier.PORT_SERIAL){
 52                 System.out.println(cpid.getName() + ", " + cpid.getCurrentOwner());
 53             }
 54         }
 55     }
 56     
 57     public ReadSerialPort() {
 58     }
 60 
 61     
 62     /**
 63      * @方法名稱 :selectPort
 64      * @功能描述 :選擇一個端口,比如:COM1
 65      * @返回值類型 :void
 66      *    @param portName
 67      */
 68     @SuppressWarnings("rawtypes")
 69     public void selectPort(String portName){
 70         
 71         this.commPort = null;
 72         CommPortIdentifier cpid;
 73         Enumeration en = CommPortIdentifier.getPortIdentifiers();
 74         
 75         while(en.hasMoreElements()){
 76             cpid = (CommPortIdentifier)en.nextElement();
 77             if(cpid.getPortType() == CommPortIdentifier.PORT_SERIAL
 78                     && cpid.getName().equals(portName)){
 79                 this.commPort = cpid;
 80                 break;
 81             }
 82         }
 83         
 84         openPort();
 85     }
 86     
 87     /**
 88      * @方法名稱 :openPort
 89      * @功能描述 :打開SerialPort
 90      * @返回值類型 :void
 91      */
 92     private void openPort(){
 93         if(commPort == null)
 94             log(String.format("無法找到名字為'%1$s'的串口!", commPort.getName()));
 95         else{
 96             log("端口選擇成功,當前端口:"+commPort.getName()+",現在實例化 SerialPort:");
 97             
 98             try{
 99                 serialPort = (SerialPort)commPort.open(appName, timeout);
100                 log("實例 SerialPort 成功!");
101             }catch(PortInUseException e){
102                 throw new RuntimeException(String.format("端口'%1$s'正在使用中!", 
103                         commPort.getName()));
104             }
105         }
106     }
107     
108     /**
109      * @方法名稱 :checkPort
110      * @功能描述 :檢查端口是否正確連接
111      * @返回值類型 :void
112      */
113     private void checkPort(){
114         if(commPort == null)
115             throw new RuntimeException("沒有選擇端口,請使用 " +
116                     "selectPort(String portName) 方法選擇端口");
117         
118         if(serialPort == null){
119             throw new RuntimeException("SerialPort 對象無效!");
120         }
121     }
122     
123     /**
124      * @方法名稱 :write
125      * @功能描述 :向端口發送數據,請在調用此方法前 先選擇端口,並確定SerialPort正常打開!
126      * @返回值類型 :void
127      *    @param message
128      */
129     public void write(String message) {
130         checkPort();
131         
132         try{
133             outputStream = new BufferedOutputStream(serialPort.getOutputStream());
134         }catch(IOException e){
135             throw new RuntimeException("獲取端口的OutputStream出錯:"+e.getMessage());
136         }
137         
138         try{
139             outputStream.write(message.getBytes());
140             log("信息發送成功!");
141         }catch(IOException e){
142             throw new RuntimeException("向端口發送信息時出錯:"+e.getMessage());
143         }finally{
144             try{
145                 outputStream.close();
146             }catch(Exception e){
147             }
148         }
149     }
150     
151     /**
152      * @方法名稱 :startRead
153      * @功能描述 :開始監聽從端口中接收的數據
154      * @返回值類型 :void
155      *    @param time  監聽程序的存活時間,單位為秒,0 則是一直監聽
156      */
157     public void startRead(int time){
158         checkPort();
159         
160         try{
161             inputStream = new BufferedInputStream(serialPort.getInputStream());
162         }catch(IOException e){
163             throw new RuntimeException("獲取端口的InputStream出錯:"+e.getMessage());
164         }
165         
166         try{
167             serialPort.addEventListener(this);
168         }catch(TooManyListenersException e){
169             throw new RuntimeException(e.getMessage());
170         }
171         
172         serialPort.notifyOnDataAvailable(true);
173         
174         log(String.format("開始監聽來自'%1$s'的數據--------------", commPort.getName()));
175         if(time > 0){
176             this.threadTime = time*1000;
177             Thread t = new Thread(this);
178             t.start();
179             log(String.format("監聽程序將在%1$d秒后關閉。。。。", threadTime));
180         }
181     }
182     public void startRead(){
183         checkPort();
184         
185         try{
186             inputStream = new BufferedInputStream(serialPort.getInputStream());
187         }catch(IOException e){
188             throw new RuntimeException("獲取端口的InputStream出錯:"+e.getMessage());
189         }
190         
191         try{
192             serialPort.addEventListener(this);
193         }catch(TooManyListenersException e){
194             throw new RuntimeException(e.getMessage());
195         }
196         
197         serialPort.notifyOnDataAvailable(true);
198         
199         log(String.format("開始監聽來自'%1$s'的數據--------------", commPort.getName()));
200         
201     }
202     
203     /**
204      * @方法名稱 :close
205      * @功能描述 :關閉 SerialPort
206      * @返回值類型 :void
207      */
208     public void close(){
209         serialPort.close();
210         serialPort = null;
211         commPort = null;
212     }
213     
214     
215     public void log(String msg){
216         System.out.println(appName+" --> "+msg);
217     }
218 
219 
220     /**
221      * 數據接收的監聽處理函數
222      */
223     @Override
224     public void serialEvent(SerialPortEvent arg0) {
225         switch(arg0.getEventType()){
226         case SerialPortEvent.BI:/*Break interrupt,通訊中斷*/ 
227         case SerialPortEvent.OE:/*Overrun error,溢位錯誤*/ 
228         case SerialPortEvent.FE:/*Framing error,傳幀錯誤*/
229         case SerialPortEvent.PE:/*Parity error,校驗錯誤*/
230         case SerialPortEvent.CD:/*Carrier detect,載波檢測*/
231         case SerialPortEvent.CTS:/*Clear to send,清除發送*/ 
232         case SerialPortEvent.DSR:/*Data set ready,數據設備就緒*/ 
233         case SerialPortEvent.RI:/*Ring indicator,響鈴指示*/
234         case SerialPortEvent.OUTPUT_BUFFER_EMPTY:/*Output buffer is empty,輸出緩沖區清空*/ 
235             break;
236         case SerialPortEvent.DATA_AVAILABLE:/*Data available at the serial port,端口有可用數據。讀到緩沖數組,輸出到終端*/
237             byte[] readBuffer = new byte[1024];
238             String readStr="";
239             String s2 = "";
240             try {
241                 
242                 while (inputStream.available() > 0) {
243                     inputStream.read(readBuffer);
244                     readStr += new String(readBuffer).trim();
245                 }
246                 
247                 s2 = new String(readBuffer).trim();
248                 
249                 log("接收到端口返回數據(長度為"+readStr.length()+"):"+readStr);
250                 log(s2);
251                 service.addRecord(s2);
252                 
253             } catch (IOException e) {
254                 e.printStackTrace();
255             }
256         }
257     }
258 
259 
260     @Override
261     public void run() {
262         try{
263             Thread.sleep(threadTime);
264             serialPort.close();
265             log(String.format("端口''監聽關閉了!", commPort.getName()));
266         }catch(Exception e){
267             e.printStackTrace();
268         }
269     }
270     276 
277     public String getSport() {
278         return sport;
279     }
280 
281     public void setSport(String sport) {
282         this.sport = sport;
283     }
284 }

注:我里面的那個sport屬性是spring注入進來的,大家測試的時候可以寫死 比如“COM1”,然后里面的service都不需要的。有問題請留言。

測試過程:

 

public static void main(String[] args) {  
          
        ReadSerialPortsp = new ReadSerialPort();  
          
        sp.listPort();  
          
        sp.selectPort("COM1");  
        sp.write("123456");  
        sp.write("hello");  
        sp.startRead(120);  
    }  

打開VSPD ,虛擬兩個串口,我這里虛擬的是COM1 和COM2

然后打開串口助手,找到COM2進行監聽:如圖

 

 

然后運行程序,相互傳輸數據即可。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM