Java ベースのシリアル通信ツールの作成

高洛峰
リリース: 2017-01-05 14:40:46
オリジナル
2217 人が閲覧しました

最近のコースでは、ホスト コンピューターのシリアル通信ツールを作成する必要がありました。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 ベースのシリアル通信ツールの作成注: 実行中のプロセス中に 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();
 }
 }
  
  
}
ログイン後にコピー

各カスタム例外クラスの toString() メソッドを書き直して、メイン プログラムが例外

をキャッチした後に対応するエラー メッセージを出力できるようにしました。 SerialException パッケージには、受信した Exception オブジェクト内のエラー情報を特別に抽出し、それを文字列に変換して返すクラスもあります。 コードは次のとおりです。

package serialException;
 
public class SerialPortParameterFailure extends Exception {
 /**
 * 
 */
 private static final long serialVersionUID = 1L;
 
 public SerialPortParameterFailure() {}
 
 @Override
 public String toString() {
 return "设置串口参数失败!打开串口操作未完成!";
 }
  
}
ログイン後にコピー

4:

メインプログラムクラスの使用法。 Client.java には、プログラム Address (メイン メソッド) のエントリ ポイントが含まれています。その機能は、ウェルカム インターフェイスを表示し、実際のシリアル ポート データを表示するために DataView.java クラスを呼び出すことです。

Client.java コードは次のとおりです:

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();
  }
  }
 }
}
ログイン後にコピー

実行中のスクリーンショット:

注: 実際の実行プロセス中、下部の「Enter キーをクリックしてメイン インターフェイスに入ります」が点滅します (一定間隔で再描画されます)。ダブルバッファリング方式は、再描画時のインターフェースのちらつきの問題を解決するのに役立ちます (ダブルバッファリング方式を使用しない場合、古いインターフェースを毎回再描画するのと同じです)。新しいものを少しずつ描画し、ダブルバッファリングは基本的に新しいインターフェイスの画像をメモリに直接描画し、古いインターフェイスを新しいインターフェイスで一度に直接上書きします)

DataView.java コードは次のとおりです: (このクラスは、シリアル ポート データをリアルタイムで表示するために使用されます)

簡単な説明:

シリアル ポート ツールがハードウェア デバイスに正常に接続された後、ハードウェア デバイスはシリアル ポートを介してコンピューターにデータを送信し、追加します。初めてデータを受信したときに、データを解析してインターフェースを更新します。

このクラスは参考用であり、実際の使用では必要になる場合があります。データ表示インターフェースとデータ分析方法を再作成します 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);
  }
  }
 }
  
 }
  
}
ログイン後にコピー

実行中のスクリーンショット:

以上がこの記事の全内容です。皆様の学習に役立つことを願っています。 PHP 中国語 Web サイトをサポートします。

Java ベースのシリアル通信ツールの作成に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート