NModbus4通信库使用
1.创建主站
串口 RTU 、ASCII
网口 TCP、 UDP
2.读寄存器:保持寄存器、线圈、输入线圈、输入寄存器
3.写寄存器:写入单线圈、单保持寄存器;写多线圈、多保持寄存器

NModbus4读取的都是无符号整数
如何读取浮点数?
直接存储浮点数会占用两个寄存器,4个字节,比较占空间
保持寄存器,一个寄存器是两个字节
为了节省空间
把浮点数按整数存进去,只占一个寄存器,读出来再转成浮点数
先乘以10的倍数,再除10的倍数
比如保留2位小数,先*100,再/100
TCP 对应TCPClient客户端连接 与socket是什么关系?
如果只是为了数据传输,传输层的用TCPClient就可以,它是在socket基础之上进行的一个封装
TCP是可信连接,更多的使用
UDP是基于数据报的不可靠的传输,只管传,不管错误率的问题

1、添加NModbus4包
一、程序创建3中主站 方式
1、创建串口对象实例: 端口号、波特率、校验位,数据位,停止位
port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);//创建串口
创建主站,两种通讯方式RTU和Ascii
//串口主站 if (isRTU) serialMaster = ModbusSerialMaster.CreateRtu(port); else serialMaster = ModbusSerialMaster.CreateAscii(port);
2、TCP主站
TcpClient tcpClient = new TcpClient(); tcpClient.Connect(ip, port);//连接到主机 ipMaster = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站
3、UDP主站
UdpClient udpClient = new UdpClient(); udpClient.Connect(ip, port);//连接到主机 ipMaster = ModbusIpMaster.CreateIp(udpClient);//Ip 主站
二、工具测试TCP主从站通讯
TCPIP主站

从站

三、程序替代工具主站实现通讯
关闭modubus Poll工具
连接程序


输入线圈和输入寄存器是只读的
离散量输入,bit读取,按位,一个位就是一个线圈状态值
输入寄存器 16-位字,两个字节,一个寄存器就是两个字节
一个字节可以存8个位

创建一个线圈,可以读写

读写线圈可以是单个也可以多个
四、读操作

1、bool[] ReadCoils 读线圈 01
输入型一般是按一个按钮的操作
读取参数:从站地址、开始地址、数量(寄存器最多2000个)

2、bool[]ReadInputs 读输入线圈 02
只读线圈,不能改
一般是设备的启停状态、继电器的状态
3、ushort[] ReadHoldingRegisters 读保持寄存器 03
4、ushort[] ReadInputRegisters 读输入寄存器 04
输入的都是只读的
五、写操作

1、void WriteSingleCoil 写单线圈 05
2、void WriteSingleRegister 写单保存寄存器 06
3、void WriteMultipleCoils 写多线圈 15
4、void WriteMultipleRegisters 写多保持寄存器 16
5、ushort[] ReadWriteMultipleRegisters 读写多个保持寄存器 23
六、注意:
报错1:0x01(Illegal Function):非法功能。这表示从站设备不支持主站设备请求的功能码。

一个是输入线圈01,一个是输入寄存器03
主从站的寄存器地址不匹配,F=要相等
修改主站读取方式为01,与从站相同
从站地址也必须相同

