java串口通信

更新时间:2024-01-11 07:03:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

javaCommunications API 简介........................................................................................................ 1 利用Java实现串口(Comm)全双工通(应广大读者要求,已做修改,附件有代码) ........................ 3 主题:JAVA操作串口有感 ............................................................................................................ 5 windows中java实现的串口通信 ................................................................................................. 11 Java串口通信-01 ........................................................................................................................... 18 Java串口通信-2 ............................................................................................................................. 19 笔记本电脑没有com端口 ............................................................................................................ 28 如何把com3接口改为com1接口?com1,com3在结构上和用途上有差别吗? ........................ 29

javaCommunications API 简介

Java提供了 CommunicationAPI(包含于javax.com包中)用于通过与机器无关的方式,控制各种外部设备。Communications API,是标准的Java的扩展部分,它在JavaAPI中是没有附带的。因此,必须先在SUN公司网站的Java站点 (www.java.sun.com)上下载这个扩展类库。

1.1Communications API 简介

Communications API 的核心是抽象的CommPort类及其两个子类:SerialPort类和ParallePort类。其中,SerialPort类是用于串口通信的类,ParallePort类是用于并行口通信的类。CommPort类还提供了常规的通信模式和方法,例如:getInputStream( )方法和getOutputStream( )方法,专用于与端口上的设备进行通信。

然而,这些类的构造方法都被有意的设置为非公有的(non-public)。所以,不能直接构造对象,而是先通过静态的 CommPortIdentifer.getPortIdentifiers()获得端口列表;再从这个端口列表中选择所需要的端口,并调用 CommPortIdentifer对象的Open( )方法,这样,就能得到一个CommPort对象。当然,还要将这个CommPort对象的类型转换为某个非抽象的子类,表明是特定的通讯设备。该子类可以是SerialPort类和ParallePort类中的一个。下面将分别对CommPort类,CommPortIdentifier类,串口类SerialPort进行详细的介绍。 1.2 CommPortIdentifier类

CommPortIdentifier类的方法如下:

方法 说明

addPortName(String, int, CommDriver) 添加端口名到端口列表里 addPortOwnershipListener(CommPortOwnershipListener) 添加端口拥有的监听器 removePortOwnershipListener(CommPortOwnershipListener) 移除端口拥有的监听器

getCurrentOwner() 得到当前占有端口的对象或应用程序

getName() 得到端口名称

getPortIdentifier(CommPort) 得到参数打开的端口的CommPortIdentifier类型对象.

getPortIdentifier(String) 得到以参数命名的端口的CommPortIdentifier类型对象

getPortIdentifiers() 得到系统中的端口列表 getPortType() 得到端口的类型

isCurrentlyOwned() 判断当前端口是否被占用 open(FileDescriptor) 用文件描述的类型打开端口

open(String, int) 打开端口,两个参数:程序名称,延迟时间(毫秒数)

1.3 SerialPort类

《1》SerialPort关于串口参数的静态成员变量:

成员变量 说明 成员变量 说明 成员变量 说明

DATABITS_5 数据位为5 , STOPBITS_2 停止位为2 , PARITY_ODD 奇检验

DATABITS_6 数据位为6, STOPBITS_1 停止位为1, PARITY_MARK 标记检验 DATABITS_7 数据位为7, STOPBITS_1_5 停止为1.5, PARITY_NONE 空格检验 DATABITS_8 数据位为8, PARITY_EVEN 偶检验 , PARITY_SPACE 无检验

《2》SerialPort对象的关于串口参数的函数: 方法 说明

getBaudRate() 得到波特率 getParity() 得到检验类型 getDataBits() 得到数据位数 getStopBits() 得到停止位数

setSerialPortParams(int, int, int, int) 设置串口参数依次为(波特率,数据位,停止位,奇偶检验)

《3》SerialPort关于事件的静态成员变量: 成员变量 说明 BI Break interrupt中断 FE Framing error错误

CD Carrier detect载波侦听 OE Overrun error错误

CTS Clear to send清除以传送 PE Parity error奇偶检验错误 DSR Data set ready数据备妥 RI Ring indicator响铃侦测

DATA_AVAILABLE 串口中的可用数据 OUTPUT_BUFFER_EMPTY 输出缓冲区空

《4》SerialPort中关于事件的方法: 方法 说明

isCD() 是否有载波 isCTS() 是否清除以传送 isDSR() 数据是否备妥 isDTR() 是否数据端备妥 isRI() 是否响铃侦测 isRTS() 是否要求传送

addEventListener(SerialPortEventListener) 向SerialPort对象中添加串口事件监听器

removeEventListener() 移除SerialPort对象中的串口事件监听器 notifyOnBreakInterrupt(boolean) 设置中断事件true有效,false无效 notifyOnCarrierDetect(boolean) 设置载波监听事件true有效,false无效 notifyOnCTS(boolean) 设置清除发送事件true有效,false无效

notifyOnDataAvailable(boolean) 设置串口有数据的事件true有效,false无效 notifyOnDSR(boolean) 设置数据备妥事件true有效,false无效

notifyOnFramingError(boolean) 设置发生错误事件true有效,false无效

