0

0

0

修罗

站点介绍

只有了解事实才能获得真正的自由

Modbus仿真工具,NModbus4使用

修罗 2023-02-04 1003 0条评论 c#

首页 / 正文

Modbus协议

Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,可以实现控制器相互之间、控制器经由网络和真实设备之间的通信。

它是一种Master/Slave协议,它并不关心是谁与谁在通信。

Modbus特点

  • 标准开放、公开发表、无版税要求、无许可证费(没有费用);
  • 支持多种电气接口(RS232、RS422、RS485、RJ45);各种介质传输(双绞线、网线),支持串口、网口;
  • 格式简单、紧凑、通俗易懂,容易上手(好用) ;

提前准备仿真工具

Modbus Slave 从机模拟软件,用于开发和调试;
Modbus Poll 主机模拟软件;
Configure Virtual Serial Port Driver 虚拟串口端口软件;

  • 启动虚拟串口助手

image-20230203162826851.png

  • 添加端口

image-20230203162910755.png

  • 启动主从机

image-20230203163022811.png

  • 从机连接串口(先连接从机)

image-20230203163159339.png

  • 从机连接成功

image-20230203163241891.png

  • 主机连接串口

image-20230203163321967.png

  • 主机连接成功

image-20230203163346790.png

通过c#连接

  • 关闭仿真工具的主机连接,使用c#代码替代仿真工具的主机连接

image-20230204165335861.png

SerialPort对象

System.IO.Ports命名空间,表示串行端口资源。

new SerialPort(portName, baudRate, parity, dataBits, stopBits);

SerialPort参数

BaudRate: 波特率,传输速率一般为9600

PortName: 端口名

Parity: 奇偶校验位

DataBits: 数据位,实际数据位,一般用8位

StopBits: 停止位

  • 一般记住9600-N-8-1即可,9600波特率,N无检验位,8位数据位,1位停止位。

NModbus

  • NModbus:是Modbus协议的C#实现。提供与Modbus从站兼容设备和应用程序的连接。支持ASCII、RTU、TCP和UDP协议。
  • NModbus4: 一个github的开源实现类库,是NModbus的一个分支。
  • 地址:https://github.com/NModbus4/NModbus4

相关读写方法: 每个方法都有各自的异步方法实现。

bool[] ReadCoils  读线圈                   01
bool[]ReadInputs  读输入线圈                 02
ushort[] ReadHoldingRegisters 读保持寄存器    03
ushort[] ReadInputRegisters  读输入寄存器       04
void WriteSingleCoil               写单线圈     05
void WriteSingleRegister        写单保存寄存器    06
void WriteMultipleCoils           写多线圈        15
void  WriteMultipleRegisters    写多保持寄存器      16
ushort[] ReadWriteMultipleRegisters  读写多个保持寄存器  23

NModbus4使用方式

  1. 将NModbus4类库导入项目中(可直接在Nuget中搜索到并安装到当前项目中)
  2. 引用命名空间
  3. 开始使用
  • 串口通信

     1)创建SerialPort对象,配置相关参数,打开串口
     2)调用相应方法创建Modbus主站对象(RTU、ASCII)
     3) 配置参数
     4)调用相关方法执行操作
  • 网口通信

      1) 定义IP地址、端口号,创建TcpClient/UdpClient  
      2) 建立与远程的连接
      3)创建Modbus 主站对象(IP)
      4)配置相关参数
      5)调用相关方法执行操作

    打开连接

// 串口
SerialPort port = null;
// 串口通信主站
ModbusSerialMaster serialMaster = null;
// 网口通信主站
ModbusIpMaster ipMaster = null;
// 串口通信主站和网口通信主站都实现了的接口
IModbusMaster master = null;
bool isRTU= true;

// 1. 串口
port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);//创建串口
if(port != null) {
    port.Open();
    // RTU主站
    if (isRTU)
        serialMaster = ModbusSerialMaster.CreateRtu(port);
    else
        // Ascii
        serialMaster = ModbusSerialMaster.CreateAscii(port);
    master = serialMaster;

}

// 2. TCP网口
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(192.168.1.100, 8000);//连接到主机
ipMaster = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站
master = ipMaster;

// 3. UDP
UdpClient udpClient = new UdpClient();
udpClient.Connect(192.168.1.100, 8000);//连接到主机
ipMaster = ModbusIpMaster.CreateIp(udpClient);//Ip 主站
master = ipMaster;

关闭连接

if(port!=null&&port.IsOpen) port.Close();//关闭串口连接
// client是上面的tcp或udp连接
else if(client!=null &&client.Connected)
{
    client.Close();
}
master.Dispose();
lblMessage.Text = "关闭成功!";

数据

寄存器: 存储数据的容器,寄存器有多个,每个寄存器有编号,用寄存器地址区分不同的寄存器;

存储区对象类型寄存器地址访问类型(针对程序)说明
离散量输入线圈单个bit10001至19999只读I/O系统提供这种类型数据
线圈单个bit00001至09999读写通过应用程序改变这种类型数据
输入寄存器16-位字30001至39999只读I/O系统提供这种类型数据
保持寄存器16-位字40001至49999读写通过应用程序改变这种类型数据

功能码:向服务器指示将执行哪种操作:位、字、双字;

image-20230204172239538.png

  • 仿真工具主站功能设置,一一对应

在菜单栏setUp -- Read Write Definition打开:

image-20230204172606457.png

注意:主从站读写时,线圈寄存器应一一对应,线圈对应线圈,寄存器对应寄存器,否则无法读写;

数据读取

image-20230204173408351.png

在从站对应的读取

image-20230204173653233.png

private void btnRead_Click(object sender, EventArgs e)
{
    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);
            // 将读取到的blVals元素,true改为1,false改为0,再转成字符串以","连接
            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;
    }
}

数据写入

  • 写单线圈

image-20230204174448811.png

private void btnWrite_Click(object sender, EventArgs e)
{
    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;
    }
}
  • 写单保持寄存器

image-20230204174739004.png

  • 写多线圈

image-20230204174941283.png

评论(0)


最新评论

  • 1

    1

  • 1

    1

  • -1' OR 2+158-158-1=0+0+0+1 or 'TKCTZnRa'='

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • @@5Qa2D

    1

  • 1

    1

  • 1

    1

日历

2025年09月

 123456
78910111213
14151617181920
21222324252627
282930    

文章目录

推荐关键字: Linux webpack js 算法 MongoDB laravel JAVA jquery javase redis