欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C# ModBus Tcp读写数据 与服务器进行通讯

程序员文章站 2022-07-14 09:31:49
...

C# ModBus Tcp读写数据 直接操做PLC寄存器

MODBUS通用数据帧:
C# ModBus Tcp读写数据 与服务器进行通讯C# ModBus Tcp读写数据 与服务器进行通讯测试用modbus服务器下载地址:
https://download.csdn.net/download/weixin_42288222/12457317
C# ModBus Tcp读写数据 与服务器进行通讯
代码下载地址:

具体modbus协议见pdf文档这里就不说了(下载包里有)
C# ModBus Tcp读写数据 与服务器进行通讯
https://download.csdn.net/download/weixin_42288222/12457342

1.这边使用裸Tcp/ip协议 通过socket发送modbus的通讯报文地址数据等,操作plc寄存器(没有使用别人写好的类库)。

界面如下:
C# ModBus Tcp读写数据 与服务器进行通讯
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;
            }
        }
    }
}