notifyOnOutputEmpty(boolean) 设置发送缓冲区为空事件true有效,false无效 notifyOnParityError(boolean) 设置发生奇偶检验错误事件true有效,false无效 notifyOnRingIndicator(boolean) 设置响铃侦测事件true有效,false无效 getEventType() 得到发生的事件类型返回值为int型 sendBreak(int) 设置中断过程的时间,参数为毫秒值 setRTS(boolean) 设置或清除RTS位 setDTR(boolean) 设置或清除DTR位

《5》SerialPort中的其他常用方法 方法 说明

close() 关闭串口

getOutputStream() 得到OutputStream类型的输出流 getInputStream() 得到InputStream类型的输入流

利用Java实现串口(Comm)全双工通(应广大读者要求,已做修改,附件有代码)

本人因为项目开发的需要,需要PC机和硬件的通讯,而这个通讯通过Comm串口实现,而 最好又是全双工的通讯,譬如一个流水线控制系统需要不断的接受从主控系统发送来的查询和控制信息,并将执行结果或查询结果发送回主控系统。本文介绍了一个简单的通过串口实现全双工通讯的Java类库,该类库大大的简化了对串口进行操作的过程。

本类库主要包括:SerialBean.java (与其他应用程序的接口), SerialBuffer.java (用来保存从串口所接收数据的缓冲区), ReadSerial.java (从串口读取数据的程序)。另外本类库还提供了一个例程SerialExample.java 作为示范。在下面的内容中将逐一对这几个部分进行详细介绍。 1. SerialBean

SerialBean是本类库与其他应用程序的接口。该类库中定义了SerialBean的构造方法以及初始化串口,从串口读取数据,往串口写入数据以及关闭串口的函数。具体介绍如下: public SerialBean(int PortID)

本函数构造一个指向特定串口的SerialBean,该串口由参数PortID所指定。PortID = 1 表示COM1,PortID = 2 表示COM2,由此类推。 public int Initialize()

本函数初始化所指定的串口并返回初始化结果。如果初始化成功返回1,否则返回-1。初始化的结果是该串口被SerialBean独占性使用,其参数被设置为9600, N, 8, 1。如果串口被成功初始化,则打开一个进程读取从串口传入的数据并将其保存在缓冲区中。

public String ReadPort(int Length)

本函数从串口(缓冲区)中读取指定长度的一个字符串。参数Length指定所返回字符串的长度。

public void WritePort(String Msg)

本函数向串口发送一个字符串。参数Msg是需要发送的字符串。 public void ClosePort()

本函数停止串口检测进程并关闭串口。 2. SerialBuffer

SerialBuffer是本类库中所定义的串口缓冲区,它定义了往该缓冲区中写入数据和从该缓冲区中读取数据所需要的函数。

public synchronized String GetMsg(int Length)

本函数从串口(缓冲区)中读取指定长度的一个字符串。参数Length指定所返回字符串的长度。

public synchronized void PutChar(int c)

本函数望串口缓冲区中写入一个字符,参数c 是需要写入的字符。

在往缓冲区写入数据或者是从缓冲区读取数据的时候,必须保证数据的同步,因此GetMsg和PutChar函数均被声明为synchronized并在具体实现中采取措施实现的数据的同步。 3. ReadSerial

ReadSerial是一个进程,它不断的从指定的串口读取数据并将其存放到缓冲区中。 public ReadSerial(SerialBuffer SB, InputStream Port)

本函数构造一个ReadSerial进程,参数SB指定存放传入数据的缓冲区,参数Port指定从串口所接收的数据流。 public void run()

ReadSerial进程的主函数,它不断的从指定的串口读取数据并将其存放到缓冲区中。 4. SerialExample

SerialExample是本类库所提供的一个例程。它所实现的功能是打开串口COM1,对其进行初始化,从串口读取信息对其进行处理后将处理结果发送到串口。 5. 编译与调试

本类库中使用了Java Communication API (javax.comm)。这是一个Java扩展类库,并不包括在标准的Java SDK当中。如果你尚未安装这个扩展类库的话,你应该从Sun公司的Java站点下载这个类库并将其安装在你的系统上。在所下载的包里面包括一个安装说 明,如果你没有正确安装这个类库及其运行环境的话,运行这个程序的时候你会找不到串口。 正确安装Java Communication API并将上述程序编译通过以后,你可以按如下方法测试这个程序。如果你只有一台机器,你可以利用一条RS-232电缆将COM1和COM2连接起来,在 COM1上运行SerialExample,在COM2上运行Windows提供的超级终端程序。如果你有两台机器的话,你可以利用一条RS-232电缆 将两台机器的COM1(或者是COM2)连接起来,在一端运行例程,另外一端运行Windows提供的超级终端程序。如果有必要的话,可以对 SerialExample中所声明的串口进行相应改动。

本程序在Windows 2000 + Java SDK 1.3环境下编译通过并成功运行。

如想要这几个文件的原代码,请留言,而且也能帮忙调试,因为关键在环境部署上,不能出错。

应广大读者的需要,本人把代码简单做了整理,特意发出来让大家相互学习!

? serial.rar (5.6 KB)

? 描述: 就此整理发出去,让大家互相学习! ? 下载次数: 824

主题:JAVA操作串口有感

在做过一年多的RXTX操作串口项目有现在把一些平时遇到的问题在这里写写:

