C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端

这篇具有很好参考价值的文章主要介绍了C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 1、客户端选择

客户端可以是一个程序或一个设备,这里我以C#WINFORM程序来实现客户机与PLC的Modbustcp服务器通信,开发环境是VS2019,.NET Framework版本是4.7.2

2、创建winform程序

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 创建类库

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

编写C#各种类的转换库,该库由我提供,不用操心,文章最后提供。

项目引入这个类库 

 

3、引入Nmodbus4协议

找到项目,找到引用,右键“管理nuget程序”,在下面对话框操作

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 4、界面布局如下:

布局中用到的是下拉框combobox,文本框textbox,按钮button,标签label

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 这个IP地址和端口号是与这里对应

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

5、窗体定义两个变量,并引入对应的命令空间

        ModbusIpMaster master = null;//modbus对象
        TcpClient tcpClient = null;//tcp客户端对象

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

6、连接按钮代码

 private void btnOpen_Click(object sender, EventArgs e)
        {
            string ip = txtIPAddress.Text.Trim();
            bool t = IsIP(ip);
            if (t)
            {
                try
                {
                    int port = int.Parse(txtPort.Text.Trim());
                    tcpClient = new TcpClient();
                    tcpClient.Connect(ip, port);//连接到主机
                    master = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站
                    master.Transport.ReadTimeout = 1000;//读超时
                    master.Transport.WriteTimeout = 1000;//写超时
                    master.Transport.Retries = 3;//尝试重复连接次数
                    master.Transport.WaitToRetryMilliseconds = 200;//尝试重复连接间隔
                    lblMessage.Text = "连接成功!";
                    btnOpen.Enabled = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("连接失败," + ex.Message);
                }
            }
            else
            {
                MessageBox.Show("无效的ip地址!");
            }
        }

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 7、读取的代码--ushort类型

本例子中只用到了读取保存寄存器这个功能码,即ReadHoldingRegisters(从站地址,开始地址,寄存器数量)

  /// <summary>
        /// 读取
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void myread_Click(object sender, EventArgs e)
        {
            //由于NModbus4读取到寄存器的数据都是ushort类型
            //功能码
            string readType = cboReadTypes.Text.Trim();
            //从站地址
            byte slaveAddr = byte.Parse(txtRSlaveId.Text.Trim());
            //开始地址
            ushort startAddr = ushort.Parse(txtRStartAddress.Text.Trim());
            //读取数量
            ushort readCount = ushort.Parse(txtRCount.Text.Trim());
            switch (readType)
            {
                case "读线圈":
                    bool[] blVals = master.ReadCoils(slaveAddr, startAddr, readCount);
                    txtReadDatas1.Text = string.Join(",", blVals.Select(b => b ? "1" : "0"));
                    break;
                case "读输入线圈":
                    bool[] blInputVals = master.ReadInputs(slaveAddr, startAddr, readCount);
                    txtReadDatas1.Text = string.Join(",", blInputVals.Select(b => b ? "1" : "0"));
                    break;
                case "读保持寄存器":
                    //情况1:ushort到ushort类型:即读取无符号的整数,如23,89,处理方法是:原封不动
                    //ushort[] uDatas = master.ReadHoldingRegisters(slaveAddr, startAddr, readCount);
                    //txtReadDatas.Text = string.Join(",", uDatas);

                    //功能码
                    string dataType = cmddatatype.Text.Trim();
                    switch (dataType)
                    {
                        case "ushort":
                            //利用token循环读取
                            ushortctsRead = new CancellationTokenSource();
                            Task.Run(new Action(() =>
                            {
                                ReadUshortFromPLC(slaveAddr, startAddr, readCount);
                            }), ushortctsRead.Token);
                            break;
                        case "short":
                            //利用token循环读取
                            shortctsRead = new CancellationTokenSource();
                            Task.Run(new Action(() =>
                            {
                                ReadShortFromPLC(slaveAddr, startAddr, readCount);
                            }), shortctsRead.Token);
                            break;
                        case "float":
                            //利用token循环读取
                            floatctsRead = new CancellationTokenSource();
                            Task.Run(new Action(() =>
                            {
                                ReadFloatFromPLC(slaveAddr, startAddr, readCount);
                            }), floatctsRead.Token);
                            break;
                    }  
                    break;
                case "读输入寄存器":
                    ushort[] uDatas1 = master.ReadInputRegisters(slaveAddr, startAddr, readCount);
                    txtReadDatas1.Text = string.Join(",", uDatas1);
                    break;
            }
        }

