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进行监听:如图

 

 

然后运行程序,相互传输数据即可。

 

posted @ 2016-04-24 21:44  嘟嘟死胖子  阅读(17598)  评论(1编辑  收藏  举报