最近のコースでは、ホスト コンピューターのシリアル通信ツールを作成する必要がありました。Java ベースのグラフィカル インターフェイスを備えた簡単なシリアル通信ツールを作成しました。参考までに、そのプロセスを以下に詳しく説明します。^_^
まず、あなた。 Java シリアル ポート通信操作をサポートする追加の jar パッケージをダウンロードする必要があります。java.comm は比較的古く、64 ビット システムをサポートしていないため、ここでは Rxtx jar パッケージ (32 ビットと 64 ビットの両方をサポート) を推奨します。
公式ダウンロードアドレス: http://fizzed.com/oss/rxtx-for-java (注: ダウンロードには FQ が必要な場合があります)
FQ できない子供用靴はここからダウンロードできます:
http:// xiazai.jb51.net/201612/yuanma/javamfzrxtx(jb51.net).rar (32 ビット)
http://xiazai.jb51.net/201612/yuanma/javamfzrxtx(jb51.net).rar (64- bit)
2 つ:
解凍した jar パッケージをダウンロードし、Java ビルド パスの下に導入します:
Capture
注: 実行中のプロセス中に java.lang.UnsatisfiedLinkError エラーがスローされた場合は、rxtxParallel を解凍してくださいこのエラーは、これら 2 つのファイル rxtxSerial.dll を C:WindowsSystem32 ディレクトリにコピーすることで解決できます。
3 このタイプのメソッドでスローされる例外はすべて私独自のカスタム例外です。これを行う理由は、メイン プログラムでの対応する処理を容易にするためです。説明のために以下の例外の 1 つを投稿します。すべてのカスタマイズに注意してください) 例外はすべて SerialException パッケージに配置されています)package serialPort; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.TooManyListenersException; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; import serialException.*; /** * 串口服务类,提供打开、关闭串口,读取、发送串口数据等服务(采用单例设计模式) * @author zhong * */ public class SerialTool { private static SerialTool serialTool = null; static { //在该类被ClassLoader加载时就初始化一个SerialTool对象 if (serialTool == null) { serialTool = new SerialTool(); } } //私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象 private SerialTool() {} /** * 获取提供服务的SerialTool对象 * @return serialTool */ public static SerialTool getSerialTool() { if (serialTool == null) { serialTool = new SerialTool(); } return serialTool; } /** * 查找所有可用端口 * @return 可用端口名称列表 */ public static final ArrayList<String> findPort() { //获得当前所有可用串口 Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList = new ArrayList<>(); //将可用串口名添加到List并返回该List while (portList.hasMoreElements()) { String portName = portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /** * 打开串口 * @param portName 端口名称 * @param baudrate 波特率 * @return 串口对象 * @throws SerialPortParameterFailure 设置串口参数失败 * @throws NotASerialPort 端口指向设备不是串口类型 * @throws NoSuchPort 没有该端口对应的串口设备 * @throws PortInUse 端口已被占用 */ public static final SerialPort openPort(String portName, int baudrate) 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, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } 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(); } } }
package serialException; public class SerialPortParameterFailure extends Exception { /** * */ private static final long serialVersionUID = 1L; public SerialPortParameterFailure() {} @Override public String toString() { return "设置串口参数失败!打开串口操作未完成!"; } }
package serialException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; /** * 负责将传入的Exception中的错误信息提取出来并转换成字符串; * @author zhong * */ public class ExceptionWriter { /** * 将Exception中的错误信息封装到字符串中并返回该字符串 * @param e 包含错误的Exception * @return 错误信息字符串 */ public static String getErrorInfoFromException(Exception e) { StringWriter sw = null; PrintWriter pw = null; try { sw = new StringWriter(); pw = new PrintWriter(sw); e.printStackTrace(pw); return "\r\n" + sw.toString() + "\r\n"; } catch (Exception e2) { return "出错啦!未获取到错误信息,请检查后重试!"; } finally { try { if (pw != null) { pw.close(); } if (sw != null) { sw.close(); } } catch (IOException e1) { e1.printStackTrace(); } } } }
DataView.java コードは次のとおりです: (このクラスは、シリアル ポート データをリアルタイムで表示するために使用されます)
簡単な説明:
シリアル ポート ツールがハードウェア デバイスに正常に接続された後、ハードウェア デバイスはシリアル ポートを介してコンピューターにデータを送信し、追加します。初めてデータを受信したときに、データを解析してインターフェースを更新します。
このクラスは参考用であり、実際の使用では必要になる場合があります。データ表示インターフェースとデータ分析方法を再作成します
package serialPort; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Image; import java.awt.Label; import java.awt.Panel; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JOptionPane; import serialException.ExceptionWriter; /** * 主程序 * @author zhong * */ public class Client extends Frame{ /** * */ private static final long serialVersionUID = 1L; /** * 程序界面宽度 */ public static final int WIDTH = 800; /** * 程序界面高度 */ public static final int HEIGHT = 620; /** * 程序界面出现位置(横坐标) */ public static final int LOC_X = 200; /** * 程序界面出现位置(纵坐标) */ public static final int LOC_Y = 70; Color color = Color.WHITE; Image offScreen = null; //用于双缓冲 //设置window的icon(这里我自定义了一下Windows窗口的icon图标,因为实在觉得哪个小咖啡图标不好看 = =) Toolkit toolKit = getToolkit(); Image icon = toolKit.getImage(Client.class.getResource("computer.png")); //持有其他类 DataView dataview = new DataView(this); //主界面类(显示监控数据主面板) /** * 主方法 * @param args // */ public static void main(String[] args) { new Client().launchFrame(); } /** * 显示主界面 */ public void launchFrame() { this.setBounds(LOC_X, LOC_Y, WIDTH, HEIGHT); //设定程序在桌面出现的位置 this.setTitle("CDIO工程项目"); //设置程序标题 this.setIconImage(icon); this.setBackground(Color.white); //设置背景色 this.addWindowListener(new WindowAdapter() { //添加对窗口状态的监听 public void windowClosing(WindowEvent arg0) { //当窗口关闭时 System.exit(0); //退出程序 } }); this.addKeyListener(new KeyMonitor()); //添加键盘监听器 this.setResizable(false); //窗口大小不可更改 this.setVisible(true); //显示窗口 new Thread(new RepaintThread()).start(); //开启重画线程 } /** * 画出程序界面各组件元素 */ public void paint(Graphics g) { Color c = g.getColor(); g.setFont(new Font("微软雅黑", Font.BOLD, 40)); g.setColor(Color.black); g.drawString("欢迎使用上位机实时监控系统", 45, 190); g.setFont(new Font("微软雅黑", Font.ITALIC, 26)); g.setColor(Color.BLACK); g.drawString("Version:1.0 Powered By:ZhongLei", 280, 260); g.setFont(new Font("微软雅黑", Font.BOLD, 30)); g.setColor(color); g.drawString("————点击Enter键进入主界面————", 100, 480); //使文字 "————点击Enter键进入主界面————" 黑白闪烁 if (color == Color.WHITE) color = Color.black; else if (color == color.BLACK) color = Color.white; } /** * 双缓冲方式重画界面各元素组件 */ public void update(Graphics g) { if (offScreen == null) offScreen = this.createImage(WIDTH, HEIGHT); Graphics gOffScreen = offScreen.getGraphics(); Color c = gOffScreen.getColor(); gOffScreen.setColor(Color.white); gOffScreen.fillRect(0, 0, WIDTH, HEIGHT); //重画背景画布 this.paint(gOffScreen); //重画界面元素 gOffScreen.setColor(c); g.drawImage(offScreen, 0, 0, null); //将新画好的画布“贴”在原画布上 } /* * 内部类形式实现对键盘事件的监听 */ private class KeyMonitor extends KeyAdapter { public void keyReleased(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode == KeyEvent.VK_ENTER) { //当监听到用户敲击键盘enter键后执行下面的操作 setVisible(false); //隐去欢迎界面 dataview.setVisible(true); //显示监测界面 dataview.dataFrame(); //初始化监测界面 } } } /* * 重画线程(每隔250毫秒重画一次) */ private class RepaintThread implements Runnable { public void run() { while(true) { repaint(); try { Thread.sleep(250); } catch (InterruptedException e) { //重画线程出错抛出异常时创建一个Dialog并显示异常详细信息 String err = ExceptionWriter.getErrorInfoFromException(e); JOptionPane.showMessageDialog(null, err, "错误", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } } } } }