串行接口是一種可以將接受來自CPU的并行數(shù)據(jù)字符轉(zhuǎn)換為連續(xù)的串行數(shù)據(jù)流發(fā)送出去,同時可將接受的串行數(shù)據(jù)流轉(zhuǎn)換為并行的數(shù)據(jù)字符供給CPU的器件。一般完成這種功能的電路,我們稱為串行接口電路。
Java是一門面向?qū)ο?a href="http://hljzzgx.com/v/tag/1315/" target="_blank">編程語言,不僅吸收了C++語言的各種優(yōu)點,還摒棄了C++里難以理解的多繼承、指針等概念,因此Java語言具有功能強大和簡單易用兩個特征。Java語言作為靜態(tài)面向?qū)ο缶幊陶Z言的代表,極好地實現(xiàn)了面向?qū)ο罄碚摚试S程序員以優(yōu)雅的思維方式進行復(fù)雜的編程。
串口通信原理
串口通信指串口按位(bit)發(fā)送和接收字節(jié)。盡管比按字節(jié)(byte)的并行通信慢,但是串口可以在使用一根線發(fā)送數(shù)據(jù)的同時用另一根線接收數(shù)據(jù)。
串口是計算機上一種非常通用的設(shè)備通信協(xié)議(不要與通用串行總線Universal SerialBus或者USB混淆)
典型地,串口用于ASCII碼字符的傳輸。通信使用3根線完成:(1)地線,(2)發(fā)送,(3)接收。由于串口通信是異步的,端口能夠在一根線上發(fā)送數(shù)據(jù)同時在另一根線上接收數(shù)據(jù)。其他線用于握手,但是不是必須的。串口通信最重要的參數(shù)是比特率、數(shù)據(jù)位、停止位和奇偶校驗。對于兩個進行通信的端口,這些參數(shù)必須匹配
RS-232(ANSI/EIA-232標準)是IBM-PC及其兼容機上的串行連接標準、RS-422(EIA RS-422-AStandard)是Apple的Macintosh計算機的串口連接標準。RS-485(EIA-485標準)是RS-422的改進。
在一臺電腦完成串口通信及調(diào)試所需的準備工作
由于筆記本或臺式機上基本上都沒有成對的串口提供給我們調(diào)試使用,我們就需要下載虛擬串口軟件來實現(xiàn)串口調(diào)試。
下載虛擬串口軟件http://pan.baidu.com/s/1hqhGDbI(這里提供的還是比較好用)。下載安裝完成后先不要急著運行,把壓縮包中的vspdctl.dll文件復(fù)制到安裝目錄下如:我的目錄為–》D:\SoftWareInstall\Virtual Serial Port Driver 7.2 替換原有文件即可成功激活。
打開軟件添加虛擬串口,一般都是成對添加的(添加COM3、COM4)后如圖所示:
添加完成后到設(shè)備管理器中查看,發(fā)現(xiàn)多了兩個虛擬串口如圖:
至此,創(chuàng)建虛擬串口的工作就全部完成了。
下載串口調(diào)試軟件http://pan.baidu.com/s/1c0AVaXq這里提供的是比較老的調(diào)試軟件了,但還是比較好用的哦。直接解壓點擊打開就ok了。
可以直接先打開兩個調(diào)試窗口,分別用來表示COM3和COM4串口。兩個串口的參數(shù)一定要設(shè)置的一樣才可以正常的收發(fā)數(shù)據(jù)。(若調(diào)試可以正常收發(fā)數(shù)據(jù)后,可以關(guān)掉一個調(diào)試器,而用java程序代替)如圖:
java程序代碼編寫
這一部分將是我們的重點,要與串口通信首先要在項目添加RXTXcomm.jar包(放在項目中的lib目錄下,并添加到build Path中)(win64位下載地址:http://pan.baidu.com/s/1o6zLmTc);另外,還需要將解壓后的rxtxParallel.dll和rxtxSerial.dll兩個文件放在%JAVA_HOME%/jre/bin目錄下,這樣該包才能被正常的加載和調(diào)用。
程序代碼解析:
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
// 監(jiān)聽器,我的理解是獨立開辟一個線程監(jiān)聽串口數(shù)據(jù)
static CommPortIdentifier portId; // 串口通信管理類
static Enumeration《?》 portList; // 有效連接上的端口的枚舉
InputStream inputStream; // 從串口來的輸入流
static OutputStream outputStream;// 向串口輸出的流
static SerialPort serialPort; // 串口的引用
// 堵塞隊列用來存放讀到的數(shù)據(jù)
private BlockingQueue《String》 msgQueue = new LinkedBlockingQueue《String》();
@Override
/**
* SerialPort EventListene 的方法,持續(xù)監(jiān)聽端口上是否有數(shù)據(jù)流
*/
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:// 當有可用數(shù)據(jù)時讀取數(shù)據(jù)
byte[] readBuffer = new byte[20];
try {
int numBytes = -1;
while (inputStream.available() 》 0) {
numBytes = inputStream.read(readBuffer);
if (numBytes 》 0) {
msgQueue.add(new Date() + “真實收到的數(shù)據(jù)為:-----”
+ new String(readBuffer));
readBuffer = new byte[20];// 重新構(gòu)造緩沖對象,否則有可能會影響接下來接收的數(shù)據(jù)
} else {
msgQueue.add(“額------沒有讀到數(shù)據(jù)”);
}
}
} catch (IOException e) {
}
break;
}
}
/**
*
* 通過程序打開COM4串口,設(shè)置監(jiān)聽器以及相關(guān)的參數(shù)
*
* @return 返回1 表示端口打開成功,返回 0表示端口打開失敗
*/
public int startComPort() {
// 通過串口通信管理類獲得當前連接上的串口列表
portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
// 獲取相應(yīng)串口對象
portId = (CommPortIdentifier) portList.nextElement();
System.out.println(“設(shè)備類型:---》” + portId.getPortType());
System.out.println(“設(shè)備名稱:----》” + 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;
}
// 設(shè)置當前串口的輸入輸出流
try {
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
return 0;
}
// 給當前串口添加一個監(jiān)聽器
try {
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {
e.printStackTrace();
return 0;
}
// 設(shè)置監(jiān)聽器生效,即:當有數(shù)據(jù)時通知
serialPort.notifyOnDataAvailable(true);
// 設(shè)置串口的一些讀寫參數(shù)
try {
// 比特率、數(shù)據(jù)位、停止位、奇偶校驗位
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(“--------------任務(wù)處理線程運行了--------------”);
while (true) {
// 如果堵塞隊列中存在數(shù)據(jù)就將其輸出
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) {
// 啟動線程來處理收到的數(shù)據(jù)
cRead.start();
try {
String st = “哈哈----你好”;
System.out.println(“發(fā)出字節(jié)數(shù):” + 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;
}
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
java程序與串口通信調(diào)試
程序調(diào)試截圖:
總結(jié)
串口通信在很多地方都要用到,特別是嵌入式開發(fā)、短信模塊開發(fā)以及為各種硬件產(chǎn)品定制軟件等都需要用到。其中最經(jīng)常用的通信協(xié)議為RS-232通信協(xié)議,要想成為真正的串口通信開發(fā)高手就需要全面的了解串口的通信協(xié)議(本人還是菜鳥一枚。。。希望高手指點)。
串口通信的另一個重點在于接收到數(shù)據(jù)后,如何判斷數(shù)據(jù)的類型以及有效數(shù)據(jù)的提取等,這些都需要根據(jù)相應(yīng)的協(xié)議進行代碼編寫。
評論
查看更多