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

关键字:Java,JBuilder,KeilC,Java Communications API,串口通讯,RS232,单片机

1 硬件部分(KeilC)

图1 硬件电路图

串口通讯硬件部分电路,收发器件采用max232,5V供电。J31接一单片机如AT89C52,单片机的串口与max232的10和11脚相连。

max232与微机通过9针接头相连。

本文的实验环境是AT89C52,单片机的内部程序是用KeilC语言编写的,程序功能非常简单,检测到开始信号后从串口读数据,然后把读入的数据发送给串口,遇到结束符停止。C语言代码如下供大家参考。在uv3中含有两个文件comm.h和comm.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<stdio.h>

#include<string.h>

#include<reg51.h>

#include<comm.h>

void commInit(){

//**************************//

// 8051串口初始化                     //

//**************************//

SCON    = 0x52;

PCON    = 0x80;

TMOD   = 0x21;

TH1      = 0x0FA;

TL1       = 0x0FA;

TCON    = 0x40;

//*****************************************************//

// 串口控制器工作于方式1,8位,频率可变。接收允许      //

// 串口波特率系数SMOD = 1                                              //

// 定时器1工作于方式1,8位自动装载。定时器0方式1,16位 //

// 11.059M晶振,波特率 = 9600,TH1 = 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("\n>>");

//printf(">>");

scanf("%c",&a);

if( a==ENDP || a == ESC ){  //如果ESC则对话结束

break;

}

for( i="0"; i<length-1 && a!=CR && a!=LF; i++ ){

//读入数据包,如果溢出或者回车则结束

str[i] = a;

scanf("%c",&a);

}

str[i] = ENDP;                            //为数据包添加结束符,“\0”

printf("%s",str);                 //输出输入值

/*To do something by yourself*/

}

return ACK;

}

printf("\n%s\n>>",wrong);

return ERROR;

}

/*END*/

2 配置运行环境(JDK)

Java通讯库函数Java Communications API,Java开发工具JBuilderX。

此Java(TM) Communications API Specification 2.0(Windows Platform)是Sun公司为Windows平台提供的一个串口API扩展,可以到 http://java.sun.com/products/javacomm/ 下载。Sun公司还提供了其他操作系统下的API下载,移植性是Java先天的优势,如果需要在其他操作系统运行程序,不需要改动程序本身,只要在操作系统下植入相应的API库函数即可实现。

JBuilder是Borland公司出品的一款功能强大的可视化Java集成开发工具,可以快速开发包括复杂企业级应用系统的各种Java程序,本文的程序都用其实现。当然我们以可使用其他优秀的开发工具,例如开放源代码的Eclipse,功能强大,插件丰富。

在下载Java Communications API压缩文件里找到三个文件:comm.jar,win32comm.dll,javax.comm.properties,这三个文件是把API安装到Windows环境中的重要文件,我们把他们放在我们的JDK里面。

把comm..jar复制到%JAVA_HOME%\jre\lib\ext,javax.comm.properties复制到%JAVA_HOME%\jre\lib,win32comm.dll复制到%JAVA_HOME%\bin即可。这样我们的程序就可以在Windows环境中运行了,Java Communications API压缩文件中自带有例子,我们可以尝试一下。

接下来我们要把Java Communications API安装到JBuilder里面,如果JBuilder不是使用的外部的JDK,照上面的的步骤再做一次。假如我们外部的JDK和JBuilder的JDK是同一的JDK,我们就直接跳到下一步。

1)打开JBuilder,为我们的任务建立一个工程,给它起个有意义的名字,不多讲了。JBuilder会自动生成两个文件,如,工程名为comm,就会生成文件commApplication和commFrame。

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

3 程序开发(JBuilderX)

1.  与51单片机交互信息,数据库存取(Data)

为了保证数据传输的顺利进行,单片机与PC之间通讯要建立一个协议,在本实例中,采用如下协议:

程序打开串口后,程序发送“启始”符(0x01)表示通讯开始。

