简要说明:一个简单的串口通信开发实例,仿串口小助手,这里使用的是CC2530开发板,控制led灯,采集光照数据,使用ecilipse java开发;
引用:【赛迪网讯】串口, RS-232-C(又称EIA RS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。RS232是一个全双工的通讯协议,它可以同时进行数据接收和发送的工作。串口是计算机上一种非常通用设备通信的协议。以前,大多数计算机包含两个基于RS232的串口。串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS-232口。同时,串口通信协议也可以用于获取远程采集的数据。
串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。
说到串口,也许很多人都要怀疑,这都什么年代了,USB设备已经如此普及了,谁还能想起这个老掉牙的通信端口呀?其实,在现实生活中,串口正因为它老,才会在实际使用中经常用到它。举个简单的例子:工业制造及其设备与计算机之间的通讯、还有在各种电子工厂测试设备的过程中,都无一例外使用的串口。因为它可以不用像USB设备一样必须有软件驱动的支持才可以进行工作。
一、必要准备
开始之前,你应该有开发板,烧写器,电源,串口线,将这些与你的PC正确连接,打开你的设置里的设备管理器,PC已经检测到你的设备,在端口显示
驱动程序
学习过操作系统设备管理的应该知道驱动程序的功能,每个与你的电脑连接的硬件设备都需要安装使用相应的驱动程序,开发板也不例外,我们这里简单的串口通信开发,使用rs232通用串口线驱动即可:
将这个驱动程序按照提示进行安装,安装完成后,回到设备管理器,右键你的设备,进行更新驱动程序,选择在我电脑查询可用驱动,再安装即可,如果安装成功,这个时候你右键查看设备属性,会显示设备运转正常,说明你的电脑真正连接上了这个开发板;
串口调试小助手
这是我们对开发好的硬件进行调试的简便工具,下图为没有插硬件时的显示,如果上面驱动程序那一步你已经完成,运行串口调试小助手,端口列表里会显示你已经连接好的端口;
驱动包
我们要使用java写与串口通信相关的代码,当然要相关类包,我们有两个选择:第一,SUN在1998年发布的串口通信API:comm2.0.jar(Windows下)、comm3.0.jar(Linux/Solaris)javacomm20-win32.zip包,但这个不建议使用,太老了,光是找这个包你都花好一会;我们用另一个现在最普遍的:RXTXcomm.jar
选择windows64版本下载即可,下载解压完成后
1.将rxtxSerial.dll、rxtxParallel.dll复制到你的java环境的\jre\bin目录下
2.将RXTXcomm.jar复制到\jre\lib\ext目录下,可能还需要把rxtxParallel.dll、rxtxSerial.dll拷贝到:C:\WINDOWS\system32下
注:RXTXcomm.jar可能还需要手动添加到的你的项目里,右键你的项目,照着图片点击添加即可,最后点击apply应用;
一些关于这个包的类以及重要函数参考这篇文章:
java RXTXcomm 串口通信_rxtxcommmdriver-优快云博客
完成这些你就可以进行编码工作了
二、编码实现
原理流程
编码前先要先知道程序是怎样的流程逻辑:
1.首先,你需要调用相应类,来获取端口列表(COMx),然后选择指定端口;
2.设置这个串口的参数:波特率,校验位等,注意设置的参数一定要和你的协调器终端参数一致才能正确发送接收数据;
3.获取串口的输入输出流,这是我们向串口发送数据和接收数据的中介
4.指定你自己的具体工作,比如向串口发送一串数字,使用相应流即可
5.对于串口返回的数据,实现相关线程,在线程里对流进行监听操作即可
具体代码
代码附有详细注释,此代码是仿照串口调试小助手进行开发,仅供参考,因为这只是小项目里的一个主类,里面还有调用其他类的内容,比如,我们进行组网,采集光敏传感器的数据,所以调用了一个处理传感器数据的类,还把采集的数据上传到服务器mysql数据库,也调用了数据库操作类,但关于串口的一些操作基本都在这个类,如果你想用,需要进行相关修改
先看运行后的这个类的界面
这个类的代码:
package text2;
/***************************************
* 此类负责主程序界面
**************************************/
import gnu.io.*;
//图形界面库
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JSplitPane;
//输入输出库
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
//编码类型转换转换库
import javax.xml.bind.DatatypeConverter;
//定时函数库
import java.util.Timer;
import java.util.TimerTask;
import text2.MySQLConnector;
import text2.LoginFrame;
//主界面以及主要事件
public class SerialPortProgram extends JFrame {
//序列化版本
private static final long serialVersionUID = 1L;
//下拉列表框
private JComboBox<String> portComboBox;
//对话框
JDialog dialog;
//定时器
Timer timer;
//勾选框
private JCheckBox checkBox;
//按钮组件
private JButton openButton;//"开"按钮
private JButton closeButton;//"关"按钮
private JButton getDataButton;//"采集数据"按钮
private JButton cleanRecv;//"清空接收"按钮
private JButton openSerial;//"开启串口"按钮
private JButton closeSerial;//"关闭串口"按钮
private JButton exitButton;//"退出程序"按钮
private JButton autoButton;//"自动采集"按钮
private JButton stopButton;//"停止显示"按钮
//文本显示
private JTextField autoTextField;//定时器数据设置
private JTextField sendTextField;//提示区
private JTextArea recvTextArea;//接收区
private JTextArea infoTextArea;//显示串口状态
//标签注释
private JLabel label;
//记录发送指令总次数
private JLabel labelsum;
private int sum = 0;
//串口变量
private SerialPort serialPort;
private OutputStream outputStream;
private InputStream inputStream;
//进度条模块
private String dLight;//数据字符串
private static int dprogressBar;//数据整型
private int percentage;//光照百分比
//构造函数:主界面
public SerialPortProgram() {
setTitle("串口调试小助手");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(520, 400);
//顶部面板(靠左显示)
JPanel topPanel = new JPanel(new BorderLayout());
JPanel topPanelx = new JPanel(new FlowLayout(FlowLayout.LEFT));
JPanel topPanely = new JPanel(new FlowLayout(FlowLayout.RIGHT));
topPanelx.setBackground(new Color(255, 182, 193)); // 设置背景颜色:浅红色
topPanely.setBackground(new Color(255, 182, 193)); // 设置背景颜色:浅红色
topPanel.setPreferredSize(new Dimension(500,50));
JLabel portLabel = new JLabel("选择端口:");
portComboBox = new JComboBox<>();
infoTextArea = new JTextArea(10, 30);
topPanelx.add(portLabel);
topPanelx.add(portComboBox);
infoTextArea.setText("已连接到端口:" + " " + "\n");
infoTextArea.append("波特率:" + " " + "");
infoTextArea.append("数据位:" + " " + " ");
topPanely.add(infoTextArea);
topPanel.add(topPanelx, BorderLayout.WEST);
topPanel.add(topPanely, BorderLayout.EAST);
//左面板(两列比例1:9)
JPanel middlePanel = new JPanel();
middlePanel.setBackground(new Color(144, 238, 144)); // 设置背景颜色:浅绿色
middlePanel.setLayout(new BoxLayout(middlePanel, BoxLayout.Y_AXIS));
JPanel middlePanell = new JPanel(new GridLayout(4, 1));
middlePanell.setBackground(new Color(144, 238, 144)); // 设置背景颜色:浅绿色
JPanel middlePanelr = new JPanel(new GridLayout(4, 1));
middlePanel.setPreferredSize(new Dimension(180, 150));
final JLabel baudRateLabel = new JLabel("波特率:");
final JLabel parityLabel = new JLabel("校验位:");
final JLabel dataBitsLabel = new JLabel("数据位:");
final JLabel stopBitsLabel = new JLabel("停止位:");
final JTextField baudRateTextField = new JTextField("115200");
JComboBox<String> parityComboBox = new JComboBox<>(new String[]{"None", "Odd", "Even"});
final JComboBox<String> dataBitsComboBox = new JComboBox<>(new String[]{"8", "6", "7", "8"});
JComboBox<String> stopBitsComboBox = new JComboBox<>(new String[]{"1", "1.5", "2"});
middlePanell.add(baudRateLabel);
middlePanelr.add(baudRateTextField);
middlePanell.add(parityLabel);
middlePanelr.add(parityComboBox);
middlePanell.add(dataBitsLabel);
middlePanelr.add(dataBitsComboBox);
middlePanell.add(stopBitsLabel);
middlePanelr.add(stopBitsComboBox);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, middlePanell, middlePanelr);
//设置左右两侧的比例
splitPane.setResizeWeight(0.1);
cleanRecv = new JButton("清空接收");
openSerial = new JButton("开启串口");
closeSerial = new JButton("关闭串口");
middlePanel.add(splitPane);
middlePanel.add(openSerial);
middlePanel.add(closeSerial);
middlePanel.add(cleanRecv);
//右面板(接收区)
JPanel eastPanel = new JPanel(new BorderLayout());
eastPanel.setPreferredSize(new Dimension(250, 150));
recvTextArea = new JTextArea(5, 30);
recvTextArea.setEditable(false);
eastPanel.add(new JScrollPane(recvTextArea), BorderLayout.CENTER);
// 底部面板
JPanel bottomPanel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(new Color(144, 238, 144)); // 设置背景颜色:浅绿色
openButton = new JButton("开");
sendTextField = new JTextField(20);
sendTextField.setForeground(Color.RED);
sendTextField.setHorizontalAlignment(JTextField.CENTER);
closeButton = new JButton("关");
getDataButton = new JButton("采集数据");
JPanel buttonPanelx = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JPanel buttonPanely = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttonPanelx.setBackground(new Color(144, 238, 144)); // 设置背景颜色:浅绿色
buttonPanely.setBackground(new Color(144, 238, 144)); // 设置背景颜色:浅绿色
exitButton = new JButton("退出");
checkBox = new JCheckBox("自动清空");
autoButton = new JButton("自动采集");
autoTextField = new JTextField("3000");
label = new JLabel("毫秒");
labelsum = new JLabel("计数:"+"0"+" ");
stopButton = new JButton("停止显示");
autoTextField.setPreferredSize(new Dimension(55, 30));
buttonPanely.add(autoButton);
buttonPanely.add(autoTextField);
buttonPanely.add(label);
buttonPanely.add(stopButton);
buttonPanel.add(openButton);
buttonPanel.add(sendTextField);
buttonPanel.add(closeButton);
buttonPanel.add(getDataButton);
buttonPanelx.add(labelsum);
buttonPanelx.add(checkBox);
buttonPanelx.add(exitButton);
bottomPanel.add(buttonPanel, BorderLayout.NORTH);
bottomPanel.add(buttonPanelx, BorderLayout.EAST);
bottomPanel.add(buttonPanely, BorderLayout.WEST);
// 添加组件到主窗口
getContentPane().setLayout(new BorderLayout());
getContentPane().add(topPanel, BorderLayout.NORTH);
getContentPane().add(middlePanel, BorderLayout.WEST);
getContentPane().add(eastPanel, BorderLayout.CENTER);
getContentPane().add(bottomPanel, BorderLayout.SOUTH);
// 查询可用串口并添加到下拉列表
@SuppressWarnings("unchecked")
Enumeration<CommPortIdentifier> portIdentifiers = CommPortIdentifier.getPortIdentifiers();
while (portIdentifiers.hasMoreElements()) {
CommPortIdentifier portIdentifier = portIdentifiers.nextElement();
if (portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) {
portComboBox.addItem(portIdentifier.getName());
}
}
//开启串口
openSerial.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String selectedPort = (String) portComboBox.getSelectedItem();
if (selectedPort != null) {
CommPortIdentifier portIdentifier = null;
try {
portIdentifier = CommPortIdentifier.getPortIdentifier(selectedPort);
} catch (NoSuchPortException ex) {
ex.printStackTrace();
}
if (portIdentifier != null) {
try {
if (serialPort != null) {
// 关闭串口
serialPort.close();
serialPort = null;
}
// 打开串口
serialPort = (SerialPort) portIdentifier.open(SerialPortProgram.class.getName(), 2000);
int baudRate = Integer.parseInt(baudRateTextField.getText());
int dataBits = Integer.parseInt((String) dataBitsComboBox.getSelectedItem());
// 配置串口参数
serialPort.setSerialPortParams(baudRate, dataBits, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
// 获取串口的输入流和输出流
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
infoTextArea.setText("已连接到端口:" + selectedPort + "\n");
infoTextArea.append("波特率:" + baudRate + " ");
infoTextArea.append("数据位:" + dataBits + " ");
sendTextField.setText("串口已开启");
//led默认初始化为关闭,向串口发送指令6
String data = "6";
outputStream.write(data.getBytes());
MySQLConnector.writeToLedState("off");
//创建一个线程用于实时设置led开关状态
Thread getledstate = new Thread(new getLedState());
getledstate.start();
} catch (PortInUseException | UnsupportedCommOperationException | IOException ex) {
ex.printStackTrace();
}
}
}
}
});
//关闭串口
closeSerial.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
infoTextArea.setText("已连接到端口:" + " " + "\n");
infoTextArea.append("波特率:" + " " + "");
infoTextArea.append("数据位:" + " " + " ");
if (serialPort != null) {
serialPort.close();
serialPort = null;
sendTextField.setText("串口已关闭");
}
}
});
//清空接收区
cleanRecv.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
recvTextArea.setText("");
sendTextField.setText("接收区已清空");
}
});
//停止显示
stopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//关闭定时器
if (timer != null) {
timer.cancel();
}
//关闭对话框
if(dialog != null)
dialog.dispose();
}
});
//退出程序
exitButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//关闭主界面
JFrame thisFrame = (JFrame)SwingUtilities.getWindowAncestor(exitButton);
thisFrame.dispose();
//关闭定时器
if (timer != null) {
timer.cancel();
}
//关闭对话框
if(dialog != null)
dialog.dispose();
//关闭串口,释放资源
if (serialPort != null) {
serialPort.close();
serialPort = null;
}
}
});
//自动采集数据,周期为3s
autoButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (serialPort != null) {
int value = Integer.parseInt(autoTextField.getText());
//调用进度条界面
DataProcess.lightDialog();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (serialPort != null) {
Thread dataCollectionThread = new Thread(new DataCollectionListener());
dataCollectionThread.start();
//判断是否需要自动清空
if (checkBox.isSelected()) {
if (recvTextArea.getLineCount() > 13) {
recvTextArea.setText("");
}
}
//向串口发送光敏传感器16进制数据指令
String datashuju = "07 03 00 2A 00 01 a5 a4";
if (serialPort != null && outputStream != null && !datashuju.isEmpty()) {
try {
// 将字符串转换为字节数组
String[] hexValues = datashuju.split(" ");
byte[] hexData = new byte[hexValues.length];
for (int i = 0; i < hexValues.length; i++) {
hexData[i] = (byte) Integer.parseInt(hexValues[i], 16);
}
outputStream.write(hexData);
sum++;
labelsum.setText("计数:"+decimalToString(sum)+" ");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}, 0, value);
}
}
});
//点击开按钮触发事件函数
openButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (serialPort != null) {
//创建一个线程用于接收串口数据并更新接收区域的显示
Thread receiveThread1 = new Thread(new ReceiveRunnable());
receiveThread1.start();
//向串口发送指令1
String data = "1";
if (serialPort != null && outputStream != null && !data.isEmpty()) {
try {
outputStream.write(data.getBytes());
MySQLConnector.writeToLedState("on");//更新led状态
sum++;
labelsum.setText("计数:"+decimalToString(sum)+" ");
sendTextField.setText("灯亮了");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
});
//点击关按钮触发事件函数
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (serialPort != null && outputStream != null) {
try {
// 创建一个线程用于接收串口数据并更新接收区域的显示
Thread receiveThread2 = new Thread(new ReceiveRunnable());
receiveThread2.start();
//向串口发送指令2
String data = "2";
outputStream.write(data.getBytes());
MySQLConnector.writeToLedState("off");//更新led状态
sum++;
labelsum.setText("计数:"+decimalToString(sum)+" ");
sendTextField.setText("灯灭了");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
});
//"采集数据"按钮的事件处理函数
getDataButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (serialPort != null) {
// 创建一个线程用于接收串口数据并更新接收区域的显示
Thread dataCollectionListener = new Thread(new DataCollectionListener());
dataCollectionListener.start();
//调用进度条界面
DataProcess.lightDialog();
//向串口发送光敏传感器16进制数据指令
String datashuju = "07 03 00 2A 00 01 a5 a4";
if (serialPort != null && outputStream != null && !datashuju.isEmpty()) {
try {
// 将字符串转换为字节数组
String[] hexValues = datashuju.split(" ");
byte[] hexData = new byte[hexValues.length];
for (int i = 0; i < hexValues.length; i++) {
hexData[i] = (byte) Integer.parseInt(hexValues[i], 16);
}
outputStream.write(hexData);
sum++;
labelsum.setText("计数:"+decimalToString(sum)+" ");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
});
setVisible(true);
}
//线程,用于接收并显示串口反馈的信息(字符串)
private class ReceiveRunnable implements Runnable {
@Override
public void run() {
byte[] buffer = new byte[99999];
int len;
try {
//第一次接收协调器控制成功的信息
while ((len = inputStream.read(buffer)) > 0) {
String recvData = new String(buffer, 0, len);
recvTextArea.append(recvData);
}
recvTextArea.append("****");
try {
Thread.sleep(1000); // 暂停
} catch (InterruptedException e) {
e.printStackTrace();
}
//第二次接收终端控制成功并反馈给协调器的信息
while ((len = inputStream.read(buffer)) > 0) {
String recvData = new String(buffer, 0, len);
recvTextArea.append(recvData);
}
recvTextArea.append("");
} catch (IOException e) {
e.printStackTrace();
}
}
}
//线程,根据led实时状态信息调整开关状态
private class getLedState implements Runnable {
@Override
public void run() {
System.out.println("线程开始");
//定时器
Timer timer;
timer = new Timer();
timer.schedule(new TimerTask() {
String state = "off";// 开关状态
@Override
public void run() {
String ledstate = MySQLConnector.getLedState();
//System.out.println("状态:"+ledstate);
if(ledstate.equals("on") && state.equals("off"))
{
String data = "5";
try {
outputStream.write(data.getBytes());
state = "on";
System.out.println("已开启");
} catch (IOException e) {
e.printStackTrace();
}
}else if(ledstate.equals("off") && state.equals("on"))
{
String data = "6";
try {
outputStream.write(data.getBytes());
state = "off";
System.out.println("已关闭");
} catch (IOException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000); // 暂停
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 0, 1000);
}
}
//线程,用于监听采集到的传感器数据信息(16进制)
private class DataCollectionListener implements Runnable {
@Override
public void run() {
//字节数组,存储接收到的信息
byte[] buffer = new byte[8];
int len;
//短暂暂停
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//开始监听数据流
try {
//第一次接收成功向协调器发送后反馈的信息
while ((len = inputStream.read(buffer)) > 0) {
String recvData = new String(buffer, 0, len);
recvTextArea.append(recvData);
//用于两次接收之间的间隔指示
recvTextArea.append("****");
//短暂暂停
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//第二次接收终端的传感器数据信息
while ((inputStream.read(buffer)) > 0) {
// 将字节数组转换为十六进制字符串(调函数)
String hexString = DatatypeConverter.printHexBinary(buffer);
String datashuju = null;
for (int i = 0; i < hexString.length(); i += 2) {
//只显示前7个字节
if(i == 14)
break;
//存储光照数据,直接转化字符串,不可空字符拼接,会触发异常
if(i == 6)
{
dLight = Character.toString(hexString.charAt(i)).concat(Character.toString(hexString.charAt(i + 1)));
}
else if(i == 8)
{
dLight = dLight + Character.toString(hexString.charAt(i)).concat(Character.toString(hexString.charAt(i + 1)));
}
dprogressBar = DataProcess.hexToDecimal(dLight);
//更新进度条
if(dprogressBar >= 0 && dprogressBar <= 1024)
percentage = DataProcess.updateProgressBar(dprogressBar);
//显示光照程度
displayProgress(dprogressBar);
if (i + 1 < hexString.length()) {
char c1 = hexString.charAt(i);
char c2 = hexString.charAt(i + 1);
datashuju = "" + c1 + c2;
recvTextArea.append(datashuju);
recvTextArea.append(" ");
} else {
char c = hexString.charAt(i);
datashuju = "" + c;
recvTextArea.append(datashuju);
recvTextArea.append(" ");
}
}
}
//接收后换行
recvTextArea.append("\n");
}
}catch (IOException e) {
e.printStackTrace();
}
//数据传送到数据库
MySQLConnector.writeToDatabase(percentage);
}
}
//将10进制整数转化为10进制字符串
public static String decimalToString(int decimalValue) {
return String.valueOf(decimalValue);
}
//显示光照程度
public void displayProgress(int dprogressBar) {
int dprogressBar0 = dprogressBar - 460;
if(dprogressBar0 > 0 && dprogressBar0 <= 110)
sendTextField.setText("光照很弱"+":"+decimalToString(percentage)+"%");
if(dprogressBar0 > 110 && dprogressBar0 <= 220)
sendTextField.setText("光照较弱"+":"+decimalToString(percentage)+"%");
if(dprogressBar0 > 220 && dprogressBar0 <= 330)
sendTextField.setText("光照适中"+":"+decimalToString(percentage)+"%");
if(dprogressBar0 > 330 && dprogressBar0 <= 440)
sendTextField.setText("光照较强"+":"+decimalToString(percentage)+"%");
if(dprogressBar0 > 440 && dprogressBar0 <= 600)
sendTextField.setText("光照很强"+":"+decimalToString(percentage)+"%");
}
//main函数
public static void main(String[] args) {
// 获取所有可用的串口端口标识符
@SuppressWarnings("unchecked")
Enumeration<CommPortIdentifier> portIdentifiers = CommPortIdentifier.getPortIdentifiers();
System.out.println("可用的串口端口数量:");
int portCount = 0;
// 遍历每个串口端口标识符并输出端口名称
while (portIdentifiers.hasMoreElements()) {
CommPortIdentifier portIdentifier = (CommPortIdentifier) portIdentifiers.nextElement();
String portName = portIdentifier.getName();
portCount++;
System.out.println("端口 " + portCount + ": " + portName);
}
if (portCount == 0) {
System.out.println("没有可用的串口端口");
}
//此线程创建主界面实例
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
//@SuppressWarnings("unused")
//LoginFrame loginFrame = new LoginFrame();
//进入主程序界面
SerialPortProgram frame = new SerialPortProgram();
frame.setVisible(true);
// 将主界面的初始位置设置在屏幕中央
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int x = (screenSize.width - frame.getWidth()) / 2;
int y = (screenSize.height - frame.getHeight()) / 2;
frame.setLocation(x, y);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
三、注意事项
java版本
一定要注意你的java要和你的设备适配,既不能版本太高,也不能太低,这个问题很恶心,不匹配的话需要重装java环境;
比如,我刚开始用的是1.8.0_181,但会不适配,运行程序会造成java虚拟机崩溃
如下报错:引用:
当更换为1.8.0_231后可以正常运行了
四、最后说明
1.图中的开关按钮是向串口发送指令控制开发板led灯的开关,采集数据是向开发板发送了一串16进制光敏传感器的指令,其本质都是对outputStream流的操作,根据需要可以随意更改;
2.大致仿照程序逻辑即可,删除处理逻辑类和数据库类影响不大,仅供参考;
3.相比串口调试小助手,我们添加一些功能,也删减了一点功能,比如发送区就没有设置,因为在我们开发时,具体向串口发送的指令已经写死了,还有一些功能或者没什么必要了,或者包含在一些其他操作里了;
4.关于硬件的代码,不同设备可能不太一样,这里就不提供了,我使用的CC2530开发,进行Zigbee组网,控制led灯开关以及采集终端光敏传感器的数据,需要注意的就是协调器和终端要和你java里发送的指令数据匹配,对硬件有疑问也可以询问博主;
5.如果你也需要将采集到的数据上传到云端服务器数据库里,可以参考我的另一篇文章:架设阿里云服务器以及数据库;
6.代码有不少冗余,博主在开发后期也仅仅对代码健壮性进行了完善,大家参考大致逻辑原理即可,可以进行代码优化实现;