浅谈Java串行端口技术协议_java 标准串口协议格式-程序员宅基地

技术标签: java 串口  

http://www.yesky.com/50/1894050_3.shtml


串行通讯慨述

  串行通讯协议有很多种,像RS232,RS485,RS422,甚至现今流行的USB等都是串行通讯协议。而串行通讯技术的应用无处不在。可能大家见的最多就是电脑的串口与Modem的通讯。记得在PC机刚开始在中国流行起来时(大约是在90年代前五年),那时甚至有人用一条串行线进行两台电脑之间的数据共享。除了这些,手机,PDA,USB鼠标键盘等等都是以串行通讯的方式与电脑连接。而笔者工作性质的关系,所接触到的就更多了,像多串口卡,各种种类的具有串口通讯接口的检测与测量仪器,串口通讯的网络设备等。

  虽然串行通讯有很多种,但笔者所知的在整个电子通讯产品方面,以RS232的通讯方式最为多见。虽然USB接口的电子产品也是层出不穷,但了解一下Java在串行通讯方面的技术还有有必要的,说不定有哪位读者还想用此技术写一个PDA与电脑之间数据共享的程序呢。

  本文主要以RS232为主来讲解Java的串行通讯技术。

  RS232通讯基础

  RS-232-C(又称EIA RS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。RS232是一个全双工的通讯协议,它可以同时进行数据接收和发送的工作。RS232的端口通常有两种:9针(DB9)和25针(DB25)。

  DB9和DB25的常用针脚定义


图1

   常见的边线方式

  常见的通讯方式是三线式,这种方式是将两个RS232设备的发送端(TXD)和接收端(RXD)及接地端(GND)互相连接,也是许多读者所知道的连接方式:


图2

  这种方式分别将两端的RS232接口的2--3,3---2,5(7)---5(7)针脚连接起来。其中2是数据接收线(RXD),3是数据发送线(TXD),5(7)是接地(RND)。如果有一台式PC,和一部 NoteBook电脑,就可以用这种方式连线了。用三线式可以将大多数的RS232设备连接起来。但如果你认死了2--3,3--2,5(7)--5(7)对接这个理,会发现在连某些RS232设备时并不奏效。这是因为有些设备在电路内部已将2和3线调换过来了,你只要2,3,5(7)针一一对应就行了。

   小技巧:如何辨别TXD和RXD端口?

  搞电子的人手边应该常备一个电表,用来测测电压,电阻什么的会很有用。你只要分别测一下RS232端口的2--5或3--5针脚之间的电压,通常TXD针脚与GND之间会有3~15V左右的负电压,表示它是TXD针脚。
安装Java Communications API

   Sun的J2SE中并没有直接提供以上提到的任何一种串行通讯协议的开发包,而是以独立的jar包形式发布在java.sun.com网站上(从这里下载)----即comm.jar,称之为Javatm Communications API,它是J2SE的标准扩展。comm.jar并不是最近才有,早在1998年时,sun就已经发布了这个开发包。comm.jar分别提供了对常用的RS232串行端口和IEEE1284并行端口通讯的支持。目前sun发布的comm.jar只有Windows和Solaris平台两个版本,如果你需要Linux平台下的,可以在http://www.geeksville.com/~kevinh/linuxcomm.html找到。

  在使用comm.jar之前,必须知道如何安装它。这也是困扰许多初学java RS232通讯者的一个难题。如果我们电脑上安装了JDK,它将同时为我们安装一份JRE(Java Runtime Entironment),通常我们运行程序时都是以JRE来运行的。所以以下的安装适用于JRE。如果你是用JDK来运行程序的,请将相应的改成。

  下载了comm.jar开发包后,与之一起的还有两个重要的文件,win32com.dll和javax.comm.properties。comm.jar提供了通讯用的java API,而win32com.dll提供了供comm.jar调用的本地驱动接口。而javax.comm.properties是这个驱动的类配置文件。首先将comm.jar复制到\lib\ext目录。再将win21com.dll复制到你的RS232应用程序运行的目录,即user.dir。然后将javax.comm.properties复制到\lib目录。

   通讯前的准备

  如果你手头上没有现成的提供了标准RS232串口的设备,你可以将自己的电脑模拟成两台不同的串口设备。通常电脑主机后面的面板提供了两个9针的串口,请将这两个串口的2,3,5脚按前面介绍的方法连接。电子市场都有现成的连接头卖,请不要买那种封装的严严实实的接头,而要买用螺丝封装可以拆开的连接头,这样可以方便自己根据需要连接各个针脚。



  我无意于在此详细描述Comm API每个类和接口的用法,但我会介绍Comm API的类结构和几个重要的API用法。

  所有的comm API位于javax.comm包下面。从Comm API的javadoc来看,它介绍给我们的只有区区以下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

  下面讲解一下几个主要类或接口。

  1.枚举出系统所有的RS232端口

  在开始使用RS232端口通讯之前,我们想知道系统有哪些端口是可用的,以下代码列出系统中所有可用的RS232端口:

Enumeration en = CommPortIdentifier.getPortIdentifiers();

  CommPortIdentifier portId;

  while (en.hasMoreElements())

  {

  portId = (CommPortIdentifier) en.nextElement();

  /*如果端口类型是串口,则打印出其端口信息*/

  if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL)

  {

  System.out.println(portId.getName());

  }

  }

  在我的电脑上以上程序输出以下结果:

  COM1

  COM2

  CommPortIdentifier类的getPortIdentifiers方法可以找到系统所有的串口,每个串口对应一个CommPortIdentifier类的实例。

  2.打开端口

  如果你使用端口,必须先打开它。

try{

  CommPort serialPort = portId.open("My App", 60);

  /*从端口中读取数据*/

  InputStream input = serialPort.getInputStream();

  input.read(...);

  /*往端口中写数据*/

  OutputStream output = serialPort.getOutputStream();

  output.write(...)

  ...

  }catch(PortInUseException ex)

  { ... }

  通过CommPortIdentifier的open方法可以返回一个CommPort对象。open方法有两个参数,第一个是String,通常设置为你的 应用程序的名字。第二个参数是时间,即开启端口超时的毫秒数。当端口被另外的应用程序占用时,将抛出PortInUseException异常。

  在这里CommPortIdentifier类和CommPort类有什么区别呢?其实它们两者是一一对应的关系。CommPortIdentifier主要负责端口的初始化和开启,以及管理它们的占有权。而CommPort则是跟实际的输入和输出功能有关的。通过CommPort的getInputStream()可以取得端口的输入流,它是java.io.InputStream接口的一个实例。我们可以用标准的InputStream的操作接口来读取流中的数据,就像通过FileInputSteam读取文件的内容一样。相应的,CommPort的getOutputStream可以获得端口的输出流,这样就可以往串口输出数据了。

  3.关闭端口

  使用完的端口,必须记得将其关闭,这样可以让其它的程序有机会使用它,不然其它程序使用该端口时可能会抛出端口正在使用中的错误。很奇怪的是,CommPortIdentifier类只提供了开启端口的方法,而要关闭端口,则要调用CommPort类的close()方法。
CommPort的输入流的读取方式与文件的输入流有些不一样,那就是你可能永远不知这个InputStream何时结束,除非对方的OutputStream向你发送了一个特定数据表示发送结束,你收到这个特定字符后,再行关闭你的InputStream。而comm.jar提供了两种灵活的方式让你读取数据。

  1.轮询方式(Polling)

  举个例子,你同GF相约一起出门去看电影,但你的GF好打扮,这一打扮可能就是半小时甚至一小时以上。这时你就耐不住了,每两分钟就催问一次“好了没?”,如此这样,直到你的GF说OK了才算完。这个就叫轮询(Polling)。

  在程序中,轮询通常设计成一个封闭的循环,当满足某个条件时即结束循环。刚才那个例子中,你的GF说“OK了!”,这个就是结束你轮询的条件。在单线程的程序中,当循环一直执行某项任务而又无法预知它何时结束时,此时你的程序看起来可能就像死机一样。在VB程序中,这个问题可以用在循环结构中插入一个doEvent语句来解决。而Java中,最好的方式是使用线程,就像以下代码片断一样。