通讯开始后,程序就开始发送和接收数据包,数据包以“结束”符(0x00,0x0D, 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("\nCOM"+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("\nCOM" + portId + " is opend");//显示区域显示串口被打开

} catch (PortInUseException e) {

System.out.println(e);

ioBean.Receiver.append("\nCOM" + portId + " " + e);

}

try {

inputStream = serialPort.getInputStream();//打开输入流

} catch (IOException e) {}

try {

outputStream = serialPort.getOutputStream();

outputStream.write((byte)0x01);//向串口写入启始符开始传送数据包

ioBean.Receiver.setText("\nCOM" + 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("\nCOM" + 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) {

JToggleButton toggle = (JToggleButton) ae.getSource();

if (toggle.isSelected()) {

controlBean.OnOff.setText("ON");

commInit();

} else {

controlBean.OnOff.setText("OFF");

commClose();

}

}

}

);

controlBean.begin.addActionListener(

new ActionListener() {

public void actionPerformed(ActionEvent ae) {

JToggleButton toggle = (JToggleButton) ae.getSource();

if (toggle.isSelected()) {//如果按钮被按下,则开始

controlBean.begin.setText("Start");

try {

outputStream.write((byte)0x01);//发送起始符

ioBean.Receiver.setText("\nCOM" + portId + " " + "Start");

} catch (IOException e) {}

} else {//如果按纽复位

controlBean.begin.setText("Stop");

try {

outputStream.write((byte)0x00);//发送结束符

ioBean.Receiver.append("\nCOM" + portId + " " + "Stop");

} catch (IOException e) {}

}

}

}

);

ioBean.jButton2.addActionListener(

new ActionListener() {

public void actionPerformed(ActionEvent ae) {

commWrite();

}

}

);

}

4)读写串口,使用多线程,实现全双工通讯。主函数CommFrame实现了Runnable接口,在程序中只需要重写run函数即可实现多线程。

public void commWrite() {

String outString = ioBean.jTextField1.getText();

if (outString.equals("clear")) {

ioBean.Receiver.setText("\nCOM" + portId +" Receive:");

}

ioBean.jTextField1.setText("Gooseli:");

try {

//outputStream.write((byte)0x01);

outputStream.write(outString.getBytes());

outputStream.write((byte)0x0D);

//outputStream.write((byte)0x00);

ioBean.Receiver.setText("\nCOM" + portId + ">>" + outString);

} catch (IOException e) {}

}

public void CommRead() {

try {

serialPort.addEventListener(this);

} catch (TooManyListenersException e) {}

serialPort.notifyOnDataAvailable(true);

readThread = new Thread(this);

readThread.start();

}

public void run() {

try {

Thread.sleep(20000);

}

catch (InterruptedException e) {}

}

public void serialEvent(SerialPortEvent event) {

switch(event.getEventType()) {

case SerialPortEvent.BI:

case SerialPortEvent.OE:

case SerialPortEvent.FE:

case SerialPortEvent.PE:

case SerialPortEvent.CD:

case SerialPortEvent.CTS:

case SerialPortEvent.DSR:

case SerialPortEvent.RI:

case SerialPortEvent.OUTPUT_BUFFER_EMPTY:

break;

case SerialPortEvent.DATA_AVAILABLE:

StringBuffer readBuffer = new StringBuffer();

String scannedInput = null;

int c;

try {

while ((c = inputStream.read()) != 0x00 && c != 0x0D && c != 0x0A) {

readBuffer.append( (char) c);//数据包以回车或者换行表示结束

}

scannedInput = readBuffer.toString();

ioBean.Receiver.append("\n" + scannedInput);

TimeStamp = new java.util.Date().toString();

System.out.println(TimeStamp + ": scanned input received:" + scannedInput);

inputStream.close();

} catch (IOException e) {}

break;

}

}

4.  测试程序

程序运行后如图四所示。

为了方便程序运行,我们作一个批处理文件,和程序生成的jar文件放在一个目录里,这样就可以很方便的在含有Java虚拟机的系统里运行我们的程序了。可以将JBuilder运行窗口(Messages)的信息直接拷贝过来,当然也可以自己建立。

我的批处理文件如下所示:

@echo off

@REM 设置路径包括Java虚拟机和程序jar文件路径

set path=%JAVA_HOME%\bin

set classpath=%cd%\comm.jar

@REM 运行程序,注意在主程序前增加包名,否则找不到主函数

echo Now initializing the program,please wait a minite...

java comm.CommApplication

图4 Test my programme

4 展望

