java的串口通信問(wèn)題
一、實(shí)驗(yàn)?zāi)康?/h2>
(1)了解串口的通信方式。
(2)掌握串口通信的原理,了解串口通信的編程的初步概念和相應(yīng)函數(shù),掌握一個(gè)具體開(kāi)
發(fā)平臺(tái)下的串口編程。
二、實(shí)驗(yàn)內(nèi)容
這一部分將是我們的重點(diǎn),要與串口通信首先要在項(xiàng)目添加RXTXcomm.jar包(放在項(xiàng)目中的lib目錄下,并添加到build Path中);
另外,還需要將解壓后的rxtxParallel.dll和rxtxSerial.dll兩個(gè)文件放在%JAVA_HOME%/jre/bin目錄下,這樣該包才能被正常的加載和調(diào)用。
由于筆記本或臺(tái)式機(jī)上基本上都沒(méi)有成對(duì)的串口提供給我們調(diào)試使用,我們就需要下載虛擬串口軟件來(lái)實(shí)現(xiàn)串口調(diào)試。
- 下載虛擬串口軟件。
- 打開(kāi)軟件添加虛擬串口vspd,一般都是成對(duì)添加的(添加COM6、COM9)
- 添加完成后到設(shè)備管理器中查看,發(fā)現(xiàn)多了兩個(gè)虛擬串口
- 下載串口調(diào)試軟件sscom32
- 可以直接先打開(kāi)兩個(gè)調(diào)試窗口,分別用來(lái)表示COM6和COM9串口。兩個(gè)串口的參數(shù)一定要設(shè)置的一樣才可以正常的收發(fā)數(shù)據(jù)。(若調(diào)試可以正常收發(fā)數(shù)據(jù)后,可以關(guān)掉一個(gè)調(diào)試器,而用java程序代替)


三、實(shí)驗(yàn)結(jié)果及分析
串口通信在很多地方都要用到,特別是嵌入式開(kāi)發(fā)、短信模塊開(kāi)發(fā)以及為各種硬件產(chǎn)品定制軟件等都需要用到。
其中最經(jīng)常用的通信協(xié)議為RS-232通信協(xié)議,要想成為真正的串口通信開(kāi)發(fā)高手就需要全面的了解串口的通信協(xié)議(本人還是菜鳥(niǎo)一枚。。。希望高手指點(diǎn))。
串口通信的另一個(gè)重點(diǎn)在于接收到數(shù)據(jù)后,如何判斷數(shù)據(jù)的類型以及有效數(shù)據(jù)的提取等,這些都需要根據(jù)相應(yīng)的協(xié)議進(jìn)行代碼編寫(xiě)。


