我是靠谱客的博主 忧伤煎饼,最近开发中收集的这篇文章主要介绍C#实现Modbus协议与PLC通信1. 获取PLC的IP地址2.,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

项目需要用C#写一个上位机,用Modbus/TCP协议与PLC通信,控制伺服电机的启停、转速等。D:CodeC#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的设备地址

最后

以上就是忧伤煎饼为你收集整理的C#实现Modbus协议与PLC通信1. 获取PLC的IP地址2.的全部内容,希望文章能够帮你解决C#实现Modbus协议与PLC通信1. 获取PLC的IP地址2.所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部