RXTX是一个开源包,主要是在COMM开源包中做扩张,以前的COMM包只能在WINDOWS下面对串口或并口做操作,扩充后的RXTX可以在LINUX和MAC下对串口和并口做操作。 现在跨平台:

在RXTX网站下载JAR包和动态库

http://users.frii.com/jarvi/rxtx/download.html

下载后配置环境

Windows

拷贝RXTXcomm.jar 文件到 \\jre\\lib\\ext 目录下 拷贝rxtxSerial.dll文件到 \\jre\\bin目录下

Mac OS X (x86 and ppc) (there is an Installer with the source)

MAC下面我自己没有配置环境成功,后来找一个MAC下RXTX的安装把环境配置好的。 http://www.jdivelog.org/how-to/mac-os-x/下载安装环境配置文件RXTX_Tiger.pkg

Linux (only x86, x86_64, ia64 here but more in the ToyBox)

拷贝RXTXcomm.jar 文件到 /jre/lib/ext 目录下

拷贝librxtxSerial.so 文件到 /jre/lib/[machine type] (i386 for instance)目录下 并将拷贝文件释放权限给所有用户

Solaris (sparc only so far)

拷贝RXTXcomm.jar 文件到 /jre/lib/ext 目录下

拷贝librxtxSerial.so 文件到 /jre/lib/[machine type]目录下 并将拷贝文件释放权限给所有用户

环境搭建好后开始写代码实现 import java.io.*;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.TooManyListenersException;

import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort;

import gnu.io.SerialPortEvent;

import gnu.io.SerialPortEventListener;

