C# ModBus Tcp读写数据 与服务器进行通讯
程序员文章站
2022-07-14 09:31:49
...
C# ModBus Tcp读写数据 直接操做PLC寄存器
MODBUS通用数据帧:
测试用modbus服务器下载地址:
https://download.csdn.net/download/weixin_42288222/12457317
代码下载地址:
具体modbus协议见pdf文档这里就不说了(下载包里有)
https://download.csdn.net/download/weixin_42288222/12457342
1.这边使用裸Tcp/ip协议 通过socket发送modbus的通讯报文地址数据等,操作plc寄存器(没有使用别人写好的类库)。
界面如下:
2.TCP部分程序如下: 内联代码片
。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ModbusTcp
{
class TCP
{
public delegate void ChangeFormList(bool change);
public event ChangeFormList ChangeList;
public delegate void TcpStutas(bool change);
public event TcpStutas ReturnFromPLC;
readonly object obj = new object();
public string STR;//接收到的消息
public string SendMsg;
/// <summary>
/// 连接状态:true 连接中 false 连接中断
/// </summary>
public bool isConnected;
Socket socketSend;
public bool Connect(string ip, int port)
{
try
{
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress IP = IPAddress.Parse(ip);
IPEndPoint point = new IPEndPoint(IP, port); ;
socketSend.Connect(point);
isConnected = true;
return true;
}
catch (Exception)
{
MessageBox.Show("请填写正确的IP地址和端口号!");
return false;
}
}
/// <summary>
/// 接收服务端返回的消息
/// </summary>
void Received()
{
try
{
//1M的缓存区
byte[] data = new byte[1024];
//实际接收到的有效字节数
int len = socketSend.Receive(data);// 将接受到的数据存入到输入buffer中
if (len == 0)
{
isConnected = false;
}
int length = data[5];//读取数据长度
Byte[] datashow = new byte[length + 6];//定义所要显示的接收的数据的长度
for (int i = 0; i <= length + 5; i++)//将要显示的数据存放到数组datashow中
datashow[i] = data[i];
string stringdata = BitConverter.ToString(datashow);//把数组转换成16进制字符串
if (data[7] == 0x01) { STR = stringdata; };
if (data[7] == 0x02) { STR = stringdata; };
if (data[7] == 0x03) { STR = stringdata; };//功能码为3
if (data[7] == 0x05) { STR = stringdata; };
if (data[7] == 0x06) { STR = stringdata; };//功能码为6
if (data[7] == 0x0F) { STR = stringdata; };
if (data[7] == 0x10) { STR = stringdata; };
ChangeList(true);
}
catch (Exception ex)
{
MessageBox.Show("接收数据出现异常!" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 向服务器发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Send(byte[] msg)
{
lock (obj)
{
try
{
socketSend.Send(msg);
for (int i = 0; i < msg.Length; i++)
{
SendMsg += msg[i];
}
ReturnFromPLC(true);
Thread.Sleep(10);
Received();
}
catch (Exception ex)
{
MessageBox.Show(" 发送数据出现异常!" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
/// <summary>
/// 16转10进制
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public int GetDex(string msg)
{
int res = Convert.ToInt32(msg, 16);
return res;
}
}
}
3.主界面部分: 内联代码片
。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ModbusTcp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/*具体详见modbus协议中文版.pdf
功能码说明(括号内为对应的16进制):
01(01):byte访问 读线圈
02(02):byte访问 读输入离散量
05(05):byte访问 写单个线圈
15(0F):byte访问 写多个线圈
03(03):16位byte访问 读多个寄存器
04(04):16位byte访问 读输入寄存器
06(06):16位byte访问 写单个寄存器
16(10):16位byte访问 写多个寄存器
23(17):16位byte访问 读/写多个寄存器
22(16):16位byte访问 屏蔽写寄存器
20(14):文件记录访问 读文件记录
21(15):文件记录访问 写文件记录
43(2B):封装接口 读设备识别码
*/
private void button1_Click(object sender, EventArgs e)
{
//连接Tcp服务器
tcp.Connect(textBox1.Text, 502);
}
TCP tcp = new TCP();
private void Form1_Load(object sender, EventArgs e)
{
tcp.ChangeList += new TCP.ChangeFormList(f_ChangeList);//tcp通讯显示发送
tcp.ReturnFromPLC += new TCP.TcpStutas(f_TcpAtutas);//tcp通讯显示返回
}
private void f_TcpAtutas(bool change)
{
Invoke(new Action(() =>{
richTextBox1.Text += tcp.STR + "***" + DateTime.Now.ToString("yyyy/mm/dd HH:mm:ss") + "\r\n";
} ));
}
private void f_ChangeList(bool change)
{
Invoke(new Action(() => {
richTextBox2.Text += tcp.STR + "***" + DateTime.Now.ToString("yyyy/mm/dd HH:mm:ss") + "\r\n";
}));
}
/// <summary>
/// 数据格式:0-6位:报文头;7位:功能码;8-9位:起始地址;10-11位:寄存器位数(读)/写入数据(写)
/// </summary>
byte[] data = new byte[] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x06, 0x00, 0x00, 0x00, 0x01 };
private void button2_Click(object sender, EventArgs e)
{
try
{
data[7] = GetHex(textBox2.Text);
data[11] = GetHex(textBox3.Text);
data[9] = GetHex(textBox4.Text);
tcp.Send(data);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// 10转16
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
private byte GetHex(string msg)
{
byte hex = Convert.ToByte(msg);
return hex;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (tcp.isConnected)
{
button1.Enabled = false;
textBox1.Enabled = false;
}
else
{
button1.Enabled = true;
textBox1.Enabled = true;
}
}
}
}
上一篇: C#串口通信上位机,使用modbus协议
下一篇: C#使用MQTT协议进行开发