这里要注意,

NModbus4读取到寄存器的数据都是ushort类型

NModbus4读取到寄存器的数据都是ushort类型

代码中用到ReadUshortFromPLC方法,ReadShortFromPLC方法,ReadFloatFromPLC方法在本文最后链接都会提供

运行程序,连接成功,读取数据

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 注意这里,从站地址一般都是1,除非你改了,开始地址是0,表示寄存器的起始地址,数量是3,表示读取3个寄存器数量,也就是前面3个变量,m1-speed,m1-duaror,m1-level

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 这里为什么数量不能是4,因为第4个变量是real,它占2个寄存器,即占4个字节,它不是ushort类型,这里地址也不能是%DB3.DBW4这种写法,这不是S7协议读取变量,是MODBUS读取寄存器,两者不一样的,别糊涂了,各位长老。

8、读取的代码--float类型

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 很多人搞不清楚这个开始地址和数量,这个开始地址是Modbus的地址,Modbus地址编号从0开始,因此8个变量的地址就是0,1,2,3,4,5,6,7,数量是指要读取的寄存器个数,word占一个,real占2个,这里很难理解,比较绕比较晕,一个是PLC地址,一个是MODBUS地址

我们要读的温度是第3个寄存器,它是real类型,占2个寄存器数量

如果要读取“摩头2温度”,怎么读了?

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp 

 大家想想,为什么开始地址是8?