public class SerialComm implements SerialPortEventListener, Runnable { public final static String PORT_OWER = \ private boolean isOpen; private boolean isStart; private boolean isSave; private boolean isPrint; private Thread readThread; private String portName; private String portAddress; private CommPortIdentifier portId; private SerialPort serialPort; private DataInputStream inputStream; private OutputStream outputStream; private SimpleDateFormat formatter; // prase data with process private String dataProtocol; private Object readWriteLock = new Object();

public SerialComm() { isOpen = false; isStart = false; isSave = true; isPrint = false; formatter = new SimpleDateFormat(\ }

portName = \portAddress = \dataProtocol = \

public void init(String port, String protocol) throws Exception { portName = port; portAddress = portName; dataProtocol = protocol; }

init();

public void init(String port, String address, String protocol) throws Exception { portName = port; portAddress = address; dataProtocol = protocol; }

init();

public void init() throws IOException, Exception, Exception { if (isOpen) { close(); }

try { //传送串口名创建CommPortIdentifier对象服务。 portId = CommPortIdentifier.getPortIdentifier(portName);

//使用portId对象服务打开串口,并获得串口对象

serialPort = (SerialPort) portId.open(PORT_OWER, 2000);

}

//通过串口对象获得读串口流对象

inputStream = new DataInputStream(serialPort.getInputStream()); //通过串口对象获得写串口流对象

outputStream = serialPort.getOutputStream();

isOpen = true;

} catch (NoSuchPortException ex) { throw new Exception(ex.toString()); } catch (PortInUseException ex) { throw new Exception(ex.toString()); }

public void start() throws Exception { if (!isOpen) { throw new Exception(portName + \ } }

try { //创建对象线程 readThread = new Thread(this); readThread.start();

//设置串口数据时间有效

serialPort.notifyOnDataAvailable(true); //增加监听

serialPort.addEventListener(this); isStart = true;

} catch (TooManyListenersException ex) { throw new Exception(ex.toString()); }

public void run() { String at = \ }

String strTemp = at + (char) Integer.parseInt(\writeComm(strTemp); isPrint = true;

public void stop() { if (isStart) { serialPort.notifyOnDataAvailable(false); serialPort.removeEventListener(); }

}

isStart = false;

public void close() { stop(); }

if (isOpen) { try { inputStream.close(); outputStream.close(); serialPort.close(); }

isOpen = false; } catch (IOException ex) { }

//如果串口有数据上报则主动调用此方法 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: readComm(); break; default: break; }

public void readComm() { StringBuffer readBuffer = new StringBuffer(); String scannedInput = \ Date currentTime = null; String TimeStamp = \ int c; char a; try { InputStreamReader fis = new InputStreamReader(inputStream, \ while ((c = fis.read()) != -1) { readBuffer.append((char) c); } scannedInput = readBuffer.toString().trim(); currentTime = new Date();

TimeStamp = formatter.format(currentTime);

} catch (IOException ex) { ex.printStackTrace(); } catch (Exception ex)

}

}

{ }

ex.printStackTrace();

public void writeComm(String outString) { synchronized (readWriteLock) { try { outputStream.write(outString.getBytes()); } catch (IOException ex) { }

}

}

public static void main(String[] args) { SerialComm serialcomm = new SerialComm(); }

try { serialcomm.init(\下测试端口 // serialcomm.init(\下测试端口 serialcomm.start(); } catch (Exception ex) { }

windows中java实现的串口通信

通过修改sample例程,使用observer模式实现串口通信数据的订阅读取. 以下为俺的原创程序:

实现功能如下:

1. 在windows中监听指定的串口

2. observer模式订阅端口数据,可以有多个数据监听者同时接收数据 先到sun网站上下载串口通信库

http://java.sun.com/products/javacomm/index.jsp 再下载windows中的dll库 http://www.rxtx.org/ java实现源程序如下

------------------ 1 --------------------- package serial;

import gnu.io.SerialPort; import java.util.HashMap; public class CommTest {

/** * windows中串口通信程序需要rxtxSerial.dll的支持,放到D:\\jdk1.5\\bin目录下即可 */

public static void main(String[] args) {

HashMap params = new HashMap(); params.put(SerialReader.PARAMS_PORT, \端口名称 params.put(SerialReader.PARAMS_RATE, 9600); // 波特率

params.put(SerialReader.PARAMS_TIMEOUT, 1000); // 设备超时时间 1秒 params.put(SerialReader.PARAMS_DELAY, 200); // 端口数据准备时间 1秒

params.put(SerialReader.PARAMS_DATABITS, SerialPort.DATABITS_8); // 数据位 params.put(SerialReader.PARAMS_STOPBITS, SerialPort.STOPBITS_1); // 停止位 params.put(SerialReader.PARAMS_PARITY, SerialPort.PARITY_NONE); // 无奇偶校验 SerialReader sr = new SerialReader(params);

CommDataObserver bob = new CommDataObserver(\ CommDataObserver joe = new CommDataObserver(\ sr.addObserver(joe); sr.addObserver(bob); } }

---------------- 2 ----------------- package serial;

import gnu.io.CommPort;

import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort;

import gnu.io.SerialPortEvent;

import gnu.io.SerialPortEventListener;

import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Observable;

import java.util.TooManyListenersException;

/**

* 串口数据读取类,用于windows的串口数据读取 * *

* @author Macro Lu * @version 2007-4-4 */

public class SerialReader extends Observable SerialPortEventListener {

static CommPortIdentifier portId; int delayRead = 200;

int numBytes; // buffer中的实际数据字节数

private static byte[] readBuffer = new byte[4096]; // 4k的buffer空间,缓存串口读入的数据

static Enumeration portList; InputStream inputStream; SerialPort serialPort;

implements Runnable,

HashMap serialParams;

// 端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完

public static final String PARAMS_DELAY = \延时等待端口数据准备的时间

public static final String PARAMS_TIMEOUT = \超时时间 public static final String PARAMS_PORT = \端口名称 public static final String PARAMS_DATABITS = \数据位 public static final String PARAMS_STOPBITS = \停止位 public static final String PARAMS_PARITY = \奇偶校验 public static final String PARAMS_RATE = \波特率 /**

* 初始化端口操作的参数. * *

* @see */

public SerialReader(HashMap params) { serialParams = params; init(); }

private void init() { try {

// 参数初始化

int timeout = Integer.parseInt(serialParams.get(PARAMS_TIMEOUT).toString()); int rate = Integer.parseInt(serialParams.get(PARAMS_RATE).toString());

int dataBits = Integer.parseInt(serialParams.get(PARAMS_DATABITS).toString()); int stopBits = Integer.parseInt(serialParams.get(PARAMS_STOPBITS).toString()); int parity = Integer.parseInt(serialParams.get(PARAMS_PARITY).toString()); delayRead = Integer.parseInt(serialParams.get(PARAMS_DELAY).toString()); String port = serialParams.get(PARAMS_PORT).toString();

// 打开端口

portId = CommPortIdentifier.getPortIdentifier(port);

serialPort = (SerialPort) portId.open(\ inputStream = serialPort.getInputStream();

serialPort.addEventListener(this);

serialPort.notifyOnDataAvailable(true);

serialPort.setSerialPortParams(rate, dataBits, stopBits, parity); } catch (PortInUseException e) {

System.out.println(\端口已经被占用!\ e.printStackTrace();

} catch (TooManyListenersException e) { System.out.println(\端口监听者过多!\ e.printStackTrace();

} catch (UnsupportedCommOperationException e) { System.out.println(\端口操作命令不支持!\ e.printStackTrace();

} catch (NoSuchPortException e) { System.out.println(\端口不存在!\ e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }

Thread readThread = new Thread(this); readThread.start(); }

/**

* Method declaration * *

* @see */

public void run() { try {

Thread.sleep(100);

} catch (InterruptedException e) { } }

/**

* Method declaration * *

* @param event *

* @see */

public void serialEvent(SerialPortEvent event) {

try {

// 等待1秒钟让串口把数据全部接收后在处理 Thread.sleep(delayRead);

System.out.print(\ } catch (InterruptedException e) { e.printStackTrace(); }

switch (event.getEventType()) {

case SerialPortEvent.BI: // 10 case SerialPortEvent.OE: // 7 case SerialPortEvent.FE: // 9 case SerialPortEvent.PE: // 8 case SerialPortEvent.CD: // 6 case SerialPortEvent.CTS: // 3 case SerialPortEvent.DSR: // 4 case SerialPortEvent.RI: // 5

case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 break;

case SerialPortEvent.DATA_AVAILABLE: // 1 try {

// 多次读取,将所有数据读入

// while (inputStream.available() > 0) { // numBytes = inputStream.read(readBuffer); // }

numBytes = inputStream.read(readBuffer); changeMessage(readBuffer, numBytes); } catch (IOException e) { e.printStackTrace(); }

break; } }

// 通过observer pattern将收到的数据发送给observer // 将buffer中的空字节删除后再发送更新消息,通知观察者 public void changeMessage(byte[] message, int length) { setChanged();

byte[] temp = new byte[length];

System.arraycopy(message, 0, temp, 0, length);

// System.out.println(\ notifyObservers(temp); }

static void listPorts() {

Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); while (portEnum.hasMoreElements()) { CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum.nextElement();

System.out.println(portIdentifier.getName() + \ + getPortTypeName(portIdentifier.getPortType())); } }

static String getPortTypeName(int portType) { switch (portType) {

case CommPortIdentifier.PORT_I2C: return \

case CommPortIdentifier.PORT_PARALLEL: return \

case CommPortIdentifier.PORT_RAW: return \

case CommPortIdentifier.PORT_RS485: return \

case CommPortIdentifier.PORT_SERIAL: return \ default:

return \ } }

/**

* @return A HashSet containing the CommPortIdentifier for all serial ports that are not

* currently being used. */

public static HashSet getAvailableSerialPorts() { HashSet h = new HashSet(); Enumeration thePorts = CommPortIdentifier.getPortIdentifiers(); while (thePorts.hasMoreElements()) {

CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement(); switch (com.getPortType()) {

case CommPortIdentifier.PORT_SERIAL: try {

CommPort thePort = com.open(\ thePort.close(); h.add(com);

} catch (PortInUseException e) {

System.out.println(\ } catch (Exception e) {

System.out.println(\ } } }

return h; } }

---------- 3 ----------------- package serial;

import java.util.Observable; import java.util.Observer;

class CommDataObserver implements Observer { String name;

public CommDataObserver(String name) { this.name = name; }

public void update(Observable o, Object arg) {

System.out.println(\+ \ } }

Java串口通信-01

找啊找,找到了comm3.0,结果发现没有Windows版。

再找comm2.0,有Windows版滴,不过是98年的老古董了,不过俺是实用主义者。。。 安装好后,运行测试程序,汗,A发A的,B根本收不到,为啥嗷!!?? 找。。。找。。。找。。。 难道是线不对?

两台PC用串口线互连,要交叉彼此的收信针和发信针。

嗯,有这可能,用网线互联的时候不就一个要a头,一个要b头滴么。

找找看。。。

Java串口通信-2

发现果然是串口线的问题啊。。。

哎,用两台pc来调试程序麻烦,用虚拟串口吧。 下载了VSPM,虚拟出4个串口。

COM3和COM4运行在server模式,COM5和COM6运行在client模式。 嗯,用COM3和COM5来通信。 测试代码如下:

//SwitchBoard.java . 模拟了一个电话交换机,呵呵 package simulateCTI;

import java.awt.FlowLayout;

import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration;

import java.util.TooManyListenersException;

import javax.comm.CommPortIdentifier; import javax.comm.PortInUseException; import javax.comm.SerialPort;

import javax.comm.SerialPortEvent;

import javax.comm.SerialPortEventListener;

import javax.comm.UnsupportedCommOperationException; import javax.swing.JButton; import javax.swing.JFrame;

import javax.swing.JOptionPane; import javax.swing.JRadioButton;

public class SwitchBoard extends JFrame implements Runnable, ActionListener, SerialPortEventListener {

static final String PORT_TO_USE = \

char ACK = (byte) 0x06;

char STX = (byte) 0x02;

char ETX = (byte) 0x03;

String MSG1 = STX + \

boolean endKeepCallFlag = false;

static CommPortIdentifier PortId;// used to check the port.

static Enumeration portList;// list all the availble ports.

SerialPort serialPort;

OutputStream outputStream = null;

InputStream inputStream = null;

String Msg;

// GUI

JButton simulateOneCall = new JButton(\ JRadioButton ACKed = new JRadioButton(\

SwitchBoard() { // Set GUI

super(\ this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setSize(300, 300); this.setVisible(true);

this.setLayout(new FlowLayout()); this.add(simulateOneCall); this.add(ACKed); this.pack();

simulateOneCall.addActionListener(this);

// Build serial port connection. openSerialPort(); }

public void run() {

// TODO Auto-generated method stub while (true) { try {

Thread.sleep(500);

// readTheBuffer();

} catch (InterruptedException e) {

// TODO Auto-generated catch block e.printStackTrace(); } } }

public void openSerialPort() {

portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) {

PortId = (CommPortIdentifier) portList.nextElement();

if (PortId.getPortType() == CommPortIdentifier.PORT_SERIAL) { if (PortId.getName().equals(PORT_TO_USE)) { try {

serialPort = (SerialPort) PortId.open(

\ try {

serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

} catch (UnsupportedCommOperationException e) { e.printStackTrace(); }

} catch (PortInUseException e) { e.printStackTrace();

System.out.println(\ } } } }

// open the io channel of the serial port. try {

outputStream = serialPort.getOutputStream(); inputStream = serialPort.getInputStream(); } catch (IOException e) {

// TODO Auto-generated catch block e.printStackTrace(); }

// to listen the serial port. try {

serialPort.addEventListener(this); } catch (TooManyListenersException tle) {

tle.printStackTrace(); }

serialPort.notifyOnDataAvailable(true); }

public void sendToComputer() { try {

// outputStream = serialPort.getOutputStream(); // Msg = simulate_Msg_inputBox.getText(); Msg = MSG1;

outputStream.write(Msg.getBytes()); outputStream.flush();

ACKed.setSelected(false); } catch (IOException e) {

// TODO Auto-generated catch block e.printStackTrace(); } }

public void close() { try {

outputStream.close(); serialPort.close(); System.exit(0); } catch (Exception e) { e.printStackTrace(); } }

public static void main(String args[]) { new SwitchBoard(); }

public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub if (e.getSource() == simulateOneCall) { sendToComputer(); } }

public void parseInMsg(String message){

if(message.trim().length() == 0){//it is ACK }

if(message.trim().length() == 23||message.trim().length() == 3){//package of one call.

JOptionPane.showMessageDialog(this,\ } }

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[50];

try {

while (inputStream.available() > 0) {

int numBytes = inputStream.read(readBuffer); if(numBytes == 1){//is ACK ACKed.setSelected(true); } }

String receivedMsg = new String(readBuffer);

System.out.println(\

//JOptionPane.showMessageDialog(this,\ parseInMsg(receivedMsg); } catch (IOException e) {} break; } } }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Computer.java, 就是和交换机通信的PC了萨。 package simulateCTI;

import java.awt.GridLayout;

import java.awt.event.ActionEvent; import java.awt.event.ActionListener;

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration;

import java.util.TooManyListenersException;

import javax.comm.CommPortIdentifier; import javax.comm.PortInUseException; import javax.comm.SerialPort;

import javax.comm.SerialPortEvent;

import javax.comm.SerialPortEventListener;

import javax.comm.UnsupportedCommOperationException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel;

import javax.swing.JOptionPane; import javax.swing.JTextArea;

public class Computer extends JFrame implements Runnable, ActionListener, SerialPortEventListener {

static final String PORT_TO_USE = \

char ACK = (byte) 0x06;

char STX = (byte) 0x02;

char ETX = (byte) 0x03;

String callOutStr = STX + \ String readMemStr = STX + \

boolean flag = false;

static CommPortIdentifier PortId;// used to check the port.

static Enumeration portList;// list all the availble ports.

SerialPort serialPort;

InputStream inputStream = null;

OutputStream outputStream = null;

String inMsg;

Thread listener;

// GUI

// JButton startListen = new JButton(\//

// JTextArea showSomething = new JTextArea(); //

// JButton endListen = new JButton(\

JLabel callTimeLb = new JLabel(\

JLabel phoneNumLb = new JLabel(\

JButton callFromComputerBtn = new JButton(\

JButton readMemoryOfArohaBtn = new JButton(\

Computer() { // set GUI

super(\

this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setLayout(new GridLayout(4, 1)); this.add(callTimeLb); this.add(phoneNumLb);

this.add(callFromComputerBtn); this.add(readMemoryOfArohaBtn);

this.setVisible(true); this.setSize(300, 500); pack();

callFromComputerBtn.addActionListener(this); readMemoryOfArohaBtn.addActionListener(this); // Build serial port connection. openSerialPort(); }

public void run() { while (true) { try {

Thread.sleep(500);// the CTI equipment will send ack in 100ms. if (flag) { return; }

} catch (InterruptedException e) {

// TODO Auto-generated catch block e.printStackTrace(); } }

}

public void close() { try {

inputStream.close(); outputStream.close(); serialPort.close(); } catch (IOException e) { e.printStackTrace(); } }

public void actionPerformed(ActionEvent e) { if (e.getSource() == callFromComputerBtn) { try {

outputStream.write(callOutStr.getBytes()); } catch (IOException e1) {

// TODO Auto-generated catch block e1.printStackTrace(); } }

if (e.getSource() == readMemoryOfArohaBtn) { try {

outputStream.write(readMemStr.getBytes()); } catch (IOException e1) {

// TODO Auto-generated catch block e1.printStackTrace(); } } }

public void openSerialPort() {

portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) {

PortId = (CommPortIdentifier) portList.nextElement();

if (PortId.getPortType() == CommPortIdentifier.PORT_SERIAL) { if (PortId.getName().equals(PORT_TO_USE)) { try {

serialPort = (SerialPort) PortId.open(

\ try {

serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

} catch (UnsupportedCommOperationException e) { e.printStackTrace(); }

} catch (PortInUseException e) { e.printStackTrace();

System.out.println(\ } } } }

// open the io channel of the serial port. try {

outputStream = serialPort.getOutputStream(); inputStream = serialPort.getInputStream(); } catch (IOException e) {

// TODO Auto-generated catch block e.printStackTrace(); }

// to listen the serial port. try {

serialPort.addEventListener(this); } catch (TooManyListenersException tle) { tle.printStackTrace(); }

serialPort.notifyOnDataAvailable(true); }

public static void main(String args[]) { new Computer(); }

public void parseInMsg(String message){

if(message.trim().length() == 0){//it is ACK }

if(message.trim().length() == 29){//package of one call.

JOptionPane.showMessageDialog(this,\ callTimeLb.setText(\

phoneNumLb.setText(\ } }

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[31];//max length is 31 bytes.

try {

while (inputStream.available() > 0) {

int numBytes = inputStream.read(readBuffer); }

inMsg = new String(readBuffer);

System.out.print(\ parseInMsg(inMsg.trim()); // send ACK to Aroha.

outputStream.write((byte) 0x06); } catch (IOException e) { }

break; } } }

笔记本电脑没有com端口

如果不是从串口读数据的话,可以用虚拟串口软件,如VSPM等等,下载地址 http://www.powerip.net/product_VSPM.htm

将TCP/IP、UDP网络协议映射成本机的虚拟COM口,用于串口服务器、GPRS/CDMA、EIO联网等产品的虚拟串口映射。也可以用于调试各类串口软件,集成Telnet管理器,全面支持Windows98/2000/XP/2003/VISTA/2008。

如果要用真是的串口,可以考虑用USB转串口的转接卡,把一个USB转换成串口,那东西也不贵,也就几十块钱,不超过50,大概二三十吧。

如何把com3接口改为com1接口?com1,com3在结构上和用途上有差别吗?

不可能,

COM3是PCI接口,

COM1\\2是串口,接口不同,怎么更改……

COM1接口

COM1与COM2接口也称串口,它是一个9针RS-232接口。它的数据的传输方式是采用串行传输,串口的最大传输速率为14.3KB/秒,通常用于传输速率较低的设备,如鼠标、外置MODEM、老式的数码相机、手写板。有些老主板上提供两个串口(9针、25针),而新主板一般是提供两个9针的串口。

COM2接口

COM2接口的功能与COM1接口一样。不过在有些586主板上虽然也提供两个串口,但是COM1接口一般是接鼠标,COM2接口一般是接外置Modem或其他串口设备。

com3以及往后的com4等就是PCI插槽了。

PCI(Peripheral Component Interconnect)插槽的功能就不用解释了吧……

16位CRC检验原理及实现一、原理

1、循环校验码(CRC码):是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。

2、生成CRC码的基本原理:任意一个由二进制位串组成的代码都可以和一个系数仅为?0?和?1?取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。 3、CRC码集选择的原则:若设码字长度为N,信息字段为K位,校验字段为R位(N=K+R),则对于CRC码集中的任一码字,存在且仅存在一个R次多项式g(x),使得

V(x)=A(x)g(x)=xRm(x)+r(x);

其中: m(x)为K次信息多项式, r(x)为R-1次校验多项式,

g(x)称为生成多项式:

g(x)=g0+g1x+ g2x2+...+g(R-1)x(R-1)+g(R)xR

发送方通过指定的g(x)产生CRC码字,接收方则通过该g(x)来验证收到的CRC码字。

4、CRC校验码软件生成方法:

借助于多项式除法,其余数为校验字段。

例如:信息字段代码为: 1011001;对应m(x)=x6+x4+x3+1

假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代码为: 11001

x4m(x)=x10+x8+x7+x4 对应的代码记为:10110010000;

采用多项式除法: 得余数为: 1010 (即校验字段为:1010)

发送方:发出的传输字段为: 1 0 1 1 0 0 1 1 0 10

信息字段 校验字段

接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除法),如果能够除尽,则正确。

二、算法

标准CRC生成多项式如下表:

名称 生成多项式 简记式* 标准引用

CRC-4 x4+x+1 3 ITU G.704

CRC-8 x8+x5+x4+1 0x31

CRC-8 x8+x2+x1+1 0x07

CRC-8 x8+x6+x4+x3+x2+x1 0x5E

CRC-12 x12+x11+x3+x+1 80F

CRC-16 x16+x15+x2+1 8005 IBM SDLC

CRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS

CRC-32 x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS

CRC-32c x32+x28+x27+...+x8+x6+1 1EDC6F41 SCTP

生成多项式的最高位固定的1,故在简记式中忽略最高位1了,如0x1021实际是0x11021。

本文档是基于CRC16-CCITT的。

I、基本算法(人工笔算):

以CRC16-CCITT为例进行说明,CRC校验码为16位,生成多项式17位。假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];

数据流左移16位,相当于扩大256×256倍,再除以生成多项式0x11021,做不借位的除法运算(相当于按位异或),所得的余数就是CRC校验码。

发送时的数据流为6字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0]、CRC[1]、CRC[0];

II、计算机算法1(比特型算法):

1)将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存

器;

2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;

否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);

3)重复第2步,直到数据流(6字节)全部移入寄存器;

4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。

实现程序:

#include

unsigned short crc16(unsigned char *ptr, char len);

int main() {

unsigned short crc;

unsigned char crcbuf[]={0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3};

unsigned char *ptr=crcbuf;

crc=crc16(ptr,8);

printf(\ }

unsigned short crc16(unsigned char *ptr, char len) {

char len_flag,i;

unsigned short crc=*ptr;

unsigned char ch;

if(len>1)

crc=(crc<<8)|(*(ptr+1));

else

crc=(crc<<8);

for(len_flag=0;len_flag

{

ch=*(ptr+2);

for(i=0;i<8;i++)

{

if((crc&0x8000)!=0)

{

crc<<=1;

if((len>2)&&(len_flag<(len-2)))

{

crc|=((ch&0x80)>>7);

ch=*(ptr+2)<<(i+1);

}

crc^=0x1021;

}

else

{

crc<<=1;

if((len>2)&&(len_flag<(len-2)))

{

crc|=((ch&0x80)>>7);

ch=*(ptr+2)<<(i+1);

}

}

}

ptr++;

}

return crc; }

III、计算机算法2(字节型算法):256^n表示256的n次方

把按字节排列的数据流表示成数学多项式,设数据流为BYTE[n]BYTE[n-1]BYTE[n-2]、、、BYTE[1]BYTE[0],表示成数学表达式为BYTE[n]×256^n+BYTE[n-1]×256^(n-1)

+...+BYTE[1]*256+BYTE[0],在这里+表示为异或运算。设生成多项式为G17(17bit),CRC码为CRC16。

则,CRC16=

(BYTE[n]×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]×256+BYTE[0])×256^2/G17,即数据流左移16位,再除以生成多项式G17。

先变换BYTE[n-1]、BYTE[n-1]扩大后的形式,

CRC16=BYTE[n]×256^n×256^2/G17+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

(Z[n]+Y[n]/G17)×256^n+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z[n]×256^n+{Y[n]×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z[n]×256^n+{(YH8[n]×256+YHL[n])×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z[n]×256^n+{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

这样就推导出,BYTE[n-1]字节的CRC校验码为{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17},即上一字节CRC校验码Y[n]的高8位(YH8[n])与本字节BYTE[n-1]异或,

该结果单独计算CRC校验码(即单字节的16位CRC校验码,对单字节可建立表格,预先生成对应的16位CRC校验码),所得的CRC校验码与上一字节CRC校验码Y[n]的低8位(YL8[n])

乘以256(即左移8位)异或。然后依次逐个字节求出CRC,直到BYTE[0]。

字节型算法的一般描述为:本字节的CRC码,等于上一字节CRC码的低8位左移8位,与上一字节CRC右移8位同本字节异或后所得的CRC码异或。

字节型算法如下:

1)CRC寄存器组初始化为全\。(注意:CRC寄存器组初始化全为1时,最后CRC应取反。)

2)CRC寄存器组向左移8位,并保存到CRC寄存器组。

3)原CRC寄存器组高8位(右移8位)与数据字节进行异或运算,得出一个指向值表的索引。

4)索引所指的表值与CRC寄存器组做异或运算。

5)数据指针加1,如果数据没有全部处理完,则重复步骤2)。

6)得出CRC。

实现程序:

include

unsigned short GetCrc_16(unsigned char * pData, int nLength);

void mK_cRctable();

unsigned short cRctable_16[256];

int main() {

unsigned short crc;

unsigned char crcbuf[]={0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3};

unsigned char *ptr=crcbuf;

mK_cRctable();

crc=GetCrc_16(ptr,8);

printf(\ }

unsigned short GetCrc_16(unsigned char * pData, int nLength)

//函数功能:计算数据流* pData的位CRC校验码,数据流长度为nLength

{

unsigned short cRc_16 = 0x0000; // 初始化

while(nLength>0)

{

cRc_16 = (cRc_16 << 8) ^ cRctable_16[((cRc_16>>8) ^ *pData) & 0xff]; //cRctable_16表由函数mK_cRctable生成

nLength--;

pData++;

}

return cRc_16; }

void mK_cRctable() {

unsigned short cRc_16=0;

unsigned short i,j,k;

for(i=0,k=0;i<256;i++,k++) {

cRc_16 = i<<8;

for(j=8;j>0;j--)

{

if(cRc_16&0x8000)

cRc_16=(cRc_16<<=1)^0x1021;

else

cRc_16<<=1;

}

cRctable_16[k] = cRc_16; } }

IV、由硬件实现所得

CRC校验可以在软件或者硬件上实现。由硬件实现时,CRC 通常为串行生成(即一位一位的生成),其串行生成器通常由XOR逻辑门组成,而XOR门的数量与位置由某一选定的多项式决定。具体的说,针对有n+1项的多项式,CRC实现电路包括如下部件:

1. 一个长度为n位的移位寄存器(n=多项式长度-1,即CRC码的长度)

2. 该实现电路可包含最多n+1个异或门(XOR)

3. 在(选定的)多项式里面出现的项,在电路里相应位置即有一个异或门。

(图片不能贴,可 google搜索,到处都是……如:

http://203.208.37.132/search?q=cache:WgDl4h_QRdoJ:book.51cto.com/art/200907/138086.htm+crc???éa????????????°&cd=7&hl=zh-CN&ct=clnk&gl=cn&st_usg=ALhdy29YWwk0Q4or5tNcRv2axbvBCwBIuA中的图3-6)

有图可见,当移出的数据与要校验的数据位相异或数值为一时,第一个异或门打开,与生成项异或,所以可以这样理解,与数据位做XOR 运算的是上次CRC值的Bit15。可写程序为:

#include

unsigned short crc16(unsigned char *ptr,unsigned char len);

int main() {

unsigned short crc;

unsigned char crcbuf[]={0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3};

unsigned char *ptr=crcbuf;

crc=crc16(ptr,8);

printf(\ }

unsigned short crc16(unsigned char *ptr,unsigned char len) {

unsigned short crc=0;

unsigned char i;

while(len--)

{

for(i=0x80;i!=0;i>>=1)

{

if(((crc&0x8000)!=0)^((*ptr&i)!=0))

{

crc=(crc<<1)^0x1021;

}

else

crc<<=1;

}

ptr++;

}

return crc; }

本文来源:https://www.bwwdw.com/article/kcko.html

Top