public TestPort extend Thread

  {

  ...

  InputStream input = serialPort.getInputStream();

  StringBuffer buf = new StringBuffer();

  boolean stopped = false;

  ...

  public void run()

  {

  try {

  while( !stopped )

  int ch = input.read();

  if ( ch=='q' || ch=='Q' )

  {

  /*结束读取,关闭端口...*/

  stopped = true;

  ...

  }

  else

  {

  buf.append((char)ch);

  ...

  }

  }catch (InterruptedException e) { }

  }

  }

2.监听方式(listening)

  Comm API支持标准的Java Bean型的事件模型。也就是说,你可以使用类似AddXXXListener这样的方法为一个串口注册自己的监听器,以监听方式进行数据读取。

  如要对端口监听,你必须先取得CommPortIdentifier类的一个实例,

  CommPort serialPort = portId.open("My App", 60);

  从而取得SerialPort,再调用它的addEventListener方法为它添加监听器,

  serialPort.addEventListener(new MyPortListener());

  SerialPort的监听器必须继承于SerialPortEventListener接口。当有任何SerialPort的事件发生时,将自动调用监听器中的serialEvent方法。Serial Event有以下几种类型:

  BI -通讯中断.

  CD -载波检测.

  CTS -清除发送.

  DATA_AVAILABLE -有数据到达.

  DSR -数据设备准备好.

  FE -帧错误.

  OE -溢位错误.

  OUTPUT_BUFFER_EMPTY -输出缓冲区已清空.

  PE -奇偶校验错.

  RI - 振铃指示.

  下面是一个监听器的示例:

public void MyPortListener implements SerialPortEventListener

  {

   public void serialEvent(SerialPortEvent evt)

   {

  switch (evt.getEventType())

  {

   case SerialPortEvent.CTS :

    System.out.println("CTS event occured.");

    break;

   case SerialPortEvent.CD :

    System.out.println("CD event occured.");

    break;

   case SerialPortEvent.BI :

    System.out.println("BI event occured.");

    break;

   case SerialPortEvent.DSR :

    System.out.println("DSR event occured.");

    break;

   case SerialPortEvent.FE :

    System.out.println("FE event occured.");

    break;

   case SerialPortEvent.OE :

    System.out.println("OE event occured.");

    break;

   case SerialPortEvent.PE :

    System.out.println("PE event occured.");

    break;

   case SerialPortEvent.RI :

    System.out.println("RI event occured.");

    break;

   case SerialPortEvent.OUTPUT_BUFFER_EMPTY :

    System.out.println("OUTPUT_BUFFER_EMPTY event occured.");

    break;

   case SerialPortEvent.DATA_AVAILABLE :

    System.out.println("DATA_AVAILABLE event occured.");

    int ch;

    StringBuffer buf = new StringBuffer();

    InputStream input = serialPort.getInputStream

    try {

     while ( (ch=input.read()) > 0) {

      buf.append((char)ch);

     }

     System.out.print(buf);

    } catch (IOException e) {}

    break;

   }

  }

  这个监听器只是简单打印每个发生的事件名称。而对于大多数 应用程序来说,通常关心是DATA_AVAILABLE事件,当数据从外部设备传送到端口上来时将触发此事件。此时就可以使用前面提到过的方法,serialPort.getInputStream()来从InputStream中读取数据了。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/daditao/article/details/23843115

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法