C#实现Modbus协议与PLC通信

您所在的位置:网站首页 台达plc C#实现Modbus协议与PLC通信

C#实现Modbus协议与PLC通信

2023-09-27 02:31| 来源: 网络整理| 查看: 265

项目需要用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加载器量程D422PLC数字量D418转速系数D426伺服加速时间D504伺服减速时间D506加减速系数D508

其中,控制电机启停的PLC地址是M30。台达DVP系列PLC中,S, X, D, M等表示PLC装置(应该与PLC内部结构有关??分别代表不同的线圈区域?不是很确定),总之知道地址M30就OK了。 现在去查M30对应的十六进制编码地址是多少,因为用C给PLC发送信号时,需要以十六进制数形式发送。下表来自台达PLC应用手册(厚达743页)中的第161页,可以看出,M30在000~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分别表示从站地址和线圈地址,类型分别为byte和ushort,vlaue为布尔型,其值为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对应的部件 CodeNameTranslationFunctionDescription01Read Coil Status读取线圈状态取得一组逻辑线圈的当前状态(on/off)S, Y, M, T, C02Read Input Status读取输入状态取得一组开关输入的当前状态(on/off)S,X,Y,M,T,C03Read Holding Registers读取保持寄存器在一个或多个保持寄存器中取得当前的二进制值T,C,D05Force Single Coil强制单线圈强制一个逻辑线圈的通断状态S,Y,M,T,C06Preset Signle Register预置单寄存器把具体二进制装入一个保持器T,C,D15Force Multiple Coils强置多线圈强置一串连续逻辑线圈的通断S,Y,M,T,C16Preset Multiple Register预置多寄存器把具体的二进制值装入一串连续的保持T,C,D17Report Slave IDNone DATA(0)~DATA(n-1): 所要发送的数据内容,DATA字符的格式取决于功能码。数据的内容包括n个8位数据,由2n个ASCII码组成(一个8-bit的数据由2个ASCII码表示),n


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3