7、读写冲突处理
使用计时器处理,读有个状态标识,写也有个状态标识
写之前,要先把读的线程给停止掉,false
不控制好就会卡死
不基于UI的,要基于线程或服务的
完整代码
using Modbus.Device; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO.Ports; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WinUpperCourse { public partial class Form1 : Form { public Form1() { InitializeComponent(); } SerialPort port = null; ModbusSerialMaster serialMaster = null;//串口主站 ModbusIpMaster ipMaster = null;//网口主站 IModbusMaster master = null;//主站接口 TcpClient client = null; private void Form1_Load(object sender, EventArgs e) { //串口对象 9600-N-8-1 cboConnWays.SelectedIndex = 0;//默认串口 //初始化串口设置 { string[] ports = SerialPort.GetPortNames();//当前计算机串口数组 cboPorts.Items.AddRange(ports);//初始化端口列表 cboPorts.SelectedIndex = 0; //初始化波特率 CommUtility.LoadCboBaudRates(cboBaudRates); //数据位 CommUtility.LoadCboDataBits(cboDataBits); //校验位 CommUtility.LoadCboParitys(cboPrarity); //停止位 CommUtility.LoadStopBits(cboStopBIts); rbtnRTU.Checked = true; //Modbus服务器初始化 //txtIPAddress.Text = CommUtility.GetLocalIP(); txtIPAddress.Text = "192.168.50.116"; txtPort.Text = "502"; rbtnIPv4.Checked = true; } } private void btnOpen_Click(object sender, EventArgs e) { //创建主站 if (cboConnWays.SelectedIndex == 0)//串口 { //校验位 Parity parity = CommUtility.GetParity(cboPrarity); //停止位 StopBits stopBits = cboStopBIts.Text == "1" ? StopBits.One : StopBits.Two; //端口 string portName = cboPorts.Text.Trim(); //波特率 int baudRate = int.Parse(cboBaudRates.Text); //数据位 int dataBits = int.Parse(cboDataBits.Text); bool isRTU = true; if (rbtnASCII.Checked) isRTU = false; port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);//创建串口 if (port != null) { port.Open(); //主站 if (isRTU) serialMaster = ModbusSerialMaster.CreateRtu(port); else serialMaster = ModbusSerialMaster.CreateAscii(port); master = serialMaster; } } //TCP else if (cboConnWays.SelectedIndex == 1) { string ip = txtIPAddress.Text.Trim(); int port = int.Parse(txtPort.Text.Trim()); TcpClient tcpClient = new TcpClient(); tcpClient.Connect(ip, port);//连接到主机 ipMaster = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站 master = ipMaster; } //UDP else if (cboConnWays.SelectedIndex == 2) { string ip = txtIPAddress.Text.Trim(); int port = int.Parse(txtPort.Text.Trim()); UdpClient udpClient = new UdpClient(); udpClient.Connect(ip, port);//连接到主机 ipMaster = ModbusIpMaster.CreateIp(udpClient);//Ip 主站 master = ipMaster; } lblMessage.Text = "连接成功!"; } private void btnRead_Click(object sender, EventArgs e) { try { string readType = cboReadTypes.Text.Trim(); //从站地址 byte slaveAddr = byte.Parse(txtRSlaveId.Text.Trim()); //开始地址 ushort startAddr = ushort.Parse(txtRStartAddress.Text.Trim()); //读取数量 ushort readCount = ushort.Parse(txtCount.Text.Trim()); switch (readType) { case "读线圈": bool[] blVals = master.ReadCoils(slaveAddr, startAddr, readCount); txtReadDatas.Text = string.Join(",", blVals.Select(b => b ? "1" : "0")); break; case "读输入线圈": bool[] blInputVals = master.ReadInputs(slaveAddr, startAddr, readCount); txtReadDatas.Text = string.Join(",", blInputVals.Select(b => b ? "1" : "0")); break; case "读保持寄存器": ushort[] uDatas = master.ReadHoldingRegisters(slaveAddr, startAddr, readCount); txtReadDatas.Text = string.Join(",", uDatas); break; case "读输入寄存器": ushort[] uDatas1 = master.ReadInputRegisters(slaveAddr, startAddr, readCount); txtReadDatas.Text = string.Join(",", uDatas1); break; } } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnWrite_Click(object sender, EventArgs e) { try { string writeType = cboWriteTypes.Text.Trim(); string vals = txtRegisterWVals.Text.Trim(); //从站地址 byte slaveAddr = byte.Parse(txtWSlaveId.Text.Trim()); //开始地址 ushort startAddr = ushort.Parse(txtWStartAddress.Text.Trim()); switch (writeType) { case "写单线圈": bool blVal = vals == "1" ? true : false; master.WriteSingleCoil(slaveAddr, startAddr, blVal); break; case "写单保持寄存器": ushort uVal01 = ushort.Parse(vals); master.WriteSingleRegister(slaveAddr, startAddr, uVal01); break; case "写多线圈": bool[] blVals = vals.Split(',').Select(s => s == "1" ? true : false).ToArray();//bool数组 master.WriteMultipleCoils(slaveAddr, startAddr, blVals); break; case "写多保持寄存器": ushort[] uVals02 = vals.Split(',').Select(s => ushort.Parse(s)).ToArray(); master.WriteMultipleRegisters(slaveAddr, startAddr, uVals02); break; } } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnClose_Click(object sender, EventArgs e) { if (port != null && port.IsOpen) port.Close();//关闭串口连接 else if (client != null && client.Connected) { client.Close(); } master.Dispose(); lblMessage.Text = "连接已关闭!"; } } }
浙公网安备 33010602011771号