Java程序与RSR232串口通讯小练手

在利尔化学中出现了,要将磅秤的重量放到物流管理平台中方便管理。磅秤供应商提到的文档中有这一RSR232方式,在群里大神给出了一个网址。http://blog.163.com/chencong860@126/blog/static/557807942015123428852/

以下是原文:


一直以来都是在学习J2EE方面的应用系统开发,从未想过用JAVA来编写硬件交互程序,不过自己就是喜欢尝试一些未曾接触的新东西。在网上搜索了些资源,了解到JAVA写串口通讯的还是蛮多的,那么便着手准备开发调试环境。软件程序开发环境搭建不成问题,可这硬件环境就有点犯难啦。更何况自己用的是笔记本哪来的串口呀,再说要是真拿这串口硬件来自己也不会弄,随即想到了虚拟机,觉得这东西应该也有虚拟的吧,果真跟自己的猜测一样还真有这东西,顺便也下载了个串口小助手做为调试之用。下面就先看看软件环境的搭建:

 

1.下载comm.jar、win32com.dll和javax.comm.properties。 (附件提供下载)

介绍:comm.jar提供了通讯用的java API,win32com.dll提供了供comm.jar调用的本地驱动接口,javax.comm.properties是这个驱动的类配置文件

 

2.拷贝javacomm.jar到X:\jre\lib\ext目录下面;

 

3.拷贝javax.comm.properties到X:\jre\lib目录下面;

 

4.拷贝win32com.dll到X:\jre\bin目录下面;

 

5.更新下IDE里面的JDK环境,如下图:

 

接着是硬件虚拟环境安装虚拟串口,这里我用的是VSPD6.0(附件提供下载),安装好后启动VSPD添加我们所需要的端口,注意这里是按组的方式添加的,例如COM1和COM2是一组同时添加,以此类推。如下图所示:

 

所有环境都准备好后,先来简单认识下comm.jar的内容。单从comm API的javadoc来看,SUM提供给我们的只有区区以下13个类或接口,具体如下:
javax.comm.CommDriver
javax.comm.CommPort javax.comm.ParallelPort
javax.comm.SerialPort javax.comm.CommPortIdentifier
javax.comm.CommPortOwnershipListener
javax.comm.ParallelPortEvent javax.comm.SerialPortEvent
javax.comm.ParallelPortEventListener (extends java.util.EventListener)
javax.comm.SerialPortEventListener (extends java.util.EventListener)
javax.comm.NoSuchPortException javax.comm.PortInUseException
javax.comm.UnsupportedCommOperationException

这些类和接口命名一看便知其意,就不做一一介绍啦,可以到官网或网上找到更详细的信息。下面先测试下所搭建的环境是否可用,主要代码如下:
Java代码   收藏代码
  1. Enumeration<?> en = CommPortIdentifier.getPortIdentifiers();  
  2. CommPortIdentifier portId;  
  3. while (en.hasMoreElements()) {  
  4.     portId = (CommPortIdentifier) en.nextElement();  
  5.     // 如果端口类型是串口,则打印出其端口信息  
  6.     if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {  
  7.         System.out.println(portId.getName());  
  8.     }  
  9. }  
  运行代码后,控制台有输出正确的端口(如下图),说明所有环境正常可进行下步工作,否则请检查。

  最后要解决的就是与串口数据交互的问题。在这个问题上,最主要的难点就是数据读取,因为我们不知道端口什么时候会有数据到来,也不知数据长度如何。通常,串口通信应用程序有两种模式,一种是实现SerialPortEventListener接口,监听各种串口事件并作相应处理;另一种就是建立一个独立的接收线程专门负责数据的接收。参考众多老前辈的代码后,下面就采用第一种方式写了个简单的助手程序,具体的实现请看详细代码,如下:

