C#实现Modbus协议与PLC通信

项目需要用C#写一个上位机,用Modbus/TCP协议与PLC通信,控制伺服电机的启停、转速等。D:\Code\C#\ConsoleApp1

1. 获取PLC的IP地址

待续。。。

2.

“启动”的代码如下,btn_stop_Click 是“启动”这个按钮对应的响应函数,启动一个新线程,实际的代码在StopEnginer函数中实现

        private void btn_stop_Click(object sender, EventArgs e) //控制电机停止
        {
            r_timer.Stop();
            t_timer.Stop();
            Thread t = new Thread(StopEnginer) { IsBackground = true };
            t.Start();
        }
private void StopEnginer()
        {
            string cmd_str = "0105081E0000";
            //01从站地址salve address
            //05功能码 写入单个线圈函数WriteSingleCoil(开源通讯库Nmodbus)
            //Nmodbus 地址https://github.com/NModbus/NModbus
            //081E是写入单个线圈地址,参考台达PLC应用手册161页DVP装置通讯地址和x工给的excel表
            //081E = M30是控制启停的地址
            //0000后四位是写入的值
            // string cmd_str = (tbx_cmdString.Text).ToUpper();

            ushort[] returnValues = new ushort[30];
            //将字符串cmd_str切割成地址、功能码、写入地址、写入值
            byte address = Convert.ToByte(cmd_str.Substring(0, 2), 16);
            byte Function = Convert.ToByte(cmd_str.Substring(2, 2), 16);
            ushort start = Convert.ToUInt16(cmd_str.Substring(4, 4), 16);
            ushort values = Convert.ToUInt16(cmd_str.Substring(8, 4), 16);
            Console.WriteLine("这是故障台停止程调用");
            try
            {
                bool value_TrueOrFalse = Convert.ToUInt16(values) == 0xFF00;
           
                //调用WriteSingleCoil函数
                master.WriteSingleCoil(address, start, value_TrueOrFalse);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

代码解释如下,需要Modbus协议、PLC通信协议的相关知识,以及PLC地址表。项目用的PLC型号为台达DELTA DVP系列

1. PLC地址表

名称对应的台达DVP系列PLC地址
转速设定D520
扭矩设定D502
实时转速D46
实时扭矩D26
启停M30
扭力计量程D410
转速量程D414
加载器量程D422
PLC数字量D418
转速系数D426
伺服加速时间D504
伺服减速时间D506
加减速系数D508

其中,控制电机启停的PLC地址是M30。台达DVP系列PLC中,S, X, D, M等表示PLC装置(应该与PLC内部结构有关??分别代表不同的线圈区域?不是很确定),总之知道地址M30就OK了。
现在去查M30对应的十六进制编码地址是多少,因为用C给PLC发送信号时,需要以十六进制数形式发送。下表来自台达PLC应用手册(厚达743页)中的第161页,可以看出,M30000~255这一区域,该区域的编码以十六进制08开头,进一步,30的十六进制为1e,所以,PLC地址M30的十六进制地址是0x081e,其中0x表示十六进制。类似的,256~511这一区域的地址,其编码以十六进制09开头,256~511分别对应0x00 ~ 0xFF。例如,M267,它的十六进制地址计算方式为 :267-256=11,11的十六进制为0b,因此M267的十六进制地址为0x090b
在这里插入图片描述
本项目PLC与上位机的通讯用到了一个开源通讯库NModbus ,下载地址https://github.com/NModbus/NModbus。该通信库官方提供的手册NModbus
在VS2017中,可以通过以下方式下载安装:
在这里插入图片描述
在这里插入图片描述

下载后,在相应的处理业务的类中定义成员变量

private NModbus.IModbusMaster master;

建立连接,用NModbus.ModbusFactory.CreateMaster创建主站,返回IModbusMaster类对象,对PLC地址的读写主要通过该类提供的方法实现

    public bool connect(string ip,int port)
    {
        if (hasConnected) return true;
       
        var tcp=new TcpClient();
        var result=tcp.BeginConnect(ip,port,null,null);
        result.AsyncWaitHandle.WaitOne(5000);
        if (result.IsCompleted)
        {
            var factory = new NModbus.ModbusFactory();
            master = factory.CreateMaster(tcp);
            hasConnected = true;
        }
        else
        {
            throw new TimeoutException("连接超时!");
        }
        return hasConnected;
    }

之后,调用IModbusMaster的成员函数就可以通信了,可以看到IModbusMaster 的部分常用API函数如下。
在这里插入图片描述
本例中,将使用WriteSingleCoil函数往M30地址中写入数据,控制电机的启动和停止。WriteSingleCoil的函数原型为void WriteSingleCoil(byte slaveAddress, ushort coilAddress, bool value);,三个参数,slaveAddress,coilAddress分别表示从站地址和线圈地址,类型分别为byteushortvlaue为布尔型,其值为trueorfalse。给PLC的M30地址发送信号启动电机的代码如下。

public void start() //给PLC的M30地址发送信号启动电机
    {
        check();
        byte slaveAddress = 1; //单元标识符
        ushort coilAddress = 0x81e; //起始地址
        bool value = true;
        master.WriteSingleCoil(slaveAddress, coilAddress, value);
        // void WriteSingleCoil(byte slaveAddress, ushort coilAddress, bool value);函数原型
    }

2. DELTA DVP系列PLC通信协议详解

翻译自 DELTA DVP系列PLC官方文档
通信数据框架(Communication Data Frame)如下:
在这里插入图片描述
解释如下:

  • STX:起始字符,为 “:”
  • ADR1 和 ADR0: 通信地址,由2个ASCII码组成,有效的通信地址范围为0…31。
  • CMD1和CMD0:命令码,由2个ASCII码组成,用来告诉PLC该执行什么任务。该系列PLC的命令码取了Modbus协议的部分功能码,Modbus协议如下表所示。完整的Modbus协议见xxxx。表中的Description 是PLC对应的部件
CodeNameTranslationFunctionDescription
01Read Coil Status读取线圈状态取得一组逻辑线圈的当前状态(on/off)S, Y, M, T, C
02Read Input Status读取输入状态取得一组开关输入的当前状态(on/off)S,X,Y,M,T,C
03Read Holding Registers读取保持寄存器在一个或多个保持寄存器中取得当前的二进制值T,C,D
05Force Single Coil强制单线圈强制一个逻辑线圈的通断状态S,Y,M,T,C
06Preset Signle Register预置单寄存器把具体二进制装入一个保持器T,C,D
15Force Multiple Coils强置多线圈强置一串连续逻辑线圈的通断S,Y,M,T,C
16Preset Multiple Register预置多寄存器把具体的二进制值装入一串连续的保持T,C,D
17Report Slave IDNone
  • DATA(0)~DATA(n-1): 所要发送的数据内容,DATA字符的格式取决于功能码。数据的内容包括n个8位数据,由2n个ASCII码组成(一个8-bit的数据由2个ASCII码表示),n<=37,因此DATA最大可包含74个ASCII码

例子:Reading Coils T20~T27 from slave device 01,从从站设备地址01开始读取线圈T20-T27中的内容,一共8个字节(8 words)
PC发给PLC的代码
PC→PLC “:01 03 06 14 00 08 DA CR LF”
代码解析如下:

Field NameExample(Hex)
Heading3A
Slave Address01
Command code03
Starting Address Hi06
Starting Address Lo14
Number of Points Hi00
Number of points Lo08
Error Check (LRC)DA
End character 1CR
End character 2LF

PLC发送给PC的代码:
:01 03 10 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 B8 CR LF
代码解析如下:

Field NameExample(Hex)
Slave Address01
Command code03
Bytes Count10
Data Hi(T20)00
Data Lo (T20)01
Data Hi (T21)00
Data Lo (T21)02
Data Hi (T22)00
Data Lo (T22)03
Data Hi (T23)00
Data Lo (T23)04
Data Hi (T24)00
Data Lo (T24)05
Data Hi (T25)00
Data Lo (T25)06
Data Hi (T26)00
Data Lo (T26)07
Data Hi (T27)00
Data Lo (T27)08
Error Check (LRC)C8

LRC(Longitudinal Redundancy Check)纵向冗余度检查,

DELTA DVP系列的PLC的设备地址

  • 22
    点赞
  • 180
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
使用C#读取三菱PLC的步骤如下: 1. 了解MODBUS协议 MODBUS是一种通信协议,用于在工业自动化和控制系统中进行通信。它可以通过串行或以太网连接进行通信,并且可以在不同类型的设备之间传输数据。要使用MODBUS协议与三菱PLC通信,需要了解PLC的寄存器映射和MODBUS协议的数据结构。 2. 安装MODBUS库 在C#中使用MODBUS协议需要使用第三方库。有许多开源库可供选择,例如NModbus、EasyModbus等。可以使用NuGet包管理器来安装这些库。 3. 设置MODBUS连接 在C#中使用MODBUS库时,需要设置与PLC的连接。这包括PLC的IP地址、端口号、设备地址等。可以使用库中提供的类来设置连接。 4. 读取PLC寄存器 一旦连接设置完成,就可以读取PLC的寄存器了。可以使用库中提供的函数来读取寄存器,例如ReadInputRegisters、ReadHoldingRegisters等。读取的数据可以存储在一个数组中,然后可以在程序中使用。 下面是一个使用NModbus库读取三菱PLC的示例代码: ```csharp using System; using Modbus.Data; using Modbus.Device; using System.Net.Sockets; namespace ModbusTest { class Program { static void Main(string[] args) { // 设置连接 TcpClient client = new TcpClient("192.168.1.1", 502); ModbusIpMaster master = ModbusIpMaster.CreateIp(client); // 读取寄存器 ushort startAddress = 0; ushort numRegisters = 10; ushort[] registers = master.ReadHoldingRegisters(1, startAddress, numRegisters); // 显示读取的数据 for (int i = 0; i < numRegisters; i++) { Console.WriteLine("Register {0}: {1}", startAddress + i, registers[i]); } // 关闭连接 client.Close(); } } } ``` 在这个例子中,我们使用了NModbus库来读取三菱PLC的保持寄存器。我们设置了PLC的IP地址为192.168.1.1,端口号为502。然后,我们读取了从第0个保持寄存器开始的10个寄存器,并将读取的数据存储在一个数组中。最后,我们遍历数组并将每个寄存器的值打印到控制台上。 请注意,此示例仅适用于保持寄存器。如果要读取其他类型的寄存器(例如输入寄存器),则需要使用不同的函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值