9、写入的代码--ushort类型

 /// <summary>
        /// 写入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnWrite_Click(object sender, EventArgs e)
        {
            //功能码
            string writeType = cboWriteTypes.Text.Trim();
            //从站地址
            byte slaveAddr = byte.Parse(txtWSlaveId.Text.Trim());
            //开始地址
            ushort startAddr = ushort.Parse(txtWStartAddress.Text.Trim());
            //数量
            //实际数量
            string objWriteVals = "";
            string dataType = cmddatatype2.Text.Trim();
            switch (dataType)
            {
                case "ushort":
                    objWriteVals = txtWriteDatas1.Text.Trim();
                    break;
                case "short":
                    objWriteVals = txtWriteDatas2.Text.Trim();
                    break;
                case "float":
                    objWriteVals = txtWriteDatas3.Text.Trim();
                    break;
            }
            ushort writeCount = ushort.Parse(txtWCount.Text.Trim()); 
            ushort objWCount = (ushort)objWriteVals.Split(',').Length;
            //实际数量与要求数量不一致,不允许操作
            if (writeCount != objWCount)
            {
                MessageBox.Show("写入值的数量不正确!");
                return;
            }
            string vals = objWriteVals;
            switch (writeType)
            {
                case "写单线圈":
                    bool blVal = vals == "1" ? true : false;
                    try
                    {
                        master.WriteSingleCoil(slaveAddr, startAddr, blVal);
                        MessageBox.Show("【单线圈】写入成功!");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
                case "写单保持寄存器":
                    ushort uVal01 = ushort.Parse(vals);
                    try
                    {
                        master.WriteSingleRegister(slaveAddr, startAddr, uVal01);
                        MessageBox.Show("【单保持寄存器】写入成功!");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
                case "写多线圈":
                    bool[] blVals = vals.Split(',').Select(s => s == "1" ? true : false).ToArray();//bool数组
                    try
                    {
                        master.WriteMultipleCoils(slaveAddr, startAddr, blVals);
                        MessageBox.Show("【多线圈】写入成功!");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
                case "写多保持寄存器":
                    try
                    {
                        //功能码
                        //string dataType = cmddatatype2.Text.Trim();
                        switch (dataType)
                        {
                            case "ushort":
                                情况1:写入无符号的整数,即写入ushort数据,如写入33,44
                                ushort[] uVals01 = vals.Split(',').Select(s => ushort.Parse(s)).ToArray();
                                master.WriteMultipleRegisters(startAddr, uVals01);
                                break;
                            case "short":
                                //情况2:写入有符号的整数,即写入short数据,如写入-133,-65,98等,处理方法是:short[]=>byte[]=>ushort[],情况2包括了情况1 
                                short[] uVals02 = vals.Split(',').Select(s => short.Parse(s)).ToArray();
                                byte[] y2 = ByteArrayLib.GetByteArrayFromShortArray(uVals02);
                                ushort[] ushorts2 = UShortLib.GetUShortArrayFromByteArray(y2);
                                master.WriteMultipleRegisters(startAddr, ushorts2);
                                MessageBox.Show("【short类型数据】写入成功!");
                                break;
                            case "float":
                                //情况3:写入有符号的小数,即写入float数据,如写入-6.3,-2.65,56.893,51,-465等,处理方法是:float[]=>byte[]=>ushort[],情况3包括了情况2和情况1 
                                float[] uVals03 = vals.Split(',').Select(s => float.Parse(s)).ToArray();
                                byte[] y3 = ByteArrayLib.GetByteArrayFromFloatArray(uVals03);
                                ushort[] ushorts3 = UShortLib.GetUShortArrayFromByteArray(y3);
                                master.WriteMultipleRegisters(startAddr, ushorts3);
                                MessageBox.Show("【float类型数据】写入成功!");
                                break;
                        }



                        情况2:写入有符号的整数,即写入short数据,如写入-133,-65,98等,处理方法是:short[]=>byte[]=>ushort[],情况2包括了情况1 
                        //short[] uVals02 = vals.Split(',').Select(s => short.Parse(s)).ToArray();
                        //byte[] y = ByteArrayLib.GetByteArrayFromShortArray(uVals02);
                        //ushort[] ushorts = UShortLib.GetUShortArrayFromByteArray(y);
                        //master.WriteMultipleRegisters(slaveAddr, startAddr, ushorts);

                        情况3:写入有符号的小数,即写入float数据,如写入-6.3,-2.65,56.893,51,-465等,处理方法是:float[]=>byte[]=>ushort[],情况3包括了情况2和情况1 
                        //float[] uVals02 = vals.Split(',').Select(s => float.Parse(s)).ToArray();
                        //byte[] y = ByteArrayLib.GetByteArrayFromFloatArray(uVals02);
                        //ushort[] ushorts = UShortLib.GetUShortArrayFromByteArray(y);
                        //master.WriteMultipleRegisters(slaveAddr, startAddr, ushorts);

                        MessageBox.Show("【多保持寄存器】写入成功!");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
            }
        }

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 写入成功,同时读取的也是刚才写的值,在博途的监控表中看到

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

10、写入的代码--float类型

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

写入负数

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

 我们向“摩头2温度”这个寄存器写入数据

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

再看博途中的数据

 C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

11、小结

客户端创建tcp client对象,然后modbus利用tcp对象创建modbus通信,然后通过不同数据类型读写PLC数据,成功了

代码链接:

链接:https://pan.baidu.com/s/1aCqv3eSX-7SXAdGtrGNpTw 
提取码:kyqo  

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端,C#上位机开发笔记,c#,服务器,开发语言,tcp client,modbus tcp文章来源地址https://www.toymoban.com/news/detail-668001.html

到了这里,关于C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#通过ModbusTcp协议读写西门子PLC中的浮点数

    MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品,显而易见,它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用用途是为诸如PLC,I/O模块,以及连接其它简单域总线或I/O模块的网关服务的。 Modbus

    2024年02月09日
    浏览(85)
  • 编写C#程序实现和西门子1500PLC进行Modbus Tcp通讯仿真

    前言 本文章的主题是介绍Modbus Tcp通讯仿真,其中C#编写的程序充当客户端(Client),西门子1500PLC充当的服务器端(Server),有关Modbus Tcp协议的具体内容在此也不再赘述,大家可以自行阅读官方文档。 注:在实现其基本功能的条件下,本文的代码编写以及软件配置均简化。

    2024年02月11日
    浏览(68)
  • 西门子PLC1500大型程序fanuc机器人焊装 包括1台 西门子1500PLC程序

    西门子PLC1500大型程序fanuc机器人焊装 包括1台 西门子1500PLC程序,2台触摸屏TP1500程序  9个智能远程终端ET200SP Profinet连接  15个Festo智能模块Profinet通讯  10台Fanuc发那科机器人Profinet通讯  3台G120变频器Profinet通讯  2台智能电能管理仪表PAC3200  4个GRAPH顺控程序  图尔克RFID总线模

    2024年01月18日
    浏览(51)
  • 西门子大型程序fanuc机器人焊装 包括1台 西门子1500PLC程序,2台触摸屏TP1500程序

    西门子大型程序fanuc机器人焊装  包括1台 西门子1500PLC程序,2台触摸屏TP1500程序,9个智能远程终端ET200SP Profinet连接 15个Festo智能模块Profinet通讯 10台Fanuc发那科机器人Profinet通讯 3台G120变频器Profinet通讯 2台智能电能管理仪表PAC3200 4个GRAPH顺控程序 图尔克RFID总线模组通讯 和ME

    2024年02月02日
    浏览(48)
  • 西门子PLC S7-1500系列CPU与西门子PLC S7-300系列的通讯模块CP343-1进行TCP通讯的方法

    西门子PLC S7-1500系列是西门子新一代PLC产品,它通过多方面的创新,为用户提供了更高性价比的产品,提高了用户的工程实施效率。西门子PLC S7-1500为用户在自动化控制系统中提供了更高的运行能力,而且简单易用,节省了大量的系统开发时间,西门子PLC S7-1500系列有很强的通

    2023年04月08日
    浏览(98)
  • 使用IOT-Tree Server连接西门子PLC S7-300/1200/1500

    IOT-Tree Server是个开源物联网软件,可以作为组态软件成为自动化系统的上位软件。她提供了接入、数据组织管理、控制逻辑和人机交互多个方面的功能。从版本0.99开始,IOT-Tree Server新增了西门子以太网驱动,能够通过以太网的方式直接访问S7-300/1200/1500. S7-200 smart好像也支持

    2024年02月03日
    浏览(60)
  • 西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一)

    第一部分:组态配置 具体步骤可参考以下内容 : 如下图所示,新建一个项目后,添加一个安全型PLC,这里以1516F-3 PN/DP为例进行说明, 如下图所示,添加CPU完成后,可以看到左侧的项目树中比普通的PLC多了几个选项和模块, 如下图所示,我们选中该CPU后进入属性画面,在“

    2024年02月06日
    浏览(86)
  • 使用浏览器访问西门子S7-1200PLC_Web服务器设置

    平常都是用触摸屏或者上位机监控在线查看PLC的数据,在西门子S7-1200中,可以使用博途配置web服务器,通过浏览器进行登录,访问PLC的运行状态及需要监控的数据信息。 打开博途,新建一个项目,选择一个常用的PLC型号,进入编程界面,上述步骤不再赘述;右击mian,点击属

    2024年02月16日
    浏览(97)
  • C#和西门子PLC使用Udp通信

    目录 一、PLC程序工程创建 1、硬件配置 2、程序编程 3、添加监控表 二、C#程序工程创建 1、界面UI 2、代码编写 (1)创建本地Udp (2)读PLC的线程函数 (3)定时器 (4)上位机写寄存器操作 (5)StringToByte()方法封装 (6)窗口关闭 3、C#和PLC测试 (1)C#上位机写操作1 (2)C#上位

    2024年02月04日
    浏览(45)
  • C#上位机与西门子PLC数据交互

    拉了换一个简单的界面 我新建了一个DB数据块【DB1】,右键【DB1】,点击【属性】项,【优化的块访问】默认是勾选,要想显示数据块中地址偏移量,需要把【优化的块访问】勾选取消 1、右键项目名,选择图中【管理NuGet程序包】 2、在搜索框输入【S7netplus】,我安装的是第

    2024年02月13日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包