基于Java语言的51单片机串口通讯PC机程序

2019-04-15 18:19发布

摘要:由于Java语言的诸多优点,Java得到了广泛的应用,如今利用Java开发串口通讯已相当成熟,实现简单,可移植性强。文章详细介绍了如何配置开发环境以及使用Java串口API函数编写PC机程序。本程序比使用C++语言编写的串口通讯程序更容易理解,且移植性非常强,视图与控制分开,便于维护和升级。
关键字:JavaJBuilderKeilCJava Communications API,串口通讯,RS232,单片机
 
 
硬件部分(KeilC
点击看大图

硬件电路图
串口通讯硬件部分电路,收发器件采用max2325V供电。J31接一单片机如AT89C52,单片机的串口与max2321011脚相连。
max232与微机通过9针接头相连。
本文的实验环境是AT89C52,单片机的内部程序是用KeilC语言编写的,程序功能非常简单,检测到开始信号后从串口读数据,然后把读入的数据发送给串口,遇到结束符停止。C语言代码如下供大家参考。在uv3中含有两个文件comm.hcomm.c,代码分别为:
/********************************************************/
/* comm.h                                               */
/* serial port define, only use in comm project                          */     
/********************************************************/
#define uchar  unsigned char
#define uint    unsigned int
#define length 0x0F       //数据包长度
 
uchar      CR          = 0x0D;
uchar      LF          = 0x0A;
uchar      ESC        = 0x1B;
uchar      SYNC     = 0x01;   //数据包启始符
uchar      PID        = 0x00;   //数据包标示字
uchar      ADDR;                  //串口接收外部命令(片内地址)
uchar      DATA;                   //串口返回片内数据
uchar      ENDP     = 0x00;   //数据包结束符
uchar      ACK              = 0x06;   //串口确认
uchar      ERROR   = 0x18;   //串口错误
 
uchar      wrong[] = "Bad command";
/*END*/
/*******************************************************/
/*comm..c                                            */
/* Write time is 2005.4.15,By Gooseli                  */
/* Copyright is changsha HUNU unversity gooseli.com          */
/* Cpu is At89C51,Fclk is 11.059MHz                                 */
/* Compiler is keilC51 compiler                                           */
/*******************************************************/
 
#include
#include
#include
#include
 
 
void commInit(){
//**************************//
// 8051串口初始化                     //
//**************************//
       SCON    = 0x52;
       PCON    = 0x80;
 
       TMOD   = 0x21;
       TH1      = 0x0FA;
       TL1       = 0x0FA;
       TCON    = 0x40;
//*****************************************************//
// 串口控制器工作于方式18位,频率可变。接收允许      //
// 串口波特率系数SMOD = 1                                              //
// 定时器1工作于方式18位自动装载。定时器0方式116 //
// 11.059M晶振,波特率 = 9600TH1 = 0x0FA;            //
//                      19200           0x0FD             //
//                      57600              0x0FF                //
// 3.6864M晶振                   9600            0x0FE             //
//                                        19200            0x0FF                    //
// #3.6864M晶振工作于方式2                                                 //
// #SMOD = 1时,波特率 = 115200                      //
// 开中断TR1 = 1                                       //
//*****************************************************//
}
 
 
uchar flag;
uchar readln();
void println( uchar *str );
 
main(){  
 
    commInit();                                             //初始化串口
       while(1){
              flag = readln();
       }
}
 
uchar readln(){
       uchar      a;
       uchar      str[length];
       int i;
 
       scanf("%c",&a);                                     //寻找起始符,回车则开始
       if( a==SYNC || a==LF ){
              while(1){
                     printf(" >>");
                     //printf(">>");
                     scanf("%c",&a);
                     if( a==ENDP || a == ESC ){  //如果ESC则对话结束
                            break;    
                     }
                     for( i="0"; i                                                                      //读入数据包,如果溢出或者回车则结束
                            str[i] = a;
                            scanf("%c",&a);
                     }
                     str[i] = ENDP;                            //为数据包添加结束符,“0
                     printf("%s",str);                 //输出输入值
                    
                     /*To do something by yourself*/
              }
              return ACK;
       }
       printf(" %s >>",wrong);
 
       return ERROR;     
}
/*END*/
配置运行环境JDK
Java通讯库函数Java Communications APIJava开发工具JBuilderX
Java(TM) Communications API Specification 2.0(Windows Platform)Sun公司为Windows平台提供的一个串口API扩展,可以到 http://java.sun.com/products/javacomm/ 下载。Sun公司还提供了其他操作系统下的API下载,移植性是Java先天的优势,如果需要在其他操作系统运行程序,不需要改动程序本身,只要在操作系统下植入相应的API库函数即可实现。
JBuilderBorland公司出品的一款功能强大的可视化Java集成开发工具,可以快速开发包括复杂企业级应用系统的各种Java程序,本文的程序都用其实现。当然我们以可使用其他优秀的开发工具,例如开放源代码的Eclipse,功能强大,插件丰富。
在下载Java Communications API压缩文件里找到三个文件:comm.jarwin32comm.dlljavax.comm.properties,这三个文件是把API安装到Windows环境中的重要文件,我们把他们放在我们的JDK里面。
comm..jar复制到%JAVA_HOME%jrelibextjavax.comm.properties复制到%JAVA_HOME%jrelibwin32comm.dll复制到%JAVA_HOME%in即可。这样我们的程序就可以在Windows环境中运行了,Java Communications API压缩文件中自带有例子,我们可以尝试一下。
接下来我们要把Java Communications API安装到JBuilder里面,如果JBuilder不是使用的外部的JDK,照上面的的步骤再做一次。假如我们外部的JDKJBuilderJDK是同一的JDK,我们就直接跳到下一步。
 
1)打开JBuilder,为我们的任务建立一个工程,给它起个有意义的名字,不多讲了。JBuilder会自动生成两个文件,如,工程名为comm,就会生成文件commApplicationcommFrame
2)选择Tools菜单,选择Configure Libraries…,如图1所示。
3)点击New按钮,为JBuilder增加一个函数库。如图2,点击OK即可。
4)下一步为你的工程增加这个库函数,以便你在工程里调用它们。选择Project菜单中的Project Properities选项,左侧选中Paths,右侧选中Required Libraries,单击Add,出现一个小的对话框,选择我们刚才增加的comm函数库,如图3,点击OK两次即可。
现在环境已经配置好了,我们要开始正式工作了。点击看大图