Java代码   收藏代码
  1. package com.elkan1788.view;  
  2.   
  3. import java.awt.BorderLayout;  
  4. import java.awt.Button;  
  5. import java.awt.Color;  
  6. import java.awt.Font;  
  7. import java.awt.GridLayout;  
  8. import java.awt.Image;  
  9. import java.awt.TextArea;  
  10. import java.awt.TextField;  
  11. import java.awt.event.ActionEvent;  
  12. import java.awt.event.ActionListener;  
  13. import java.io.IOException;  
  14. import java.io.InputStream;  
  15. import java.io.OutputStream;  
  16. import java.util.ArrayList;  
  17. import java.util.Enumeration;  
  18. import java.util.List;  
  19. import java.util.TooManyListenersException;  
  20.   
  21. import javax.comm.CommPortIdentifier;  
  22. import javax.comm.NoSuchPortException;  
  23. import javax.comm.PortInUseException;  
  24. import javax.comm.SerialPort;  
  25. import javax.comm.SerialPortEvent;  
  26. import javax.comm.SerialPortEventListener;  
  27. import javax.comm.UnsupportedCommOperationException;  
  28. import javax.imageio.ImageIO;  
  29. import javax.swing.JComboBox;  
  30. import javax.swing.JFrame;  
  31. import javax.swing.JLabel;  
  32. import javax.swing.JOptionPane;  
  33. import javax.swing.JPanel;  
  34. import javax.swing.SwingConstants;  
  35. import javax.swing.border.EmptyBorder;  
  36.   
  37. public class JavaRs232 extends JFrame implements ActionListener, SerialPortEventListener {  
  38.   
  39.     /** 
  40.      * JDK Serial Version UID 
  41.      */  
  42.     private static final long serialVersionUID = -7270865686330790103L;  
  43.   
  44.     protected int WIN_WIDTH = 380;  
  45.       
  46.     protected int WIN_HEIGHT = 300;  
  47.       
  48.     private JComboBox<?> portCombox, rateCombox, dataCombox, stopCombox, parityCombox;   
  49.       
  50.     private Button openPortBtn, closePortBtn, sendMsgBtn;  
  51.       
  52.     private TextField sendTf;  
  53.       
  54.     private TextArea readTa;  
  55.       
  56.     private JLabel statusLb;  
  57.       
  58.     private String portname, rate, data, stop, parity;  
  59.       
  60.     protected CommPortIdentifier portId;  
  61.       
  62.     protected Enumeration<?> ports;  
  63.       
  64.     protected List<String> portList;  
  65.   
  66.     protected SerialPort serialPort;  
  67.   
  68.     protected OutputStream outputStream = null;   
  69.   
  70. protected InputStream inputStream = null;   
  71.       
  72. protected String mesg;  
  73.       
  74. protected int sendCount, reciveCount;  
  75.       
  76.     /** 
  77.      * 默认构造函数 
  78.      */  
  79.     public JavaRs232() {          
  80.         super("Java RS-232串口通信测试程序   凡梦星尘");  
  81.         setSize(WIN_WIDTH, WIN_HEIGHT);  
  82.         setLocationRelativeTo(null);  
  83.         Image icon = null;  
  84.         try {  
  85.             icon = ImageIO.read(JavaRs232.class.getResourceAsStream("/res/rs232.png"));  
  86.         } catch (IOException e) {  
  87.             showErrMesgbox(e.getMessage());  
  88.         }  
  89.         setIconImage(icon);  
  90.         setResizable(false);  
  91.         scanPorts();  
  92.         initComponents();  
  93.         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  94.         setVisible(true);  
  95.     }  
  96.       
  97.     /** 
  98.      * 初始化各UI组件 
  99.      * @since 2012-3-22 下午11:56:39 
  100.      */  
  101.     public void initComponents() {        
  102.         // 共用常量  
  103.         Font lbFont = new Font("微软雅黑", Font.TRUETYPE_FONT, 14);  
  104.   
  105.         // 创建左边面板  
  106.         JPanel northPane = new JPanel();  
  107.         northPane.setLayout(new GridLayout(11));  
  108.         // 设置左边面板各组件  
  109.         JPanel leftPane = new JPanel();       
  110.         leftPane.setOpaque(false);  
  111.         leftPane.setLayout(new GridLayout(3,2));  
  112.         JLabel portnameLb = new JLabel("串口号:");  
  113.         portnameLb.setFont(lbFont);  
  114.         portnameLb.setHorizontalAlignment(SwingConstants.RIGHT);  
  115.         portCombox = new JComboBox<String>((String [])portList.toArray(new String[0]));  
  116.         portCombox.addActionListener(this);  
  117.         JLabel databitsLb = new JLabel("数据位:");  
  118.         databitsLb.setFont(lbFont);  
  119.         databitsLb.setHorizontalAlignment(SwingConstants.RIGHT);  
  120.         dataCombox = new JComboBox<Integer>(new Integer[]{5678});  
  121.         dataCombox.setSelectedIndex(3);  
  122.         dataCombox.addActionListener(this);  
  123.         JLabel parityLb = new JLabel("校验位:");  
  124.         parityLb.setFont(lbFont);  
  125.         parityLb.setHorizontalAlignment(SwingConstants.RIGHT);  
  126.         parityCombox = new JComboBox<String>(new String[]{"NONE","ODD","EVEN","MARK","SPACE"});  
  127.         parityCombox.addActionListener(this);  
  128.         // 添加组件至面板  
  129.         leftPane.add(portnameLb);  
  130.         leftPane.add(portCombox);  
  131.         leftPane.add(databitsLb);  
  132.         leftPane.add(dataCombox);  
  133.         leftPane.add(parityLb);  
  134.         leftPane.add(parityCombox);  
  135.   
  136.         //创建右边面板  
  137.         JPanel rightPane = new JPanel();  
  138.         rightPane.setLayout(new GridLayout(3,2));  
  139.         // 设置右边面板各组件  
  140.         JLabel baudrateLb = new JLabel("波特率:");  
  141.         baudrateLb.setFont(lbFont);  
  142.         baudrateLb.setHorizontalAlignment(SwingConstants.RIGHT);  
  143.         rateCombox = new JComboBox<Integer>(new Integer[]{2400,4800,9600,14400,19200,38400,56000});  
  144.         rateCombox.setSelectedIndex(2);  
  145.         rateCombox.addActionListener(this);  
  146.         JLabel stopbitsLb = new JLabel("停止位:");  
  147.         stopbitsLb.setFont(lbFont);  
  148.         stopbitsLb.setHorizontalAlignment(SwingConstants.RIGHT);  
  149.         stopCombox = new JComboBox<String>(new String[]{"1","2","1.5"});  
  150.         stopCombox.addActionListener(this);  
  151.         openPortBtn = new Button("打开端口");  
  152.         openPortBtn.addActionListener(this);  
  153.         closePortBtn = new Button("关闭端口");    
  154.         closePortBtn.addActionListener(this);  
  155.         // 添加组件至面板  
  156.         rightPane.add(baudrateLb);  
  157.         rightPane.add(rateCombox);  
  158.         rightPane.add(stopbitsLb);  
  159.         rightPane.add(stopCombox);  
  160.         rightPane.add(openPortBtn);  
  161.         rightPane.add(closePortBtn);  
  162.         // 将左右面板组合添加到北边的面板  
  163.         northPane.add(leftPane);  
  164.         northPane.add(rightPane);  
  165.   
  166.         // 创建中间面板  
  167.         JPanel centerPane = new JPanel();  
  168.         // 设置中间面板各组件  
  169.         sendTf = new TextField(42);  
  170.         readTa = new TextArea(8,50);  
  171.         readTa.setEditable(false);  
  172.         readTa.setBackground(new Color(225,242,250));  
  173.         centerPane.add(sendTf);  
  174.         sendMsgBtn = new Button(" 发送 ");  
  175.         sendMsgBtn.addActionListener(this);  
  176.         // 添加组件至面板  
  177.         centerPane.add(sendTf);  
  178.         centerPane.add(sendMsgBtn);  
  179.         centerPane.add(readTa);  
  180.           
  181.         // 设置南边组件  
  182.         statusLb = new JLabel();  
  183.         statusLb.setText(initStatus());  
  184.         statusLb.setOpaque(true);  
  185.           
  186.         // 获取主窗体的容器,并将以上三面板以北、中、南的布局整合  
  187.         JPanel contentPane = (JPanel)getContentPane();  
  188.         contentPane.setLayout(new BorderLayout());  
  189.         contentPane.setBorder(new EmptyBorder(0000));  
  190.         contentPane.setOpaque(false);  
  191.         contentPane.add(northPane, BorderLayout.NORTH);  
  192.         contentPane.add(centerPane, BorderLayout.CENTER);  
  193.         contentPane.add(statusLb, BorderLayout.SOUTH);  
  194.     }  
  195.       
  196.     /** 
  197.      * 初始化状态标签显示文本 
  198.      * @return String 
  199.      * @since 2012-3-23 上午12:01:53 
  200.      */  
  201.     public String initStatus() {  
  202.         portname = portCombox.getSelectedItem().toString();  
  203.         rate = rateCombox.getSelectedItem().toString();  
  204.         data = dataCombox.getSelectedItem().toString();  
  205.         stop = stopCombox.getSelectedItem().toString();  
  206.         parity = parityCombox.getSelectedItem().toString();  
  207.           
  208.         StringBuffer str = new StringBuffer("当前串口号:");  
  209.         str.append(portname).append(" 波特率:");  
  210.         str.append(rate).append(" 数据位:");  
  211.         str.append(data).append(" 停止位:");  
  212.         str.append(stop).append(" 校验位:");  
  213.         str.append(parity);  
  214.         return str.toString();  
  215.     }  
  216.       
  217.     /** 
  218.      * 扫描本机的所有COM端口 
  219.      * @since 2012-3-23 上午12:02:42 
  220.      */  
  221.     public void scanPorts() {  
  222.         portList = new ArrayList<String>();  
  223.         Enumeration<?> en = CommPortIdentifier.getPortIdentifiers();  
  224.         CommPortIdentifier portId;  
  225.         while(en.hasMoreElements()){  
  226.             portId = (CommPortIdentifier) en.nextElement();  
  227.             if(portId.getPortType() == CommPortIdentifier.PORT_SERIAL){  
  228.                 String name = portId.getName();  
  229.                 if(!portList.contains(name)) {  
  230.                     portList.add(name);  
  231.                 }  
  232.             }  
  233.         }  
  234.         if(null == portList   
  235.                 || portList.isEmpty()) {  
  236.             showErrMesgbox("未找到可用的串行端口号,程序无法启动!");  
  237.             System.exit(0);  
  238.         }  
  239.     }  
  240.       
  241.     /** 
  242.      * 打开串行端口 
  243.      * @since 2012-3-23 上午12:03:07 
  244.      */  
  245.     public void openSerialPort() {   
  246.         // 获取要打开的端口  
  247.         try {  
  248.             portId = CommPortIdentifier.getPortIdentifier(portname);  
  249.         } catch (NoSuchPortException e) {  
  250.             showErrMesgbox("抱歉,没有找到"+portname+"串行端口号!");  
  251.             setComponentsEnabled(true);  
  252.             return ;  
  253.         }  
  254.         // 打开端口  
  255.         try {  
  256.             serialPort = (SerialPort) portId.open("JavaRs232"2000);  
  257.             statusLb.setText(portname+"串口已经打开!");  
  258.         } catch (PortInUseException e) {  
  259.             showErrMesgbox(portname+"端口已被占用,请检查!");  
  260.             setComponentsEnabled(true);  
  261.             return ;  
  262.         }  
  263.           
  264.         // 设置端口参数  
  265.         try {  
  266.             int rate = Integer.parseInt(this.rate);  
  267.             int data = Integer.parseInt(this.data);  
  268.             int stop = stopCombox.getSelectedIndex()+1;  
  269.             int parity = parityCombox.getSelectedIndex();  
  270.             serialPort.setSerialPortParams(rate,data,stop,parity);  
  271.         } catch (UnsupportedCommOperationException e) {  
  272.             showErrMesgbox(e.getMessage());  
  273.         }  
  274.   
  275.         // 打开端口的IO流管道   
  276.         try {   
  277.             outputStream = serialPort.getOutputStream();   
  278.             inputStream = serialPort.getInputStream();   
  279.         } catch (IOException e) {  
  280.             showErrMesgbox(e.getMessage());  
  281.         }   
  282.   
  283.         // 给端口添加监听器  
  284.         try {   
  285.             serialPort.addEventListener(this);   
  286.         } catch (TooManyListenersException e) {  
  287.             showErrMesgbox(e.getMessage());  
  288.         }   
  289.   
  290.         serialPort.notifyOnDataAvailable(true);   
  291.     }   
  292.       
  293.     /** 
  294.      * 给串行端口发送数据 
  295.      * @since 2012-3-23 上午12:05:00 
  296.      */  
  297.     public void sendDataToSeriaPort() {   
  298.         try {   
  299.             sendCount++;  
  300.             outputStream.write(mesg.getBytes());   
  301.             outputStream.flush();   
  302.   
  303.         } catch (IOException e) {   
  304.             showErrMesgbox(e.getMessage());  
  305.         }   
  306.           
  307.         statusLb.setText("  发送: "+sendCount+"                                      接收: "+reciveCount);  
  308.     }   
  309.       
  310.     /** 
  311.      * 关闭串行端口 
  312.      * @since 2012-3-23 上午12:05:28 
  313.      */  
  314.     public void closeSerialPort() {   
  315.         try {   
  316.             if(outputStream != null)  
  317.                 outputStream.close();  
  318.             if(serialPort != null)  
  319.                 serialPort.close();   
  320.             serialPort = null;  
  321.             statusLb.setText(portname+"串口已经关闭!");  
  322.             sendCount = 0;  
  323.             reciveCount = 0;  
  324.             sendTf.setText("");  
  325.             readTa.setText("");  
  326.         } catch (Exception e) {   
  327.             showErrMesgbox(e.getMessage());  
  328.         }   
  329.     }     
  330.       
  331.     /** 
  332.      * 显示错误或警告信息 
  333.      * @param msg 信息 
  334.      * @since 2012-3-23 上午12:05:47 
  335.      */  
  336.     public void showErrMesgbox(String msg) {  
  337.         JOptionPane.showMessageDialog(this, msg);  
  338.     }  
  339.   
  340.     /** 
  341.      * 各组件行为事件监听 
  342.      */  
  343.     public void actionPerformed(ActionEvent e) {  
  344.         if(e.getSource() == portCombox  
  345.                 || e.getSource() == rateCombox  
  346.                 || e.getSource() == dataCombox  
  347.                 || e.getSource() == stopCombox  
  348.                 || e.getSource() == parityCombox){  
  349.             statusLb.setText(initStatus());  
  350.         }  
  351.         if(e.getSource() == openPortBtn){  
  352.             setComponentsEnabled(false);              
  353.             openSerialPort();  
  354.         }  
  355.         if(e.getSource() == closePortBtn){  
  356.             if(serialPort != null){  
  357.                 closeSerialPort();  
  358.             }  
  359.             setComponentsEnabled(true);  
  360.         }  
  361.           
  362.         if(e.getSource() == sendMsgBtn){  
  363.             if(serialPort == null){  
  364.                 showErrMesgbox("请先打开串行端口!");  
  365.                 return ;  
  366.             }  
  367.             mesg = sendTf.getText();  
  368.             if(null == mesg || mesg.isEmpty()){  
  369.                 showErrMesgbox("请输入你要发送的内容!");  
  370.                 return ;  
  371.             }  
  372.             sendDataToSeriaPort();  
  373.         }  
  374.     }  
  375.   
  376.     /** 
  377.      * 端口事件监听 
  378.      */  
  379.     public void serialEvent(SerialPortEvent event) {  
  380.         switch (event.getEventType()) {  
  381.             case SerialPortEvent.BI:  
  382.             case SerialPortEvent.OE:  
  383.             case SerialPortEvent.FE:  
  384.             case SerialPortEvent.PE:  
  385.             case SerialPortEvent.CD:  
  386.             case SerialPortEvent.CTS:  
  387.             case SerialPortEvent.DSR:  
  388.             case SerialPortEvent.RI:  
  389.             case SerialPortEvent.OUTPUT_BUFFER_EMPTY:  
  390.                 break;  
  391.             case SerialPortEvent.DATA_AVAILABLE:  
  392.                 byte[] readBuffer = new byte[50];  
  393.   
  394.             try {  
  395.                 while (inputStream.available() > 0) {  
  396.                     inputStream.read(readBuffer);  
  397.                 }  
  398.                 StringBuilder receivedMsg = new StringBuilder("/-- ");  
  399.                 receivedMsg.append(new String(readBuffer).trim()).append(" --/\n");  
  400.                 readTa.append(receivedMsg.toString());  
  401.                 reciveCount++;  
  402.                 statusLb.setText("  发送: "+sendCount+"                                      接收: "+reciveCount);  
  403.             } catch (IOException e) {  
  404.                 showErrMesgbox(e.getMessage());  
  405.             }  
  406.         }  
  407.     }  
  408.       
  409.     /** 
  410.      * 设置各组件的开关状态 
  411.      * @param enabled 状态 
  412.      * @since 2012-3-23 上午12:06:24 
  413.      */  
  414.     public void setComponentsEnabled(boolean enabled) {  
  415.         openPortBtn.setEnabled(enabled);  
  416.         openPortBtn.setEnabled(enabled);  
  417.         portCombox.setEnabled(enabled);  
  418.         rateCombox.setEnabled(enabled);  
  419.         dataCombox.setEnabled(enabled);  
  420.         stopCombox.setEnabled(enabled);  
  421.         parityCombox.setEnabled(enabled);  
  422.     }  
  423.       
  424.     /** 
  425.      * 运行主函数 
  426.      * @param args 
  427.      * @since 2012-3-23 上午12:06:45 
  428.      */  
  429.     public static void main(String[] args) {  
  430.         new JavaRs232();          
  431.     }  
  432. }  
  代码编写完成,按下F11键进入调试状态,一切运行正常良好,请看图:
1.启动界面

 

2.端口检测

 

3. 通讯测试

  

最后再抽空来美化程序下,效果更漂亮,谁还会说JAVA程序的界面丑陋呢,呵呵...




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值