0

0

0

修罗

站点介绍

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

Modbus仿真工具,NModbus4使用

修罗 2023-02-04 1226 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)


最新评论

  • https://www.studyglobus.com/author/carroll34a5552/

    Ценники на вывоз мусора сейчас космос, любые лайфхаки по экономии в тему.

  • Richardgrold

    1xbet onlayn kazino platforması ilə vaxtınızı daha səmərəli və maraqlı keçirin. Saytın canlı kazino bölməsi istifadəçilərə fərqli bir dünya təklif edir. Burada canlı dilerli kazino oyunlarının hər bir növünü sınaqdan keçirə bilərsiniz. Krupyelərin peşəkarlığı oyunun dinamikasını və marağını artırır. Müntəzəm olaraq yenilənən oyun siyahısı cansıxıcılığa yol vermir. Hesabınızı artırmaq üçün onlarla fərqli və etibarlı üsul mövcuddur. Qazanılan pullar cəmi bir neçə dəqiqə ərzində şəxsi hesabınıza köçürülür. Aktiv fəaliyyətinizə görə fərdi bonuslar və hədiyyələr qazana bilərsiniz. Dəstək xidməti həm çat, həm də e-poçt vasitəsilə kömək göstərir. 1xbet ailəsinə qoşulun və böyük uduşlar üçün ilk addımı atın. onlayn kazino

  • 砂岩白丘

    我一直梦想, 看到你们相册那样的地方。真棒。

  • 城市地標

    我喜欢, 这里分享真实经验。你的项目 就是 属于这里的。请继续。

  • 宗教地標

    我热爱这样的想法, 去那么多国家。真的很鼓舞。

  • 觀景高地

    能感受到热爱。继续保持 感受。

  • 最佳季節

    我关注这样的资源, 写得很实在。你的网站 就是 属于这里的。加油。

  • 1

    1

  • 1

    1

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

    1

日历

2026年07月

   1234
567891011
12131415161718
19202122232425
262728293031 

文章目录

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