Java作为一个逐渐成熟的程序设计语言,在网络和嵌入式系统越来越多地得到广泛的应用,但是微机底层程序开发发展缓慢。本文应用Java作为串口上位机程序开发语言,是考虑到Java语言的各种优越性,主要是其平台无关性,强大的可移植性,这一点在不久的将来会受到更多的重视。ln

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

  1. 51单片机串口通讯 +Proteus仿真实验

    51单片机串口通讯 +Proteus仿真实验 ✨注意不要使用Proteus 8 Professional 8.13版本串口通信会出错.

  2. 110报警声+单片机c语言,用51单片机做发声小玩意及程序

    用51单片机做发声小玩意及程序 "嘀嘀"警报 生活中我们常常到各种各样的报警声,例如"嘀.嘀-"就是常见的一种声音报警声,但对于这种报警声,嘀0.2秒钟,然后断 ...

  3. 51单片机串口通讯c语言程序,如何使用51单片机实现串口通信

    描述 STC51单片机一般带有1个串口,有的带有2个串口,串口一般用于下载程序和串口通信.串口通信特别适合控制设备,所以工控机的电脑上一般都带有串口. 51单片机的串口引脚为P3.0引脚与P3.1引脚 ...

  4. 51单片机串口通讯介绍和实现

    串口通讯 前言 计算机是一种现代化的信息处理工具,它对信息进行处理并提供结果,其结果(输出)取决于所接收的信息(输入)及相应的处理算法. 随着多微机系统的广泛应用和计算机网络技术的普及,计算机的通信功 ...

  5. 51单片机串口通讯接收一串字符串

    在51单片机中,我们使用上下位机时,我们通常会发送一串字符串,将它作为信号发给单片机处理. 因为串口通信时,发送信息是以一个个字符的形式发送过来的,所以接收的就是一个个字符,通常我们是一个字符数组保存 ...

  6. 51单片机串口通讯详解

    串口,作为单片机程序开发中最常用.最方便,也是应用最广泛的程序调试方法:无论是作为调试工具,打印出调试信息,还是对功能模块进行通信,串口是每个单片机开发人员最常用的单片机外设. 由于大部分51单片机不 ...

  7. [附源码]Python计算机毕业设计SSM基于JAVA语言的国货美妆店管理系统(程序+LW)

    项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...

  8. [附源码]JAVA+ssm基于JAVA语言的国货美妆店管理系统(程序+Lw)

    项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...

  9. VC2012/VS2012 MFC串口通讯上位机程序教程笔记(转)

    使用MFC来编写串口程序,需要有一定的c++语言功底,要清楚MFC代码的组织方式. 鉴于绝大多数的教程还停留在vc6.0这个骨灰级的环境,特在此说明一下VC2012下的代码组织方式,和大家一起交流下~ ...

  10. 51单片机串行口c语言编程,51单片机串口通信c语言编程

    这只是个模板,参考一下 /*----------------------------------------------- 名称:串口通信 网站:www.doflye.net 编写:shifang 日 ...

最新文章

  1. 清华大学图神经网络综述:模型与应用
  2. 关于Java基础需要注意的点
  3. 动态鼠标指针_推荐8款电脑鼠标指针,让你电脑不再千篇一律
  4. BZOJ 1488 Luogu P4727 [HNOI2009]图的同构 (群论、Burnside引理、组合计数)
  5. Wordpress插件
  6. day36 fullstack gevent模块 IO阻塞和非阻塞 IO多路复用 异步IO介绍 其他的补充
  7. 计算机网络(1)TCP和UDP
  8. 数据结构(C语言版)顺序栈相关算法的代码实现
  9. 一、python基本语法元素(温度转换)
  10. linux下dns劫持C语言实现,Linux下实现劫持系统调用的总结(上)--代码及实现
  11. 百度编辑器ueditor获取不到内容?请把form放在table等其他元素最外面
  12. java安装下载步骤_java下载安装教程
  13. Redis实现邮件激活码保存
  14. java的流间隔问题_java – SuperMemo(SM-2)的间隔重复算法
  15. 计算机考研301数学一攻略,国家海洋技术中心
  16. 一种提取HTML网页正文的方法
  17. netstat 的各个 state 什么意思
  18. Android 媒体播放框架MediaSession分析与实践
  19. 以太坊环境以及Solidity学习笔记
  20. MATLAB应用:第二章-基本使用方法

热门文章

  1. 赤峰市田家炳中学2021高考成绩查询,2021年常州各高中高考成绩排名及放榜最新消息...
  2. C++优先级队列priority_queue详解及其模拟实现
  3. 中国科学家完全破解世界级百年数学难题庞加莱猜想
  4. ACM1880魔咒词典
  5. Git报错--Everything up-to-date branch ‘main‘ set up to track ‘origin/main‘.
  6. 陶大程招收博士计算机视觉,回顾优必选AI首席科学家陶大程博士获IEEE ICDM研究贡献奖的相关事件...
  7. Traceback (most recent call last)解决方法
  8. PyQt5 基本语法(一):基类控件
  9. 用计算机在作文格中打单字字,二年级信息技术第3—12课教案
  10. fedora 11源码安装设置fcitx3.6输入法