1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Java使用RXTX进行串口SerialPort通讯

Java使用RXTX进行串口SerialPort通讯

时间:2019-08-27 20:12:13

相关推荐

Java使用RXTX进行串口SerialPort通讯

RXTX简介 (/p/cb61f797ffc1

RXTX是一个提供串口和并口通信的开源java类库,由该项目发布的文件均遵循LGPL协议。

RXTX项目提供了Windows,Linux,Mac os X,Solaris操作系统下的兼容m串口通讯包API的实现,为其他开发人员在此类系统下开发串口应用提供了相当的方便。

RXTX的使用上与sun提供的comm.jar基本相同,编程时最明显的不同是要包含的包名由m.改成了gnu.io.

RxtxAPI 的核心是抽象的CommPort类(用于描述一个被底层系统支持的端口的抽象类,它包含一些高层的IO控制方法,这些方法对于所有不同的通讯端口来说是通用的)及其两个子类:SerialPort类和ParallePort类。其中,SerialPort类是用于串口通信的类,ParallePort类是用于并行口通信的类。CommPort类还提供了常规的通信模式和方法,例如:getInputStream( )方法和getOutputStream( )方法,专用于与端口上的设备进行通信。

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

接口CommDriver可负载设备(the loadable device)驱动程序接口的一部分CommPortOwnershipListener传递各种通讯端口的所有权事件ParallelPortEventListener传递并行端口事件SerialPortEventListener传递串行端口事件类CommPort通讯端口CommPortIdentifier通讯端口管理ParallelPort并行通讯端口ParallelPortEvent并行端口事件SerialPortRS-232串行通讯端口SerialPortEvent 串行端口事件异常类NoSuchPortException当驱动程序不能找到指定端口时抛出PortInUseException当碰到指定端口正在使用中时抛出UnsupportedCommOperationException驱动程序不允许指定操作时抛出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) 打开端口,两个参数:程序名称,延迟时间(毫秒数)SerialPort类这个类用于描述一个RS-232串行通信端口的底层接口,它定义了串口通信所需的最小功能集。通过它,用户可以直接对串口进行读、写及设置工作。SerialPort类中关于串口参数的静态成员变量说明:DATABITS_5 数据位为5DATABITS_6 数据位为6DATABITS_7 数据位为7DATABITS_8 数据位为8PARITY_NONE 空格检验PARITY_ODD 奇检验PARITY_EVEN 偶检验PARITY_MARK 标记检验PARITY_SPACE 无检验STOPBITS_1 停止位为1STOPBITS_2 停止位为2STOPBITS_1_5 停止位为1.5SerialPort类中关于串口参数的方法说明:getBaudRate()得到波特率getParity()得到检验类型getDataBits()得到数据位数getStopBits()得到停止位数setSerialPortParams(int,int, int, int) 设置串口参数依次为(波特率,数据位,停止位,奇偶检验)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 输出缓冲区已清空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位SerialPort中的其他常用方法说明:close()关闭串口getOutputStream()得到OutputStream类型的输出流getInputStream()得到InputStream类型的输入流

准备工作

RXTX包:rxtx-2.2pre2-bins.zip串口虚拟工具:vspd.exe串口调试工具:amcktszs_v2.4.0.0.exe

安装RXTX包

解压rxtx-2.2pre2-bins.zip,将RXTXcomm.jar加入项目依赖库里,对应操作的系统的rxtxSerial.dll和rxtxParallel.dll文件放入jdk的bin目录下

前提条件:maven已经加入环境变量中mvn install:install-file -DgroupId=gnu.io -DartifactId=RXTXcomm -Dversion=1.0 -Dpackaging=jar -Dfile=E:\Work\Yotrio\libs\RXTXcomm.jar

工具创建一对虚拟串口

Image.png

打开串口调试工具,配置串口参数

Image [2].png

样例Demo

封装串口读写工具类

/*** 模块名称:projects-parent mon* 功能说明:串口服务类,提供打开、关闭串口,读取、发送串口数据等服务(采用单例设计模式)* <br>* 开发人员:Wangyq* 创建时间: -09-20 10:05* 系统版本:1.0.0**/public class SerialPortUtil {private static SerialPortUtil serialPortUtil = null;static {//在该类被ClassLoader加载时就初始化一个SerialTool对象if (serialPortUtil == null) {serialPortUtil = new SerialPortUtil();}}//私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象private SerialPortUtil() {}/*** 获取提供服务的SerialTool对象** @return serialPortUtil*/public static SerialPortUtil getSerialPortUtil() {if (serialPortUtil == null) {serialPortUtil = new SerialPortUtil();}return serialPortUtil;}/*** 查找所有可用端口** @return 可用端口名称列表*/public static final ArrayList<String> findPort() {//获得当前所有可用串口Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();ArrayList<String> portNameList = new ArrayList<>();//将可用串口名添加到List并返回该Listwhile (portList.hasMoreElements()) {String portName = portList.nextElement().getName();portNameList.add(portName);}return portNameList;}/*** 打开串口** @param portName 端口名称* @param baudrate 波特率* @param databits 数据位* @param parity 校验位(奇偶位)* @param stopbits 停止位* @return 串口对象* @throws SerialPortParameterFailure 设置串口参数失败* @throws NotASerialPort 端口指向设备不是串口类型* @throws NoSuchPort 没有该端口对应的串口设备* @throws PortInUse 端口已被占用*/public static final SerialPort openPort(String portName, int baudrate, int databits, int parity, int stopbits) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse {try {//通过端口名识别端口CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);//打开端口,并给端口名字和一个timeout(打开操作的超时时间)CommPort commPort = portIdentifier.open(portName, 2000);//判断是不是串口if (commPort instanceof SerialPort) {SerialPort serialPort = (SerialPort) commPort;try {//设置一下串口的波特率等参数serialPort.setSerialPortParams(baudrate, databits, stopbits, parity);} catch (UnsupportedCommOperationException e) {throw new SerialPortParameterFailure();}//System.out.println("Open " + portName + " sucessfully !");return serialPort;} else {//不是串口throw new NotASerialPort();}} catch (NoSuchPortException e1) {throw new NoSuchPort();} catch (PortInUseException e2) {throw new PortInUse();}}/*** 关闭串口** @param serialPort 待关闭的串口对象*/public static void closePort(SerialPort serialPort) {if (serialPort != null) {serialPort.close();serialPort = null;}}/*** 往串口发送数据** @param serialPort 串口对象* @param order待发送数据* @throws SendDataToSerialPortFailure 向串口发送数据失败* @throws SerialPortOutputStreamCloseFailure 关闭串口对象的输出流出错*/public static void sendToPort(SerialPort serialPort, byte[] order) throws SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure {OutputStream out = null;try {out = serialPort.getOutputStream();out.write(order);out.flush();} catch (IOException e) {throw new SendDataToSerialPortFailure();} finally {try {if (out != null) {out.close();out = null;}} catch (IOException e) {throw new SerialPortOutputStreamCloseFailure();}}}/*** 从串口读取数据** @param serialPort 当前已建立连接的SerialPort对象* @return 读取到的数据* @throws ReadDataFromSerialPortFailure从串口读取数据时出错* @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错*/public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure {InputStream in = null;byte[] bytes = null;try {in = serialPort.getInputStream();int bufflenth = in.available(); //获取buffer里的数据长度while (bufflenth != 0) {bytes = new byte[bufflenth]; //初始化byte数组为buffer中数据的长度in.read(bytes);bufflenth = in.available();}} catch (IOException e) {throw new ReadDataFromSerialPortFailure();} finally {try {if (in != null) {in.close();in = null;}} catch (IOException e) {throw new SerialPortInputStreamCloseFailure();}}return bytes;}/*** 添加监听器** @param port串口对象* @param listener 串口监听器* @throws TooManyListeners 监听类对象过多*/public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners {try {//给串口添加监听器port.addEventListener(listener);//设置当有数据到达时唤醒监听接收线程port.notifyOnDataAvailable(true);//设置当通信中断时唤醒中断线程port.notifyOnBreakInterrupt(true);} catch (TooManyListenersException e) {throw new TooManyListeners();}}/*** 删除监听器** @param port串口对象* @param listener 串口监听器* @throws TooManyListeners 监听类对象过多*/public static void removeListener(SerialPort port, SerialPortEventListener listener) {//删除串口监听器port.removeEventListener();}}

整合websocket获取并推送给前台页面实时显示

@ServerEndpoint(value = "/websocket") //接受websocket请求路径@Componentpublic class PoundWebSocket {private Logger logger = LoggerFactory.getLogger(this.getClass());/*** 保存所有在线socket连接*/private static Map<String, PoundWebSocket> webSocketMap = new LinkedHashMap<>();/*** 记录当前在线数目*/private static int count = 0;/*** 当前连接(每个websocket连入都会创建一个MyWebSocket实例*/private Session session;/*** 创建监听串口*/private static SerialPort serialPort = null;/*** 创建监听器*/private static SerialPortEventListener serialPortEventListener = null;/*** 监听串口*/private static String PORT_NAME;/*** 监听串口波特率*/private static int BAUD_RATE;/*** 数据位*/private static int DATA_BITS;/*** 停止位*/private static int STOP_BITS;/*** 奇偶位*/private static int PARITY;/*** 地磅型号*/private static String MODEL;private static IPoundInfoService poundInfoService;private static ApplicationContext applicationContext;public static void setApplicationContext(ApplicationContext applicationContext) {PoundWebSocket.applicationContext = applicationContext;}private static StringBuffer stringBuffer = new StringBuffer();/*** 处理连接建立** @param session*/@OnOpenpublic void onOpen(Session session) {if (poundInfoService == null) {poundInfoService = applicationContext.getBean(IPoundInfoService.class);}//获取地磅信息PoundInfo poundInfo = poundInfoService.findOne();PORT_NAME = poundInfo.getSerialPort();BAUD_RATE = poundInfo.getBaudRate();MODEL = poundInfo.getModel();DATA_BITS = poundInfo.getDataBits() != null ? poundInfo.getDataBits() : SerialPort.DATABITS_8;STOP_BITS = poundInfo.getStopBits() != null ? poundInfo.getStopBits() : SerialPort.STOPBITS_1;PARITY = poundInfo.getParity() != null ? poundInfo.getParity() : SerialPort.PARITY_NONE;this.session = session;webSocketMap.put(session.getId(), this);addCount();// logger.info("新的连接加入:{}", session.getId());try {//确保串口已被关闭,未关闭会导致重新监听串口失败if (serialPort != null) {SerialPortUtil.closePort(serialPort);serialPort = null;}//创建串口 COM5位串口名称 9600波特率if (serialPort == null && StringUtils.isNotEmpty(PORT_NAME) && StringUtils.isNotEmpty(MODEL)) {serialPort = SerialPortUtil.openPort(PORT_NAME, BAUD_RATE, DATA_BITS, PARITY, STOP_BITS);//logger.info("创建串口:{}", serialPort);//设置串口监听SerialPortUtil.addListener(serialPort, new SerialPortEventListener() {@Overridepublic void serialEvent(SerialPortEvent serialPortEvent) {if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {try {//读取串口数据byte[] bytes = SerialPortUtil.readFromPort(serialPort);//根据型号解析字符串switch (MODEL) {case PoundConstant.MODEL_XK_3190:parsingString1(bytes);break;case PoundConstant.MODEL_XK_3190_10:parsingString2(bytes);break;case PoundConstant.MODEL_D_:parsingString1(bytes);break;case PoundConstant.MODEL_DK_3230_D_6:parsingString3(bytes);break;case PoundConstant.MODEL_D__F:parsingString4(bytes);break;default:String value = String.valueOf(Integer.valueOf(new String(bytes, "GB2312")) - RandomUtil.randomInt(1000, 10000));sendMessageToAll(value);}// System.out.println("收到的数据:" + new String(bytes, "GB2312") + "----" + new Date());} catch (ReadDataFromSerialPortFailure readDataFromSerialPortFailure) {logger.error(readDataFromSerialPortFailure.toString());} catch (SerialPortInputStreamCloseFailure serialPortInputStreamCloseFailure) {logger.error(serialPortInputStreamCloseFailure.toString());} catch (UnsupportedEncodingException e) {logger.error(e.toString());} catch (IOException e) {logger.error(e.toString());}}}});}} catch (SerialPortParameterFailure serialPortParameterFailure) {logger.error(serialPortParameterFailure.toString());} catch (NotASerialPort notASerialPort) {logger.error(notASerialPort.toString());} catch (NoSuchPort noSuchPort) {logger.error(noSuchPort.toString());} catch (PortInUse portInUse) {logger.error(portInUse.toString());} catch (TooManyListeners tooManyListeners) {logger.error(tooManyListeners.toString());}}/*** 解析字符串 方法1** @param bytes 获取的字节码*/private void parsingString1(byte[] bytes) {StringBuffer sb = new StringBuffer();//将ASCII码转成字符串for (int i = 0; i < bytes.length; i++) {sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));}//解析字符串String[] strs = sb.toString().trim().split("\\+");int weight = 0;for (int j = 0; j < strs.length; j++) {if (strs[j].trim().length() >= 6) {weight = Integer.parseInt(strs[j].trim().substring(0, 6));//发送数据sendMessageToAll(String.valueOf(weight));break;}}}/*** 解析字符串 方法2** @param bytes 获取的字节码*/private void parsingString2(byte[] bytes) {StringBuffer sb = new StringBuffer();//将ASCII码转成字符串for (int i = 0; i < bytes.length; i++) {sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));}//解析字符串String[] strs = sb.toString().trim().split("\\+");double weight = 0;for (int j = 0; j < strs.length; j++) {if (strs[j].trim().length() >= 6) {weight = Double.parseDouble(strs[j].trim().substring(0, 6)) / 10;//发送数据sendMessageToAll(String.valueOf(weight));break;}}}/*** 解析字符串 方法3** @param bytes 获取的字节码*/private void parsingString3(byte[] bytes) {StringBuffer sb = new StringBuffer();//将ASCII码转成字符串for (int i = 0; i < bytes.length; i++) {sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));}// logger.info("sb:" + sb.toString());sb.reverse();//解析字符串String[] strs = sb.toString().trim().split("\\=");double weight = 0;for (int j = 0; j < strs.length; j++) {if (strs[j].trim().length() >= 6) {weight = Double.parseDouble(strs[j].trim());//发送数据sendMessageToAll(String.valueOf(weight));break;}}}/*** 解析字符串 方法3** @param bytes 获取的字节码*/private void parsingString4(byte[] bytes) {StringBuffer sb = new StringBuffer();//将ASCII码转成字符串for (int i = 0; i < bytes.length; i++) {sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));}// logger.info("sb:" + sb.reverse());//字符串反转sb.reverse();//解析字符串String[] strs = sb.toString().trim().split("\\=");int weight = 0;for (int j = 0; j < strs.length; j++) {if (strs[j].trim().length() >= 6) {weight = Integer.parseInt(strs[j].trim().substring(0, 6));//发送数据sendMessageToAll(String.valueOf(weight));break;}}}/*** 接受消息** @param message* @param session*/@OnMessagepublic void onMessage(String message, Session session) {logger.info("收到客户端{}消息:{}", session.getId(), message);try {this.sendMessage(message);} catch (Exception e) {logger.error(e.toString());}}/*** 处理错误** @param error* @param session*/@OnErrorpublic void onError(Throwable error, Session session) {logger.info("发生错误{},{}", session.getId(), error.getMessage());}/*** 处理连接关闭*/@OnClosepublic void onClose() {webSocketMap.remove(this.session.getId());reduceCount();logger.info("连接关闭:{}", this.session.getId());//连接关闭后关闭串口,下一次打开连接重新监听串口if (serialPort != null) {SerialPortUtil.closePort(serialPort);serialPort = null;}}/*** 群发消息** @param message*/public void sendMessageToAll(String message) {for (int i = 0; i < webSocketMap.size(); i++) {try {//logger.info("session:id=" + session.getId());this.session.getBasicRemote().sendText(message);} catch (IOException e) {logger.error(e.getMessage());}}}/*** 发送消息** @param message* @throws IOException*/public void sendMessage(String message) throws IOException {// logger.info("session:id=" + session.getId());this.session.getBasicRemote().sendText(message);}//广播消息public static void broadcast() {PoundWebSocket.webSocketMap.forEach((k, v) -> {try {v.sendMessage("这是一条测试广播");} catch (Exception e) {}});}//获取在线连接数目public static int getCount() {return count;}//操作count,使用synchronized确保线程安全public static synchronized void addCount() {PoundWebSocket.count++;}public static synchronized void reduceCount() {PoundWebSocket.count--;}}

作者:小土豆哥哥

链接:/p/cb61f797ffc1

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。