四、實(shí)驗(yàn)小結(jié)、問(wèn)題討論
(1)串口有兩種
1.PC上的COM口
COM口即串行通訊端口。微機(jī)上的com口多為9針,最大速率115200bps。
通常用于連接鼠標(biāo)(串口)及通訊設(shè)備(如連接外置式MODEM進(jìn)行數(shù)據(jù)通訊)等。
但目前主流的主板一般都只帶1個(gè)串口,甚至不帶。
機(jī)箱后面,梯形的,兩排,一排5個(gè)孔,一排4個(gè)孔
一般有兩個(gè),就是com1 com2,背板上應(yīng)該都標(biāo)明的
反正要么上1下2,要么左1右2
可以轉(zhuǎn)接USB
2.設(shè)備上的Serial口
專為廣域網(wǎng)設(shè)計(jì),它可以做ISDN,PPP,幀中繼等網(wǎng)絡(luò)類型的連接可以接很多網(wǎng)絡(luò)類型,要使用它必須設(shè)置時(shí)鐘頻率(DCE、DTE),路由表的算法也在此接口上形成。
以太網(wǎng)口是對(duì)局域網(wǎng)內(nèi)的,它只有擁有局域網(wǎng)所需要的所有功能。
沒(méi)有廣域網(wǎng)接口所需要的功能,而廣域網(wǎng)串口也沒(méi)有局域網(wǎng)以太網(wǎng)口接口的功能,所以兩個(gè)接口是不能對(duì)調(diào)的。
路由器連接路由器就要用路由器上的Serial端口連接,不過(guò)現(xiàn)在的路由器都沒(méi)有這些,都用光口代替了。
ethernet口:以太網(wǎng)口,現(xiàn)在可以說(shuō)是百兆口,交換機(jī)間連在一起用的。
以太口(eth)是接RJ45水晶頭的,串口(ser) 是遠(yuǎn)距離連接 使用的!可以是電纜也可以是光纖!
串口是串行口通訊協(xié)議,以太網(wǎng)口是以太網(wǎng)通訊協(xié)議。
(2)
- 讀出寄存器數(shù)據(jù)
- 將讀出的數(shù)據(jù)轉(zhuǎn)換成可計(jì)算的數(shù)據(jù)類型(兩個(gè)char類型轉(zhuǎn)換成一個(gè)short或int或float類型)
- 根據(jù)公式計(jì)算
根據(jù)公式計(jì)算
不用union的函數(shù)也可以用sprintf實(shí)現(xiàn)
package com.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
/**
* @項(xiàng)目名稱 :DSerialPort
* @文件名稱 :SerialPort.java
* @所在包 :org.serial
* @功能描述 : 串口類
* @修改記錄 :
*/
public class DSerialPort implements Runnable, SerialPortEventListener {
private String appName = "串口通訊測(cè)試";
private int timeout = 2000;// open 端口時(shí)的等待時(shí)間
private int threadTime = 0;
private CommPortIdentifier commPort;
private SerialPort serialPort;
private InputStream inputStream;
private OutputStream outputStream;
/**
* @方法名稱 :listPort
* @功能描述 :列出所有可用的串口
* @返回值類型 :void
*/
@SuppressWarnings("rawtypes")
public void listPort() {
CommPortIdentifier cpid;
Enumeration en = CommPortIdentifier.getPortIdentifiers();
System.out.println("now to list all Port of this PC:" + en);
while (en.hasMoreElements()) {
cpid = (CommPortIdentifier) en.nextElement();
if (cpid.getPortType() == CommPortIdentifier.PORT_SERIAL) {
System.out.println(cpid.getName() + ", " + cpid.getCurrentOwner());
}
}
}
/**
* @方法名稱 :selectPort
* @功能描述 :選擇一個(gè)端口,比如:COM1
* @返回值類型 :void
* @param portName
*/
@SuppressWarnings("rawtypes")
public void selectPort(String portName) {
this.commPort = null;
CommPortIdentifier cpid;
Enumeration en = CommPortIdentifier.getPortIdentifiers();
while (en.hasMoreElements()) {
cpid = (CommPortIdentifier) en.nextElement();
if (cpid.getPortType() == CommPortIdentifier.PORT_SERIAL && cpid.getName().equals(portName)) {
this.commPort = cpid;
break;
}
}
openPort();
}
/**
* @方法名稱 :openPort
* @功能描述 :打開(kāi)SerialPort
* @返回值類型 :void
*/
private void openPort() {
if (commPort == null){
log(String.format("無(wú)法找到名字為'%1$s'的串口!", commPort.getName()));}
else {
log("端口選擇成功,當(dāng)前端口:" + commPort.getName() + ",現(xiàn)在實(shí)例化 SerialPort:");
try {
serialPort = (SerialPort) commPort.open(appName, timeout);
log("實(shí)例 SerialPort 成功!");
} catch (PortInUseException e) {
throw new RuntimeException(String.format("端口'%1$s'正在使用中!", commPort.getName()));
}
}
}
/**
* @方法名稱 :checkPort
* @功能描述 :檢查端口是否正確連接
* @返回值類型 :void
*/
private void checkPort() {
if (commPort == null){
throw new RuntimeException("沒(méi)有選擇端口,請(qǐng)使用 " + "selectPort(String portName) 方法選擇端口");}
if (serialPort == null) {
throw new RuntimeException("SerialPort 對(duì)象無(wú)效!");
}
}
/**
* @方法名稱 :write
* @功能描述 :向端口發(fā)送數(shù)據(jù),請(qǐng)?jiān)谡{(diào)用此方法前 先選擇端口,并確定SerialPort正常打開(kāi)!
* @返回值類型 :void
* @param message
*/
public void write(String message) {
checkPort();
try {
outputStream = new BufferedOutputStream(serialPort.getOutputStream());
} catch (IOException e) {
throw new RuntimeException("獲取端口的OutputStream出錯(cuò):" + e.getMessage());
}
try {
outputStream.write(message.getBytes("GBK"), 0, message.getBytes("GBK").length);
//outputStream.write(message.getBytes());
log("信息發(fā)送成功:"+new String(message.getBytes()));
} catch (IOException e) {
throw new RuntimeException("向端口發(fā)送信息時(shí)出錯(cuò):" + e.getMessage());
} finally {
try {
outputStream.close();
} catch (Exception e) {
}
}
}
/**
* @方法名稱 :startRead
* @功能描述 :開(kāi)始監(jiān)聽(tīng)從端口中接收的數(shù)據(jù)
* @返回值類型 :void
* @param time
* 監(jiān)聽(tīng)程序的存活時(shí)間,單位為秒,0 則是一直監(jiān)聽(tīng)
*/
public void startRead(int time) {
checkPort();
try {
inputStream = new BufferedInputStream(serialPort.getInputStream());
} catch (IOException e) {
throw new RuntimeException("獲取端口的InputStream出錯(cuò):" + e.getMessage());
}
try {
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {
throw new RuntimeException(e.getMessage());
}
serialPort.notifyOnDataAvailable(true);
log(String.format("開(kāi)始監(jiān)聽(tīng)來(lái)自'%1$s'的數(shù)據(jù)--------------", commPort.getName()));
if (time > 0) {
this.threadTime = time * 1000;
Thread t = new Thread(this);
t.start();
log(String.format("監(jiān)聽(tīng)程序?qū)⒃?1$d秒后關(guān)閉。。。。", threadTime));
}
}
/**
* @方法名稱 :close
* @功能描述 :關(guān)閉 SerialPort
* @返回值類型 :void
*/
public void close() {
serialPort.close();
serialPort = null;
commPort = null;
}
public void log(String msg) {
System.out.println(appName + " --> " + msg);
}
/**
* 數(shù)據(jù)接收的監(jiān)聽(tīng)處理函數(shù)
*/
@Override
public void serialEvent(SerialPortEvent arg0) {
switch (arg0.getEventType()) {
case SerialPortEvent.BI:/* Break interrupt,通訊中斷 */
case SerialPortEvent.OE:/* Overrun error,溢位錯(cuò)誤 */
case SerialPortEvent.FE:/* Framing error,傳幀錯(cuò)誤 */
case SerialPortEvent.PE:/* Parity error,校驗(yàn)錯(cuò)誤 */
case SerialPortEvent.CD:/* Carrier detect,載波檢測(cè) */
case SerialPortEvent.CTS:/* Clear to send,清除發(fā)送 */
case SerialPortEvent.DSR:/* Data set ready,數(shù)據(jù)設(shè)備就緒 */
case SerialPortEvent.RI:/* Ring indicator,響鈴指示 */
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:/*
* Output buffer is
* empty,輸出緩沖區(qū)清空
*/
break;
case SerialPortEvent.DATA_AVAILABLE:/*
* Data available at the serial
* port,端口有可用數(shù)據(jù)。讀到緩沖數(shù)組,輸出到終端
*/
byte[] readBuffer = new byte[1024];
String readStr = "";
String s2 = "";
try {
while (inputStream.available() > 0) {
inputStream.read(readBuffer);
readStr += new String(readBuffer).trim();
}
s2 = new String(readBuffer).trim();
log("接收到端口返回?cái)?shù)據(jù)(長(zhǎng)度為" + readStr.length() + "):" + readStr);
log(s2);
} catch (IOException e) {
}
}
}
@Override
public void run() {
try {
Thread.sleep(threadTime);
serialPort.close();
log(String.format("端口''監(jiān)聽(tīng)關(guān)閉了!", commPort.getName()));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
DSerialPort dp = new DSerialPort();
dp.listPort();
dp.selectPort("COM6");
dp.write("tdgfg!");
dp.startRead(30);
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java設(shè)計(jì)模式之策略模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
策略模式是對(duì)算法的封裝,把一系列的算法分別封裝到對(duì)應(yīng)的類中,并且這些類實(shí)現(xiàn)相同的接口,相互之間可以替換。接下來(lái)通過(guò)本文給大家分享Java設(shè)計(jì)模式之策略模式,感興趣的朋友一起看看吧2017-08-08
關(guān)于MyBatis plus條件構(gòu)造器的逐條詳解
什么是條件構(gòu)造器呢?簡(jiǎn)單來(lái)說(shuō),條件構(gòu)造器就是用來(lái)生成我們查數(shù)據(jù)庫(kù)的sql。它可以簡(jiǎn)化sql代碼的編寫(xiě),靈活、方便且易于維護(hù)2021-09-09
JavaWeb評(píng)論功能實(shí)現(xiàn)步驟以及代碼實(shí)例
項(xiàng)目初始版本上線,有時(shí)間寫(xiě)點(diǎn)東西記錄一下項(xiàng)目中的心得體會(huì),通過(guò)這個(gè)項(xiàng)目學(xué)習(xí)了很多,要寫(xiě)下來(lái)的有很多,先從評(píng)論功能開(kāi)始吧,下面這篇文章主要給大家介紹了關(guān)于JavaWeb評(píng)論功能實(shí)現(xiàn)步驟以及代碼的相關(guān)資料,需要的朋友可以參考下2023-01-01
MyBatis一對(duì)一級(jí)聯(lián)更新問(wèn)題小結(jié)
日常工作中經(jīng)常會(huì)涉及到一對(duì)一級(jí)聯(lián)更新的問(wèn)題,本文主要介紹了MyBatis一對(duì)一級(jí)聯(lián)更新問(wèn)題小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
Java類變量和成員變量初始化過(guò)程的應(yīng)用介紹
昨天看了一本叫做《突破程序員基本功的16課》的書(shū),個(gè)人感覺(jué)還可以,主要對(duì)Java的技巧進(jìn)行了一些深入的講解,讓我對(duì)類的初始化和對(duì)象的創(chuàng)建有了新的認(rèn)識(shí)2013-04-04
springboot+jwt+springSecurity微信小程序授權(quán)登錄問(wèn)題
這篇文章主要介紹了springboot+jwt+springSecurity微信小程序授權(quán)登錄問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
SpringMVC的Body參數(shù)攔截的問(wèn)題
SpringMVC對(duì)出參和入?yún)⒂蟹浅S押玫耐卣怪С?方便你對(duì)數(shù)據(jù)的輸入和輸出有更大的執(zhí)行權(quán),我們?nèi)绾瓮ㄟ^(guò)SpringMVC定義的結(jié)果做一系列處理呢,需要的朋友可以參考下2018-06-06

