帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端
发布时间:2024-03-10 19:26:49   分类:帮助文档
C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端  1、客户端选择 客户端可以是一个程序或一个设备,这里我以C#WINFORM程序来实现客户机与PLC的Modbustcp服务器通信,开发环境是VS2019,.NET Framework版本是4.7.2 2、创建winform程序  创建类库   编写C#各种类的转换库,该库由我提供,不用操心,文章最后提供。 项目引入这个类库    3、引入Nmodbus4协议 找到项目,找到引用,右键“管理nuget程序”,在下面对话框操作  4、界面布局如下: 布局中用到的是下拉框combobox,文本框textbox,按钮button,标签label  这个IP地址和端口号是与这里对应   5、窗体定义两个变量,并引入对应的命令空间         ModbusIpMaster master = null;//modbus对象         TcpClient tcpClient = null;//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地址!"); } }  7、读取的代码--ushort类型 本例子中只用到了读取保存寄存器这个功能码,即ReadHoldingRegisters(从站地址,开始地址,寄存器数量) /// /// 读取 /// /// /// 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方法在本文最后链接都会提供 运行程序,连接成功,读取数据  注意这里,从站地址一般都是1,除非你改了,开始地址是0,表示寄存器的起始地址,数量是3,表示读取3个寄存器数量,也就是前面3个变量,m1-speed,m1-duaror,m1-level  这里为什么数量不能是4,因为第4个变量是real,它占2个寄存器,即占4个字节,它不是ushort类型,这里地址也不能是%DB3.DBW4这种写法,这不是S7协议读取变量,是MODBUS读取寄存器,两者不一样的,别糊涂了,各位长老。 8、读取的代码--float类型  很多人搞不清楚这个开始地址和数量,这个开始地址是Modbus的地址,Modbus地址编号从0开始,因此8个变量的地址就是0,1,2,3,4,5,6,7,数量是指要读取的寄存器个数,word占一个,real占2个,这里很难理解,比较绕比较晕,一个是PLC地址,一个是MODBUS地址 我们要读的温度是第3个寄存器,它是real类型,占2个寄存器数量 如果要读取“摩头2温度”,怎么读了?    大家想想,为什么开始地址是8? 9、写入的代码--ushort类型 /// /// 写入 /// /// /// 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; } }  写入成功,同时读取的也是刚才写的值,在博途的监控表中看到 10、写入的代码--float类型   写入负数  我们向“摩头2温度”这个寄存器写入数据 再看博途中的数据   11、小结 客户端创建tcp client对象,然后modbus利用tcp对象创建modbus通信,然后通过不同数据类型读写PLC数据,成功了 代码链接: 链接:https://pan.baidu.com/s/1aCqv3eSX-7SXAdGtrGNpTw  提取码:kyqo  
香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价