Java和51单片机串口通信(Java发送数据到单片机,单片机反馈数据到电脑)
Java发送字符串到单片机,单片机返回给电脑
—————————————————————————————————-
材料:
1. 51单片机
2. Java客户端
3. Keil程序
—————————————————————————————————-
一、单片机程序
在Keil中新建工程,编写程序,生成 .hex 文件(这个文件可以烧录到单片机中)
/* 串口通信: 1、由PC机通过串行口向单片机发送数据,这个数据是存放在单片机的接收缓冲器SBUF中的; 2、单片机将串行口中的数据存放在一个临时变量中; 3、单片机将存放在临时变量中的数据发送到发送缓冲器SBUF中,在PC机上显示。 */ #include <reg52.h> #define u16 unsigned int #define u8 unsigned char // 串行口通信初始化函数 void StartInit() { /* 1、确定T1的工作方式(编程TMOD寄存器):因为串行口中断是由定时器T1决定的, 所以,低四位全部为0,高四位中,GATE=0,C/T非=0,选择工作方式1(8位的自动重装载),即M1M0=10 所以是:00100000,转成十六进制数是:0x20 */ TMOD=0x20; /* 2、计算T1的初值,装载TH1、TL1:使用工具生成,设置参数,定时器方式:方式2;晶振频率:12Mhz; 波特率:4800;SMOD:波特率倍增位,1,即增加1倍;计算结果是:F3H 所以TH1=0xF3,TL1=0xF3,自动重装载 */ TH1=0xF3; TL1=0xF3; /* PCON:与串行口工作相关的参数,只有一位SMOD(最高位),在串行口方式1、方式2、方式3时, 波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0, 这里波特率提高一倍,所以SMOD=1,即10000000,转成十六进制数字是:0x80 */ PCON=0x80; /* 4、启动T1(编程TCON中的TR1位):TR1=1时,定时器T1才开始启动 */ TR1=1; /* 5、确定串行口控制(编程SCON寄存器):选择工作方式1(10位异步收发器,8位数据,1位起始位,1位停止位), 所以SM0=0,SM1=1;不需要RB8控制RI的激活(就是为了简单),设置SM2=0(SM2是多机通信控制位); REN,允许串行接收位,启动串行口接收数据,REN=1; TB8,RB8,TI,RI均为0(看资料),所以是:01010000,转成十六进制数是:0x50 */ SCON=0x50; /* 6、中断位的开启,总中断允许位EA=1;串行口中断允许位ES=1 */ EA=1; ES=1; } // 主函数 void main() { StartInit(); // 串行口通信初始化 while(1); // 等待数据的发送和接收 } // 发送或接收完一帧数据引起中断,串行口中断函数 void Start() interrupt 4 { u8 receiveData; // 用一个变量存放数据 receiveData=SBUF; // 从单片机的接收缓冲器中获取数据 RI=0; // 当数据接收完成后,由内部硬件将RI置1,所以这里需要把RI置0,等待下一次继续接收数据 SBUF=receiveData; // 把变量中的数据放到发送缓冲器中,向PC机发送数据 while(!TI); // 当数据发送完成后(即串行口在发送停止位时,由内部硬件将TI置1,所以数据发送完成时TI=1) TI=0; // 数据发送完成时,要将TI置0,等待下一次继续发送数据 }
二、使用USB线连接电脑和单片机(或使用RS232/RS485 + MAX232),下载程序到单片机
三、编写Java端程序
下载串口通信的 Jar 包, RXTXcomm.jar,下载地址:https://files.cnblogs.com/files/Dreamer-1/mfz-rxtx-2.2-20081207-win-x64.zip
这个文件夹里面需要注意两点:jar包RXTXcomm需要导入到java工程里面去。另外就是需要将rxtxParallel.dll与rxtxSerial.dll复制在安转JDK的bin文件下和jre的bin文件夹下面,这样才能保证能够正常使用这个jar包。以下是将两个dll文件复制的位置
新建Java工程:这里只是做一个测试,没有考虑代码的结构
package com.lvshitech.java51; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; public class Tools { /*类方法 不可改变 不接受继承 * 扫描获取可用的串口 * 将可用串口添加至list并保存至list */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static final ArrayList<String> uartPortUseAblefind() { //获取当前所有可用串口 //由CommPortIdentifier类提供方法 Enumeration<CommPortIdentifier> portList=CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList=new ArrayList(); //添加并返回ArrayList while(portList.hasMoreElements()) { String portName=portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /* * 串口常见设置 * 1)打开串口 * 2)设置波特率 根据单板机的需求可以设置为57600 ... * 3)判断端口设备是否为串口设备 * 4)端口是否占用 * 5)对以上条件进行check以后返回一个串口设置对象new UARTParameterSetup() * 6)return:返回一个SerialPort一个实例对象,若判定该com口是串口则进行参数配置 * 若不是则返回SerialPort对象为null */ public static final SerialPort portParameterOpen(String portName,int baudrate) { SerialPort serialPort=null; try { //通过端口名识别串口 CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); //打开端口并设置端口名字 serialPort和超时时间 2000ms CommPort commPort=portIdentifier.open(portName,1000); //进一步判断comm端口是否是串口 instanceof if(commPort instanceof SerialPort) { System.out.println("该COM端口是串口!串口名称是:" + portName); //进一步强制类型转换 serialPort=(SerialPort)commPort; //设置baudrate 此处需要注意:波特率只能允许是int型 对于57600足够 //8位数据位 //1位停止位 //无奇偶校验 serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); //串口配制完成 log System.out.println("串口参数设置已完成,波特率为"+baudrate+",数据位8bits,停止位1位,无奇偶校验"); } else { //不是串口 System.out.println("该com端口不是串口,请检查设备!"); //将com端口设置为null 默认是null不需要操作 } } catch (NoSuchPortException e) { e.printStackTrace(); } catch (PortInUseException e) { e.printStackTrace(); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); } return serialPort; } /* * 串口数据发送以及数据传输作为一个类 * 该类做主要实现对数据包的传输至下单板机 */ /* * 上位机往单板机通过串口发送数据 * 串口对象 seriesPort * 数据帧:dataPackage * 发送的标志:数据未发送成功抛出一个异常 */ public static void uartSendDatatoSerialPort(SerialPort serialPort,byte[] dataPackage) { OutputStream out=null; try { out=serialPort.getOutputStream(); out.write(dataPackage); out.flush(); } catch (IOException e) { e.printStackTrace(); } finally { //关闭输出流 if(out!=null) { try { out.close(); out=null; //System.out.println("数据已发送完毕!"); } catch (IOException e) { e.printStackTrace(); } } } } /* * 上位机接收数据 * 串口对象seriesPort * 接收数据buffer * 返回一个byte数组 */ public static byte[] uartReceiveDatafromSingleChipMachine(SerialPort serialPort) { byte[] receiveDataPackage=null; InputStream in=null; try { in=serialPort.getInputStream(); // 获取data buffer数据长度 int bufferLength=in.available(); while(bufferLength!=0) { receiveDataPackage=new byte[bufferLength]; in.read(receiveDataPackage); bufferLength=in.available(); } } catch (IOException e) { e.printStackTrace(); } return receiveDataPackage; } public static void main(String[] args) throws Exception { // 打开串口 SerialPort serialPort = portParameterOpen("COM3", 4800); // 要发送的数据 String dataSend = "【Java和51单片机串口通信测试,我能吞下玻璃而不伤身体!】"; int i=1; while(true) { // 发送数据到单片机 byte []datByte = dataSend.getBytes(); uartSendDatatoSerialPort(serialPort, datByte); System.out.println("-------------------------------------------------------"); System.out.println((i++) + ". 发送到串口的数据:" + dataSend); // 休眠300ms,等待单片机反应 Thread.sleep(500); // 从单片机接收到的数据 byte[] dat = uartReceiveDatafromSingleChipMachine(serialPort); if(dat != null && dat.length > 0) { String dataReceive = new String(dat, "GB2312"); System.out.println((i++) + ". 从串口接收的数据:" + dataReceive); } else { System.out.println("接收到的数据为空!"); } } } }
四、测试
插上USB,右键“我的电脑” – “管理” – “设备管理器” – “端口”,可以看到单片机的串口号
(1)打开单片机
(2)运行Java程序
以上实现了Java和单片机的串口通信,扩展:
(1)控制单片机的功能模块,比如 LED灯的亮灭,蜂鸣器,跑马灯,数码管,电机转动等等。
(2)在(1)的基础上,使用Web工程做其他扩展实验,通过点击页面的按钮。
(3)点击单片机上的按钮,向电脑串口(Java端)发送数据,在页面上显示数据。
(4)使用C或者GUI开发客户端进行(1)(2)(3)的实验,还可以进行饼图、柱状图、折线图等形式展现数据规律。