目录
Modbus/TCP简介
使用Java GUI实现的过程
modsim下载地址:
官网http://www.win-tech.com/html/demos.htm百度网盘(提取码:0x18)http://xn--https-bl8js66z7n7i//pan.baidu.com/s/1W0gS5kOm-X3Fdy7iYQg0cg%20%20%E6%8F%90%E5%8F%96%E7%A0%81%EF%BC%9A
Modbus/TCP简介
????????Modbus/TCP是Modbus的TCP网络协议,TCP网络端口号为502。Modbus/TCP在原有ModBus协议前增加了6个字节的协议头,同时取消了Modbus协议的CRC16校验和。其帧格式如下?
Modbus/TCP协议帧格式
事务标识符 | 协议标识符 | Modbus信文长度 | 从站地址 | 功能码 | 数据 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | 0-248字节 |
使用Java GUI实现的过程
? ? ? ? 这里使用JLibMosbus(JLibModbus下载地址)实现,JLibModbus是Modbus的一个实现,该库包含了ModBus/TCP协议的接口和类等,编写通信程序时可以直接调用。另外该库还封装了流行的通信库(如jSerialComm、RXTXcomm等),编写Modbus串口通信(RTU)时也可使用该库。
? ? ? ? 编写Modbus/TCP通信程序的基本步骤如下:(1)设置TCP参数(使用TcpParameters),可以是本机(127.0.0.1),也可以时远端机,将参数配置为远端机的IP即可;(2)设置TCP端口号为默认端口号(502);(3)创建主机,即Modbus协议中提到的主站,与从站实现通信;(4)建立连接,进行数据的读写。
GUI实现
? ? ? ? 使用swing组件(JButton,JLabel,JTextFiled)来创建界面,创建好的界面如下图:
?实现部分代码:
//按钮
JButton[] btn = new JButton[4];
btn[0] = new JButton("连接");
btn[1] = new JButton("断开");
btn[2] = new JButton("采集数据");
btn[3] = new JButton("更改数据");
btn[0].setBounds(150, 30, 100, 30);
btn[1].setBounds(350, 30, 100, 30);
btn[2].setBounds(130, 190, 120, 30);
btn[3].setBounds(130, 300, 120, 30);
//静态标签
JLabel[] jl = new JLabel[6];
jl[0] = new JLabel("寄存器地址:");
jl[0].setBounds(100, 145, 100, 30);
jl[1] = new JLabel("更改寄存器的地址:");
jl[1].setBounds(50, 255, 160, 30);
jl[2] = new JLabel("采集到的数据:");
jl[2].setBounds(270, 190, 120, 30);
jl[3] = new JLabel("更改后的值为:");
jl[3].setBounds(270, 300, 120, 30);
jl[4] = new JLabel("连接状态:");
jl[4].setBounds(200, 100, 80, 30);
jl[5] = new JLabel("未连接");
jl[5].setForeground(Color.RED);
Font f = new Font("宋体",Font.ITALIC,16);
jl[5].setFont(f);
jl[5].setBounds(280, 100, 100, 30);
//编辑框
JTextField[] jtf = new JTextField[4];
jtf[0] = new JTextField("**");
jtf[1] = new JTextField("**");
jtf[2] = new JTextField("**");
jtf[3] = new JTextField("**");
jtf[0].setBounds(200, 150, 80, 20);//寄存器地址
jtf[1].setBounds(390, 195, 80, 20);//采集到的数据
jtf[2].setBounds(200, 260, 80, 20);//更改寄存器的地址
jtf[3].setBounds(390, 305, 80, 20);//更改后的值
JFrame jf = new JFrame();
jf.setTitle("ModbusTCP_Test");
jf.setLocation(200, 100);
jf.setSize(600, 400);
jf.getContentPane().setBackground(Color.PINK);
jf.setLayout(null);
jf.setVisible(true);
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Font f1 = new Font("宋体",Font.BOLD,16);
for (JButton jButton : btn) {
jf.add(jButton);
jButton.setFont(f1);
}
for (JTextField jTextField : jtf) {
jf.add(jTextField);
jTextField.setFont(f1);
}
for (int i=0;i< jl.length;i++) {
jf.add(jl[i]);
if (i!=5){
jl[i].setFont(f1);
}
}
通信部分实现
? ? ? ? 该部分主要就是给各个按钮添加监听事件(这里使用lambda表达式),当按钮点击时,通过一定的逻辑原理对modSim进行数据的读写操作。
代码实现:
//设置TCP参数
TcpParameters tcpParameters = new TcpParameters();
InetAddress ipAddress = InetAddress.getByName("127.0.0.1");
tcpParameters.setHost(ipAddress);
//设置连接和端口
tcpParameters.setKeepAlive(true);
tcpParameters.setPort(Modbus.TCP_PORT);//使用TCP默认端口502
// 创建主机
ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
Modbus.setAutoIncrementTransactionId(true);
//初始化为未连接
master.disconnect();
int slaveId = 1;//设置从机地址默认为1
btn[0].addActionListener(a -> {
if (a.getActionCommand().equals("连接")) {
if (!master.isConnected()) {
try {
master.connect();//开启连接
jl[5].setText("已连接");
jl[5].setForeground(Color.BLUE);
JOptionPane.showMessageDialog(null,
"连接成功!", "提示", JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
btn[1].addActionListener(a -> {
if (a.getActionCommand().equals("断开")) {
try {
master.disconnect();
jl[5].setText("未连接");
jl[5].setForeground(Color.RED);
JOptionPane.showMessageDialog(null,
"断开连接成功!", "提示", JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
btn[2].addActionListener(a -> {
if (a.getActionCommand().equals("采集数据") && master.isConnected()) {
//获取编辑框中的数据
String readAddress = jtf[0].getText();
int r_address = Integer.parseInt(readAddress);//寄存器读取开始地址,转换为int型
int quantity = 1;//读取的寄存器数量
try {
//读取对应从机的数据,readInputRegisters
int[] registerValues = master.readHoldingRegisters(slaveId, r_address-1, quantity);
//显示在指定组件
for (int value : registerValues) {
jtf[1].setText(String.valueOf(value));
}
} catch (Exception e) {
e.printStackTrace();
}
JOptionPane.showMessageDialog(null, "数据采集成功!",
"提示", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null, "请先进行连接!",
"提示", JOptionPane.ERROR_MESSAGE);
}
});
btn[3].addActionListener(a -> {
if (a.getActionCommand().equals("更改数据") && master.isConnected()) {
String writeAddress = String.valueOf(jtf[2].getText());
int w_address = Integer.parseInt(writeAddress);
int w_data = Integer.parseInt(jtf[3].getText());
try {
master.writeSingleRegister(slaveId, w_address-1, w_data);
} catch (Exception e) {
e.printStackTrace();
}
} else {
JOptionPane.showMessageDialog(null, "请先进行连接!",
"提示", JOptionPane.ERROR_MESSAGE);
}
});
|