2 Configure Library

点击看大图
2 New Librariy Wizard

点击看大图3 Select comm. Library
 
程序开发JBuilderX
 
1.  51单片机交互信息,数据库存取(Data
为了保证数据传输的顺利进行,单片机与PC之间通讯要建立一个协议,在本实例中,采用如下协议:
程序打开串口后,程序发送启始符(0x01)表示通讯开始。
通讯开始后,程序就开始发送和接收数据包,数据包以结束符(0x000x0D, 0x0A)表示结尾。由于单片机受控于PC机,所以单片机一般不主动发送数据,只有在PC机发送一个命令,它才会发送一个回应
如果程序停止符(0x00),则通讯结束。
2.  界面设计(View
这部分设计主程序的视图,即使用者看到的部分,包括按钮,下拉菜单,文字编辑框等。
为了程序的可读性,我们将所有的视图从主程序中分离出来,作成Bean的形式,然后在主程序中调用它们。Java提供了五种布局管理形式FlowLayout,GridLayout GridBagLayout BorderLayout,CardLayout。灵活的运用这些布局,可以达到各种各样的效果,其中GridBagLayout功能强大,使用灵活,本文主要采用这种布局。
3.  主程序设计(Control
这部分设计程序的实现方法,逻辑步骤。
1)首先定义串口,输入输出流等,如下所示:
package comm;
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.comm.*;//包含comm类包,才能使用其API函数
import java.io.*;
import java.util.*;
 
public class CommFrame extends JFrame implements Runnable, SerialPortEventListener {
  JPanel contentPane; //定义一个JPanel,将视图Bean包含进来
  BorderLayout borderLayout1 = new BorderLayout();
  IOBean ioBean = new IOBean();//右侧视图Bean类事例化
  ControlBean controlBean = new ControlBean();//左侧视图Bean类事例化
 
  //Communination define
  static CommPortIdentifier portName;//定义串口
  int portId;
  static Enumeration portList;
  InputStream inputStream;//定义输入流
  OutputStream outputStream;//定义输出流
  SerialPort serialPort;
  Thread readThread;//定义一个线程,程序全双工通讯
  static String TimeStamp;
 
 
  //Construct the frame
  public CommFrame() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();//程序初始化
      commInit();//串口初始化
    }catch(Exception e) {
      e.printStackTrace();
    }
  }
 
private void jbInit() throws Exception  {……}
public void commInit() {……}
public void commClose() {……}
 
public void commWrite() {……}
public void CommRead() {……}
public void run() {……}
public void serialEvent(SerialPortEvent event) {…….}//代码如下
 
 
//Overridden so we can exit when window is closed
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      commClose();
      System.exit(0);
    }
  }
}
2)串口初始化,首先监测串口是否被占用,如果没有被占用则打开串口。打开输入输出流以便下面的程序从串口读写数据,定义串口的波特率,位数,停止位,奇偶校验,在使用过程中可以改变这些内容以适应不同的需求。
public void commInit() {
    //Communination ports owned or not
    portId = 1;
    try{
      portList = CommPortIdentifier.getPortIdentifiers();
      while (portList.hasMoreElements()) {
        portName = (CommPortIdentifier) portList.nextElement();
        if (portName.getPortType() == CommPortIdentifier.PORT_SERIAL) {
          if (portName.isCurrentlyOwned()) {//串口是否被占用
  ioBean.Receiver.append(" COM"+portId+"Ownedby"+ portName.getCurrentOwner());
            TimeStamp = new java.util.Date().toString();
            portId ++;
          }else if (portName.getName().equals("COM" + portId)) {
            break;
          }
        }
      }
      //Communination ports init
      try {
  serialPort = (SerialPort) portName.open("Gooseli_MCU_Control_App", 2000);//打开串口
        controlBean.CommPortID.setText("COM" + portId);
        controlBean.OnOff.setText("ON");//开关按钮置开状态
        controlBean.OnOff.setSelected(true);
        TimeStamp = new java.util.Date().toString();
  System.out.println(TimeStamp + ": msg2 - SerialPort COM" + portId + " is opend");
  ioBean.Receiver.append(" COM" + portId + " is opend");//显示区域显示串口被打开
      } catch (PortInUseException e) {
        System.out.println(e);
        ioBean.Receiver.append(" COM" + portId + " " + e);
      }
      try {
        inputStream = serialPort.getInputStream();//打开输入流
      } catch (IOException e) {}
      try {
        outputStream = serialPort.getOutputStream();
        outputStream.write((byte)0x01);//向串口写入启始符开始传送数据包
        ioBean.Receiver.setText(" COM" + portId + ">>" + "Start");
        controlBean.begin.setSelected(true);
      } catch (IOException e) {}
      try {
        serialPort.setSerialPortParams(9600,//波特率
                                       SerialPort.DATABITS_8,//数据位
                                       SerialPort.STOPBITS_1,//停止位
                                       SerialPort.PARITY_NONE);//校验位
      } catch (UnsupportedCommOperationException e) {}
      CommRead();//程序开始从串口读数据
    }catch(Exception e) {}
  }
 
public void commClose() {
    try {
      inputStream.close();
      outputStream.close();
      serialPort.close();
      System.out.println(TimeStamp + ": msg2 - SerialPort COM" + portId + " is closing");
      ioBean.Receiver.append(" COM" + portId + " is closing");
    }catch (Exception e) {
       System.out.println(e);
    }
  }
       3)程序初始化,这里定义了一些事件,以便控制程序的运行。例如开始按钮的事件定义如下:
private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Serial Ports Communication Current");
 
    contentPane.add(ioBean,BorderLayout.CENTER);
    contentPane.add(controlBean, BorderLayout.WEST);
    controlBean.OnOff.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent ae) {