串行接口是一種可以將接受來自CPU的并行數據字符轉換為連續的串行數據流發送出去,同時可將接受的串行數據流轉換為并行的數據字符供給CPU的器件。一般完成這種功能的電路,我們稱為串行接口電路。
Java是一門面向對象編程語言,不僅吸收了C++語言的各種優點,還摒棄了C++里難以理解的多繼承、指針等概念,因此Java語言具有功能強大和簡單易用兩個特征。Java語言作為靜態面向對象編程語言的代表,極好地實現了面向對象理論,允許程序員以優雅的思維方式進行復雜的編程。
串口通信原理
串口通信指串口按位(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程序代替)如圖:
java程序代碼編寫
這一部分將是我們的重點,要與串口通信首先要在項目添加RXTXcomm.jar包(放在項目中的lib目錄下,并添加到build Path中)(win64位下載地址:http://pan.baidu.com/s/1o6zLmTc);另外,還需要將解壓后的rxtxParallel.dll和rxtxSerial.dll兩個文件放在%JAVA_HOME%/jre/bin目錄下,這樣該包才能被正常的加載和調用。
程序代碼解析:
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;
}
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
java程序與串口通信調試
程序調試截圖:
總結
串口通信在很多地方都要用到,特別是嵌入式開發、短信模塊開發以及為各種硬件產品定制軟件等都需要用到。其中最經常用的通信協議為RS-232通信協議,要想成為真正的串口通信開發高手就需要全面的了解串口的通信協議(本人還是菜鳥一枚。。。希望高手指點)。
串口通信的另一個重點在于接收到數據后,如何判斷數據的類型以及有效數據的提取等,這些都需要根據相應的協議進行代碼編寫。
評論
查看更多