|
先上两个通用Modbus帮助类,下面这个是多线程不安全版,在多线程多电机同一端口通信下,可能造成步进电机丢步或者输出口无响应等,还有个多线程安全版,只是基于这个不安全版加上了LOCK,THIS- using Modbus.Device;
- using Sunny.UI;
- using System;
- using System.IO.Ports;
- using System.Linq;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;<br><br>namespace SunnyUI_NuclearForm
- {
- /// <summary>
- /// Modbus通用帮助类
- /// </summary>
- public class ModbusHelper : IDisposable
- {<br><br> IModbusMaster master;<br><br> //串口通信
- SerialPort serialPort;<br><br> //网口-TCP
- TcpClient tcpClient;<br><br> //网口-套接字(备用)
- Socket socket;<br><br>
- //private static readonly object threadObj = new object();//线程安全锁<br><br> //ManualResetEvent manualEvent = new ManualResetEvent(true);//true运行,false不运行<br><br>
- #region connection<br><br> /// <summary>
- /// 串口连接
- /// </summary>
- /// <returns></returns>
- public bool ConnectForSerialPort(string com, int baudRate)
- {
- bool result = false;<br><br> if (!string.IsNullOrWhiteSpace(com) && baudRate > 0)
- {
- serialPort = new SerialPort();<br><br> serialPort.PortName = com;
- serialPort.BaudRate = baudRate;<br><br> //下面三个参数看情况要不要开放
- serialPort.DataBits = 8;
- serialPort.StopBits = StopBits.One;
- serialPort.Parity = Parity.None;<br><br> try
- {
- if (!serialPort.IsOpen)
- {
- serialPort.Open();
- }<br><br>
- master = ModbusSerialMaster.CreateRtu(serialPort);
- master.Transport.ReadTimeout = 3 * 1000;//读 超时时间
- master.Transport.WriteTimeout = 3 * 1000;//写 超时时间
- master.Transport.Retries = 20;//重试次数
- master.Transport.WaitToRetryMilliseconds = 3 * 1000;//重试间隔<br><br> result = true;
- }
- catch (Exception e)
- {
- //打开失败
- LogHelper.Error($"串口无法连接!COM:{com},波特率:{baudRate}。以下为详细信息:\r\n{e.Message}");
- result = false;
- }
- }
- return result;
- }<br><br> /// <summary>
- /// 网口TCP连接
- /// </summary>
- /// <param name="ip"></param>
- /// <returns></returns>
- public bool ConnectForTCP(string ip, int port)
- {
- bool result = false;
- if (!string.IsNullOrWhiteSpace(ip) && port > 0)
- {
- try
- {
- tcpClient = new TcpClient(ip, port);
- if (tcpClient.Connected)
- {
- master = ModbusIpMaster.CreateIp(tcpClient);<br><br> master.Transport.ReadTimeout = 3 * 1000;//读 超时时间
- master.Transport.WriteTimeout = 3 * 1000;//写 超时时间
- master.Transport.Retries = 20;//重试次数
- master.Transport.WaitToRetryMilliseconds = 3 * 1000;//重试间隔<br><br> result = true;
- }
- else
- {
- LogHelper.Error($"网口无法连接!IP:{ip},端口:{port}。\r\n");
- result = false;
- }
- }
- catch (Exception e)
- {
- LogHelper.Error($"网口无法连接!IP:{ip},端口:{port}。以下为详细信息:\r\n{e.Message}");
- return false;
- }<br><br> }
- return result;<br><br> }<br><br> /// <summary>
- /// Socket连接(备用)
- /// </summary>
- /// <param name="ip"></param>
- /// <param name="port"></param>
- /// <returns></returns>
- public bool ConnectForSocket(string ip, int port)
- {
- bool result = false;
- if (!string.IsNullOrWhiteSpace(ip) && port > 0)
- {
- //部分硬件,用TCP发指令没响应,但是用Socket可以,不知道是没支持好TCP还是没支持好Modbus
- //所以在此留下备用通信方法 <br><br> socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);<br><br> try
- {
- socket.Connect(IPAddress.Parse(ip), port);
- result = true;<br><br> }
- catch (Exception e)
- {
- //连接失败
- LogHelper.Error($"Socket(备用)无法连接!IP:{ip},端口:{port}。以下为详细信息:\r\n{e.Message}");
- result = false;
- }<br><br> }
- return result;
- }<br><br> #endregion<br><br> #region send<br><br> /// <summary>
- /// 向串口发送数据 Modbus报文(字节)
- /// </summary>
- public void SendSerialByte(byte[] arr)
- {
- //this.manualEvent.WaitOne();//等待
- //lock (threadObj)
- //{
- //this.manualEvent.Reset();//红灯<br><br> if (serialPort != null && serialPort.IsOpen && arr != null && arr.Count() > 0)
- {
- serialPort.DiscardInBuffer();
- serialPort.DiscardOutBuffer();<br><br> Thread.Sleep(50);<br><br> serialPort.Write(arr, 0, arr.Length);<br><br> Thread.Sleep(50);//写入读取命令后延时读取 或者跟下一条命令之间产生间隔<br><br> try
- {
- // 接收来自读取命令的数据 广播命令执行完毕不响应
- //byte[] receiveData = new byte[1024];
- //int bytesRead = serialPort.Read(receiveData, 0, receiveData.Length);<br><br> if (serialPort.BytesToRead > 0)
- {
- var result = serialPort.ReadExisting();
- }<br><br> }
- catch (Exception e)
- {<br><br> }<br><br> }<br><br> //this.manualEvent.Set();//绿灯
- //}
- }<br><br> /// <summary>
- /// 向串口发送数据 Modbus报文(字符串)
- /// </summary>
- public string SendSerialString(string str)
- {
- string result = string.Empty;<br><br> //this.manualEvent.WaitOne();//等待<br><br> //lock (threadObj)
- //{
- //this.manualEvent.Reset();//红灯
- if (serialPort != null && serialPort.IsOpen && !string.IsNullOrWhiteSpace(str))
- {<br><br> serialPort.DiscardInBuffer();
- serialPort.DiscardOutBuffer();<br><br> Thread.Sleep(50);<br><br> serialPort.Write(str);<br><br> Thread.Sleep(50);//写入读取命令后延时读取 或者跟下一条命令之间产生间隔<br><br> try
- {
- // 接收来自读取命令的数据 广播命令执行完毕不响应
- if (serialPort.BytesToRead > 0)
- {
- result = serialPort.ReadExisting();
- }
- }
- catch (Exception e)
- {<br><br> }<br><br> }
- //this.manualEvent.Set();//绿灯
- //}
- return result;
- }<br><br> /// <summary>
- /// 向网口发送数据 Modbus报文
- /// </summary>
- /// <param name="arr"></param>
- public void SendTCPByte(byte[] arr)
- {
- if (arr != null && arr.Count() > 0 && tcpClient.Connected)
- {
- // 获取网络流
- NetworkStream stream = tcpClient.GetStream();<br><br> //tcpClient.Client.Send(arr);
- stream.Write(arr, 0, arr.Length);
- //Thread.Sleep(50);//写入读取命令后延时读取 或者跟下一条命令之间产生间隔<br><br> try
- {
- // 接收来自读取命令的数据 广播命令执行完毕不响应
- byte[] receiveData = new byte[1024];
- int bytesRead = stream.Read(receiveData, 0, receiveData.Length);
- }
- catch (Exception)
- {<br><br> throw;
- }<br><br> }<br><br>
- }<br><br> /// <summary>
- /// 向网口发送数据 Modbus报文(Socket备用)
- /// </summary>
- /// <param name="arr"></param>
- public void SendSocketByte(byte[] arr)
- {
- if (arr != null && arr.Count() > 0 && socket.Connected)
- {
- socket.Send(arr);
- //Thread.Sleep(50);//写入读取命令后延时读取 或者跟下一条命令之间产生间隔<br><br> try
- {
- // 接收来自读取命令的数据 广播命令执行完毕不响应
- byte[] buffer = new byte[1024];
- int byteRead = socket.Receive(buffer);
- }
- catch (Exception)
- {<br><br> throw;
- }<br><br>
- }
- }<br><br> #endregion<br><br> #region read<br><br>
- /// <summary>
- /// 读取单个线圈 Modbus 01功能码
- /// </summary>
- /// <param name="slaveAddress">从站号</param>
- /// <param name="StartAddress">开始读取的寄存器地址</param>
- /// <param name="numberOfPoints">读取数据个数</param>
- /// <returns></returns>
- public bool[] ReadCoils_01(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
- {
- return master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
- }<br><br> /// <summary>
- /// 读取离散/输入线圈 Modbus 02功能码
- /// </summary>
- /// <param name="slaveAddress">从站号</param>
- /// <param name="StartAddress">开始读取的寄存器地址</param>
- /// <param name="numberOfPoints">读取数据个数</param>
- /// <returns></returns>
- public bool[] ReadInputs_02(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
- {
- return master.ReadInputs(slaveAddress, startAddress, numberOfPoints);
- }<br><br> /// <summary>
- /// 读取保持型寄存器 Modbus 03功能码
- /// </summary>
- /// <param name="slaveAddress">从站号</param>
- /// <param name="StartAddress">开始读取的寄存器地址</param>
- /// <param name="numberOfPoints">读取数据个数</param>
- /// <returns></returns>
- public ushort[] ReadHoldingRegisters_03(byte slaveAddress, ushort StartAddress, ushort numberOfPoints)
- {<br><br> try
- {
- ushort[] Uvalue = master.ReadHoldingRegisters(slaveAddress, StartAddress, numberOfPoints);<br><br> //ushort 转short
- //short[] value = new short[Uvalue.Length];
- //for (int i = 0; i < Uvalue.Length; i++)
- //{
- // if (Uvalue[i] > short.MaxValue)
- // {
- // value[i] = (short)(Uvalue[i] - 65536);
- // }
- // else
- // {
- // value[i] = (short)Uvalue[i];
- // }
- //}<br><br> return Uvalue;
- }
- catch (Exception e)
- {
- return null;
- }<br><br> }<br><br> /// <summary>
- /// 读取输入寄存器 Modbus 04功能码
- /// </summary>
- /// <param name="slaveAddress">从站号</param>
- /// <param name="StartAddress">开始读取的寄存器地址</param>
- /// <param name="numberOfPoints">读取数据个数</param>
- /// <returns></returns>
- public ushort[] ReadInputRegisters_04(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
- {<br><br> try
- {
- ushort[] Uvalue = master.ReadInputRegisters(slaveAddress, startAddress, numberOfPoints);<br><br> //ushort 转short<br><br> //short[] value = new short[Uvalue.Length];
- //for (int i = 0; i < Uvalue.Length; i++)
- //{
- // if (Uvalue[i] > short.MaxValue)
- // {
- // value[i] = (short)(Uvalue[i] - 65536);
- // }
- // else
- // {
- // value[i] = (short)Uvalue[i];
- // }<br><br>
- //}<br><br> return Uvalue;
- }
- catch (Exception e)
- {
- return null;
- }<br><br> }<br><br>
- #endregion<br><br> #region write<br><br> /// <summary>
- /// 写单个线圈 Modbus 05功能码
- /// </summary>
- /// <param name="slaveAddress"></param>
- /// <param name="coilAddress"></param>
- /// <param name="value"></param>
- public void WriteSingleCoil_05(byte slaveAddress, ushort coilAddress, bool value)
- {<br><br> master.WriteSingleCoil(slaveAddress, coilAddress, value);<br><br> }<br><br> /// <summary>
- /// 写单个保持寄存器 Modbus 06功能码
- /// </summary>
- /// <param name="slaveAddress"></param>
- /// <param name="registerAddress"></param>
- /// <param name="value"></param>
- public void WriteSingleRegister_06(byte slaveAddress, ushort registerAddress, ushort value)
- {<br><br> try
- {
- //short 转 ushort<br><br> //ushort Uvalue;
- //if (value < 0)
- //{
- // Uvalue = (ushort)(ushort.MaxValue + value + 1);
- //}
- //else
- //{
- // Uvalue = (ushort)value;
- //}
- master.WriteSingleRegister(slaveAddress, registerAddress, value);
- }
- catch (Exception e)
- {
- return;
- }<br><br>
- }<br><br><br><br> /// <summary>
- /// 写多个寄存器 Modbus 10功能码
- /// </summary>
- /// <param name="slaveAddress"></param>
- /// <param name="startAddress"></param>
- /// <param name="data"></param>
- public void WriteMultipleRegisters_10(byte slaveAddress, ushort startAddress, ushort[] data)
- {
- try
- {
- master.WriteMultipleRegisters(slaveAddress, startAddress, data);
- //master.WriteMultipleRegistersAsync(slaveAddress, startAddress, data);
- }
- catch (Exception e)
- {<br><br> }<br><br><br><br>
- }<br><br> #endregion<br><br> #region 鸣志伺服-多线程不安全模式<br><br> // 设置加减速,减速度,速度 数值1-10k/分钟
- public void SetAccelerationSpeedDeceleration(byte slaveAddr, ushort acceleration, ushort deceleration, ushort speed)
- {
- ushort parametersAddress = 344;<br><br> ushort[] parameters = new ushort[6];
- parameters[0] = 0;
- parameters[1] = acceleration;
- parameters[2] = 0;
- parameters[3] = deceleration;
- parameters[4] = 0;
- parameters[5] = speed;<br><br> WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);
- }<br><br> /// <summary>
- /// 读取伺服电机加速度减速度速度
- /// </summary>
- /// <param name="slaveAddr"></param>
- /// <returns></returns>
- public ushort[] ReadAccelerationSpeedDeceleration(byte slaveAddr)
- {
- ushort[] result = new ushort[3];
- ushort[] speedArr = ReadHoldingRegisters_03(slaveAddr, 344, 6);
- if (speedArr != null && speedArr.Length >= 6)
- {
- //AC 加速度 344+1
- //DC 减速度 346+1
- //VE 速度 348+1
- result[0] = speedArr[1];
- result[1] = speedArr[3];
- result[2] = speedArr[5];
- }
- return result;
- }<br><br> // 设置距离 数值1-100/圈
- public void Distance(byte slaveAddr, long distance)
- {<br><br> ushort parametersAddress = 350;
- ushort[] parameters = new ushort[1];
- parameters[0] = (ushort)distance;<br><br> WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);<br><br> }<br><br> // 设置距离 脉冲数
- public void DistanceForPulse(byte slaveAddr, int pulse)
- {
- string convert = pulse.ToString("X").PadLeft(8, '0'); //转十六进制然后八位补零<br><br> var sendByte = new byte[] {
- slaveAddr,
- 0X10, 0x01, 0x5E, 0x00, 0x02 ,0x04 ,
- Convert.ToByte(convert.Substring(0, 2), 16),
- Convert.ToByte(convert.Substring(2, 2), 16),
- Convert.ToByte(convert.Substring(4, 2), 16),
- Convert.ToByte(convert.Substring(6, 2), 16)};<br><br> var crc = CRC16.CRC16Calc(sendByte);
- var newSend = sendByte.Concat(crc).ToArray();<br><br> SendSerialByte(newSend);<br><br>
- }<br><br>
- //Modbus 寄存器表中寄存器40125被定义为操作码寄存器,向40125寄存器写入相应的操作码,即执行相应操作码的动作
- //FL 0x66
- //SK 0xE1
- //SO 0x8B<br><br> /// <summary>
- /// 电机旋转运行到指定距离 (执行相对移动命令,移动距离和方向来自最后一个DI命令 按给定长度进至距离)
- /// </summary>
- /// <param name="slaveAddr"></param>
- public void Opcode_FL(byte slaveAddr)
- {
- ushort operationCodeAddress = 124;
- byte opCode = 0x66;<br><br> WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);
- }<br><br> /// <summary>
- /// 强制停止
- /// </summary>
- /// <param name="slaveAddr"></param>
- public void Opcode_SK(byte slaveAddr)
- {
- ushort operationCodeAddress = 124;
- byte opCode = 0xE1;
- WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);
- }<br><br> ///// <summary>
- ///// 强制停止-带缓冲
- ///// </summary>
- ///// <param name="slaveAddr"></param>
- //public void Opcode_SKD(byte slaveAddr)
- //{
- // ushort operationCodeAddress = 124;
- // byte opCode = 0xE2;
- // master.WriteSingleRegister(slaveAddr, operationCodeAddress, opCode);
- //}<br><br> /// <summary>
- /// 报警清除
- /// </summary>
- /// <param name="slaveAddr"></param>
- public void Opcode_AX(byte slaveAddr)
- {
- ushort operationCodeAddress = 124;
- byte opCode = 0xBA;
- WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);
- }<br><br>
- //1 0x31 数字量输入/输出端口1
- //2 0x32 数字量输入/输出端口2
- //3 0x33 数字量输入/输出端口3
- //4 0x34 数字量输入/输出端口4
- //5 0x35 数字量输入/输出端口5
- //6 0x36 数字量输入/输出端口6
- //7 0x37 数字量输出端口7
- //8 0x38 数字量输出端口8
- //9 0x39 数字量输出端口9
- //L 0x4C 低电平(光耦导通)
- //H 0x48 高电平(光耦断开)<br><br> /// <summary>
- /// Y口输出 L 0x4C H 0x48
- /// </summary>
- /// <param name="slaveAddr"></param>
- public void Opcode_SO(byte slaveAddr, byte ioPoint, byte condition)
- {
- ushort operationCodeAddress = 124;
- byte operationCode = 0x8B;<br><br> ushort[] operationCodeParameters = new ushort[3];
- operationCodeParameters[0] = operationCode;
- operationCodeParameters[1] = ioPoint;
- operationCodeParameters[2] = condition;<br><br> WriteMultipleRegisters_10(slaveAddr, operationCodeAddress, operationCodeParameters);<br><br>
- }<br><br> /// <summary>
- /// X口输入 ,0触碰1断开
- /// </summary>
- /// <param name="slaveAddr"></param>
- public string Opcode_IS(byte slaveAddr)
- {
- string result = string.Empty;
- try
- {
- ushort inputPortAddress = 5;
- ushort numberRegisters = 1;<br><br> ushort[] data = ReadHoldingRegisters_03(slaveAddr, inputPortAddress, numberRegisters);
- if (data != null && data.Count() > 0)
- {
- result = Convert.ToString(data[0], 2).PadLeft(12, '0');//转2进制,然后12位补零;
- }
- }
- catch (Exception)
- {<br><br> throw;
- }
- return result;
- }<br><br> /// <summary>
- /// 伺服使能
- /// </summary>
- /// <param name="slaveAddr"></param>
- /// <returns></returns>
- public void Opcoded_ME(byte slaveAddr)
- {
- ushort operationCodeAddress = 124;
- byte opCode = 0x9F;
- WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);
- }<br><br> /// <summary>
- /// 伺服使能关闭
- /// </summary>
- /// <param name="slaveAddr"></param>
- /// <returns></returns>
- public void Opcoded_MD(byte slaveAddr)
- {
- ushort operationCodeAddress = 124;
- byte opCode = 0x9E;
- WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);
- }<br><br> //以下单独设置参数,在不知道其他参数,不改动其他参数的时候使用(备用)<br><br> // 设置加速度
- public void Acceleration(byte slaveAddr, ushort acceleration)
- {
- ushort parametersAddress = 344;<br><br> ushort[] parameters = new ushort[2];
- parameters[0] = 0;
- parameters[1] = acceleration;<br><br>
- WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);
- }<br><br> // 设置减速度
- public void Deceleration(byte slaveAddr, ushort deceleration)
- {
- ushort parametersAddress = 346;<br><br> ushort[] parameters = new ushort[2];
- parameters[0] = 0;
- parameters[1] = deceleration;<br><br>
- WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);
- }<br><br> // 设置速度
- public void Speed(byte slaveAddr, ushort speed)
- {
- ushort parametersAddress = 348;<br><br> ushort[] parameters = new ushort[2];
- parameters[0] = 0;
- parameters[1] = speed;<br><br>
- WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);
- }<br><br> #endregion<br><br> #region 鸣志步进-多线程不安全模式 <br><br> //鸣志步进写入,读取命令延时在 ModbusHelper.SendSerialString 统一设置<br><br> //步进电机10以及以上从站地址以符号表示 <br><br> //AC25 - 将加 设置为25转/秒/秒 344
- //DE25 - 将减 设置为25转/秒/秒 346
- //VE1.5 - 将速度设置为1.5转/秒 348
- //FL20000 - 执行20000步的按长度给进移动到距离 350<br><br> /// <summary>
- /// 步进电机设置加速,减速,速度 支持整数和小数 数值1-10转/秒
- /// </summary>
- public void Stepping_SetAccelerationSpeedDeceleration(object slaveAddr, string acceleration, string deceleration, string speed)
- {
- string strAC = $"{slaveAddr}AC{acceleration}\r";
- SendSerialString(strAC);
- //加速度<br><br>
- string strDE = $"{slaveAddr}DE{deceleration}\r";
- SendSerialString(strDE);
- //减速度<br><br>
- string strVE = $"{slaveAddr}VE{speed}\r";
- SendSerialString(strVE);
- //速度
- }<br><br> /// <summary>
- /// 步进电机读取当前电机的加速度减速度速度
- /// </summary>
- /// <param name="slaveAddr"></param>
- /// <returns></returns>
- public int[] Stepping_Read_AC_DE_VE(object slaveAddr)
- {
- int[] result = new int[3];<br><br>
- //加速度
- string strAC = $"{slaveAddr}AC\r";
- var speed = SendSerialString(strAC);
- speed = speed.Replace($"{slaveAddr}AC=", string.Empty);
- speed = speed.Replace("\r", string.Empty);
- if (!string.IsNullOrWhiteSpace(speed))
- {
- result[0] = Convert.ToInt32(speed);
- }<br><br> //减速度
- string strDE = $"{slaveAddr}DE\r";
- speed = SendSerialString(strDE);
- speed = speed.Replace($"{slaveAddr}DE=", string.Empty);
- speed = speed.Replace("\r", string.Empty);
- if (!string.IsNullOrWhiteSpace(speed))
- {
- result[1] = Convert.ToInt32(speed);
- }<br><br> //速度
- string strVE = $"{slaveAddr}VE\r";
- speed = SendSerialString(strVE);
- speed = speed.Replace($"{slaveAddr}VE=", string.Empty);
- speed = speed.Replace("\r", string.Empty);
- if (!string.IsNullOrWhiteSpace(speed))
- {
- result[2] = Convert.ToInt32(speed);
- }<br><br> return result;
- }<br><br>
- /// <summary>
- /// 设置步进电机移动距离 (支持正负数) 数值1w脉冲/圈
- /// </summary>
- /// <param name="slaveAddr"></param>
- /// <param name="speed"></param>
- public void Stepping_Distance(object slaveAddr, long distance)
- {
- string strDI = $"{slaveAddr}DI{distance}\r";
- SendSerialString(strDI);
- //移动距离
- }<br><br> /// <summary>
- /// 电机旋转运行到指定距离 (执行相对移动命令,移动距离和方向来自最后一个DI命令 按给定长度进至距离) 数值同DI
- /// </summary>
- public void Stepping_FL(object slaveAddr, string numberStr)
- {
- string str = $"{slaveAddr}FL{numberStr}\r";
- SendSerialString(str);
- }<br><br>
- /// <summary>
- /// 设置步进电机强制停止
- /// </summary>
- public void Stepping_SK(object slaveAddr)
- {
- string str = $"{slaveAddr}SK\r";
- SendSerialString(str);
- }<br><br> /// <summary>
- /// 设置步进电机报警复位(部分电机是限位开关,不是限位传感器)
- /// </summary>
- public void Stepping_AR(object slaveAddr)
- {
- string str = $"{slaveAddr}AR\r";
- SendSerialString(str);
- }<br><br> /// <summary>
- /// 设置步进电机Y口开关,L开,H关
- /// </summary>
- public void Stepping_SO(object slaveAddr, int number, string _switch)
- {
- string str = $"{slaveAddr}SO{number}{_switch}\r";
- SendSerialString(str);
- }<br><br> /// <summary>
- /// 读取步进电机X口开关,0触碰1断开
- /// </summary>
- public string Stepping_IS(object slaveAddr)
- {
- string str = $"{slaveAddr}IS\r";
- str = SendSerialString(str);
- return str;<br><br> }<br><br> /// <summary>
- /// 设置步进电机运转时同时输出 1 支持 0 不支持
- /// </summary>
- public void Stepping_MT(object slaveAddr, int number)
- {
- //2024年 鸣志研发确认鸣志伺服暂不支持MT多任务并行
- string str = $"{slaveAddr}MT{number}\r";
- SendSerialString(str);
- }<br><br><br><br>
- #endregion<br><br> #region close 关闭串口、网口、Socket连接<br><br> /// <summary>
- /// 关闭串口,Modbus485连接
- /// </summary>
- public void CloseSerialPort()
- {
- serialPort.Close();
- master.Dispose();
- }<br><br> /// <summary>
- /// 关闭网口,Modbus485连接
- /// </summary>
- public void CloseTCP()
- {
- tcpClient.Close();
- master.Dispose();
- }<br><br> /// <summary>
- /// 关闭socket,Modbus485连接
- /// </summary>
- public void CloseSocket()
- {
- socket.Close();
- socket.Disconnect(true);<br><br> //master.Dispose();
- }<br><br> /// <summary>
- /// 垃圾回收,串口,网口,socket,Modbus485 全部关闭
- /// 单个设备调试用using,多线程流程用手动连接并关闭
- /// </summary>
- public void Dispose()
- {
- try
- {
- //串口部分
- if (serialPort != null)
- {
- serialPort.Close();
- }<br><br> //网口部分
- if (tcpClient != null)
- {
- tcpClient.Close();
- }<br><br> //socket 备用部分
- if (socket != null)
- {
- socket.Close();
- }<br><br> //modbus-485
- if (master != null)
- {
- master.Dispose();
- }<br><br> }
- catch (Exception e)
- {
- LogHelper.Error($"垃圾回收处理异常:" + e.Message);
- }<br><br> }<br><br> #endregion<br><br> }<br><br> /// <summary>
- /// 16位CRC校验
- /// </summary>
- public static class CRC16
- {
- /// <summary>
- /// 输出CRC校验码
- /// </summary>
- /// <param name="data">输入字节数组</param>
- /// <returns>字节0是高8位,字节1是低8位</returns>
- public static byte[] CRC16Calc(byte[] data)
- {
- //crc计算赋初始值
- int crc = 0xffff;
- for (int i = 0; i < data.Length; i++)
- {
- crc = crc ^ data[i];
- for (int j = 0; j < 8; j++)
- {
- int temp;
- temp = crc & 1;
- crc = crc >> 1;
- crc = crc & 0x7fff;
- if (temp == 1)
- {
- crc = crc ^ 0xa001;
- }
- crc = crc & 0xffff;
- }
- }
- //CRC寄存器的高低位进行互换
- byte[] crc16 = new byte[2];
- //CRC寄存器的高8位变成低8位,
- crc16[1] = (byte)((crc >> 8) & 0xff);
- //CRC寄存器的低8位变成高8位
- crc16[0] = (byte)(crc & 0xff);<br><br> return crc16;
- }<br><br>
- }<br><br>}
复制代码
以下是多线程安全版,基于上方代码封装的版本- using System;
- using System.Linq;
- using System.Threading;<br><br>namespace SunnyUI_NuclearForm
- {
- /// <summary>
- /// 线程安全版 鸣志步进/伺服,松下伺服,华庆军继电器模块通用帮助类
- /// </summary>
- public class ThreadModbusHelper
- {<br><br> private static readonly object threadLock = new object();//线程安全锁<br><br> /// <summary>
- /// 松下
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void PannasonicSendByte(string com, int baudRate, byte[] arr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> modbus.SendSerialByte(arr);<br><br> }
- }
- }<br><br> /// <summary>
- /// 华庆军
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void HuaqingjunSendByte(string com, int baudRate, byte[] arr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> modbus.SendSerialByte(arr);<br><br> }
- }
- }<br><br>
- /// <summary>
- /// 称重模块获取数值/去皮归零
- /// </summary>
- public string GetWeight(string com, int baudRate, byte slaveAddr)
- {
- string result = string.Empty;<br><br> lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> //去皮
- //slaveAddr = 18;
- ushort operationCodeAddress = 240; //去皮地址
- modbus.WriteSingleCoil_05(slaveAddr, operationCodeAddress, true);<br><br> Thread.Sleep(100);//去皮再称重延迟<br><br> ushort[] weightArr = modbus.ReadHoldingRegisters_03(slaveAddr, 1, 3);
- if (weightArr != null && weightArr.Length > 0)
- {
- ushort weight = weightArr[2];
- var weight1 = weight.ToString().Substring(0, weight.ToString().Length - 1);//正整数部分
- var weight2 = weight.ToString().Substring(weight.ToString().Length - 1, 1);//小数部分<br><br> result = $"{weight1}.{weight2}";
- }<br><br>
- }
- }<br><br> return result;<br><br> }<br><br>
- #region Stepping_Moons<br><br> /// <summary>
- /// 步进电机设置加速,减速,速度 支持整数和小数 数值1-10转/秒
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Stepping_SetAccelerationSpeedDeceleration(string com, int baudRate, object slaveAddr, string acceleration, string deceleration, string speed)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> string strAC = $"{slaveAddr}AC{acceleration}\r";
- modbus.SendSerialString(strAC);
- //加速度<br><br>
- string strDE = $"{slaveAddr}DE{deceleration}\r";
- modbus.SendSerialString(strDE);
- //减速度<br><br>
- string strVE = $"{slaveAddr}VE{speed}\r";
- modbus.SendSerialString(strVE);
- //速度<br><br> }
- }
- }<br><br>
- /// <summary>
- /// 设置步进电机移动距离 (支持正负数) 数值1w脉冲/圈
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Stepping_Distance(string com, int baudRate, object slaveAddr, long distance)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> string strDI = $"{slaveAddr}DI{distance}\r";
- modbus.SendSerialString(strDI);
- //移动距离<br><br> }
- }
- }<br><br>
- /// <summary>
- /// 电机旋转运行到指定距离 (执行相对移动命令,移动距离和方向来自最后一个DI命令 按给定长度进至距离) 数值同DI
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Stepping_FL(string com, int baudRate, object slaveAddr, string numberStr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> string str = $"{slaveAddr}FL{numberStr}\r";
- modbus.SendSerialString(str);<br><br> }
- }
- }<br><br> /// <summary>
- /// 设置步进电机强制停止
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Stepping_SK(string com, int baudRate, object slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> string str = $"{slaveAddr}SK\r";
- modbus.SendSerialString(str);<br><br> }
- }
- }<br><br> /// <summary>
- /// 设置步进电机报警复位(部分电机是限位开关,不是限位传感器)
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Stepping_AR(string com, int baudRate, object slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> string str = $"{slaveAddr}AR\r";
- modbus.SendSerialString(str);<br><br> }
- }
- }<br><br> /// <summary>
- /// 设置步进电机Y口开关,L开,H关
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Stepping_SO(string com, int baudRate, object slaveAddr, int number, string _switch)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> string str = $"{slaveAddr}SO{number}{_switch}\r";
- modbus.SendSerialString(str);<br><br> }
- }
- }<br><br> /// <summary>
- /// 读取步进电机X口开关,0触碰1断开
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public string Stepping_IS(string com, int baudRate, object slaveAddr)
- {
- string str = string.Empty;
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> str = $"{slaveAddr}IS\r";
- str = modbus.SendSerialString(str);<br><br> }
- }
- return str;
- }<br><br> /// <summary>
- /// 设置步进电机运转时同时输出 1 支持 0 不支持
- /// </summary>
- public void Stepping_MT(string com, int baudRate, object slaveAddr, int number)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> modbus.Stepping_MT(slaveAddr, number);<br><br> }
- }
- }<br><br><br><br> #endregion<br><br> #region Servo_Moons<br><br> /// <summary>
- /// 伺服电机设置加速,减速,速度 支持整数 数值1-10k/分钟
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_SetAccelerationSpeedDeceleration(string com, int baudRate, byte slaveAddr, ushort acceleration, ushort deceleration, ushort speed)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> ushort parametersAddress = 344;<br><br> ushort[] parameters = new ushort[6];
- parameters[0] = 0;
- parameters[1] = acceleration;
- parameters[2] = 0;
- parameters[3] = deceleration;
- parameters[4] = 0;
- parameters[5] = speed;<br><br> modbus.WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);<br><br> }
- }
- }<br><br> /// <summary>
- /// 设置距离 数值1-100/圈
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_Distance(string com, int baudRate, byte slaveAddr, long distance)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> ushort parametersAddress = 350;<br><br> ushort[] parameters = new ushort[1];
- parameters[0] = (ushort)distance;<br><br> modbus.WriteMultipleRegisters_10(slaveAddr, parametersAddress, parameters);<br><br> }
- }
- }<br><br> /// <summary>
- /// 电机旋转运行到指定距离 (执行相对移动命令,移动距离和方向来自最后一个DI命令 按给定长度进至距离)
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_FL(string com, int baudRate, byte slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> ushort operationCodeAddress = 124;
- byte opCode = 0x66;<br><br> modbus.WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);<br><br> }
- }
- }<br><br> /// <summary>
- /// 强制停止
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_SK(string com, int baudRate, byte slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> ushort operationCodeAddress = 124;
- byte opCode = 0xE1;
- modbus.WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);<br><br> }
- }
- }<br><br> /// <summary>
- /// 报警清除
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_AX(string com, int baudRate, byte slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> ushort operationCodeAddress = 124;
- byte opCode = 0xBA;
- modbus.WriteSingleRegister_06(slaveAddr, operationCodeAddress, opCode);<br><br> }
- }
- }<br><br>
- /// <summary>
- /// Y口输出 L 0x4C H 0x48
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_SO(string com, int baudRate, byte slaveAddr, byte ioPoint, byte condition)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> ushort operationCodeAddress = 124;
- byte operationCode = 0x8B;<br><br> ushort[] operationCodeParameters = new ushort[3];
- operationCodeParameters[0] = operationCode;
- operationCodeParameters[1] = ioPoint;
- operationCodeParameters[2] = condition;<br><br> modbus.WriteMultipleRegisters_10(slaveAddr, operationCodeAddress, operationCodeParameters);<br><br> }
- }
- }<br><br>
- /// <summary>
- /// X口输入
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public string Servo_IS(string com, int baudRate, byte slaveAddr)
- {
- string result = string.Empty;
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> try
- {
- ushort inputPortAddress = 5;
- ushort numberRegisters = 1;<br><br> ushort[] data = modbus.ReadHoldingRegisters_03(slaveAddr, inputPortAddress, numberRegisters);
- if (data != null && data.Count() > 0)
- {
- result = Convert.ToString(data[0], 2).PadLeft(12, '0');//转2进制,然后12位补零;
- }
- }
- catch (Exception)
- {<br><br> }<br><br>
- }
- }
- return result;
- }<br><br> /// <summary>
- /// 伺服使能关闭
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="arr"></param>
- /// <returns></returns>
- public void Servo_MD(string com, int baudRate, byte slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> modbus.Opcoded_MD(slaveAddr);<br><br> }
- }
- }<br><br> /// <summary>
- /// 伺服使能
- /// </summary>
- /// <param name="com"></param>
- /// <param name="baudRate"></param>
- /// <param name="slaveAddr"></param>
- public void Servo_ME(string com, int baudRate, byte slaveAddr)
- {
- lock (threadLock)
- {
- using (ModbusHelper modbus = new ModbusHelper())
- {
- modbus.ConnectForSerialPort(com, baudRate);<br><br> modbus.Opcoded_ME(slaveAddr);<br><br> }
- }
- }<br><br><br><br> <br><br><br><br>
- #endregion<br><br> }
- }
复制代码 支持串口通讯,也支持网口通讯。先讲讲Modbus 通讯是什么,软件部署在工控机上作上位机控制下位机运转,比如各种电机和继电器模块(将电脑的小电流信号转换为大电流信号发送到硬件上)
ModbusRTU的报文格式: 从站地址/设备Id(1个字节)+功能码(1个字节)+数据部分(N个字节)+校验、CRC检验(2个字节)
- Modbus-RTU的功能码是用于指示Modbus协议进行何种数据操作的标识符。以下是常用的Modbus-RTU功能码及其含义:
- 01:读取线圈状态,用于读取开关量输入(DO)。
- 02:读取离散输入状态,用于读取开关量输入(DI)。
- 03:读取保持寄存器,用于读取模拟量输入(AI)。
- 04:读取输入寄存器,用于读取模拟量输入(AI)。
- 05:写单个线圈,用于控制开关量输出(DO)。
- 06:写单个保持寄存器,用于控制模拟量输出(AO)。
- 15:写多个线圈,用于控制多个开关量输出(DO)。
- 16:写多个保持寄存器,用于控制多个模拟量输出(AO)。
- 需要注意的是,不同设备支持的功能码可能不同,因此在使用Modbus-RTU通信时需要根据实际情况选择合适的功能码。
复制代码 一般常用的01,03,05,06,10
01是读线圈,03是读寄存器
05是写线圈,06是写寄存器
10是往多个寄存器里写数值(16)
15不怎么用
线圈是什么,软件层面可以简单的理解为开关阀门
寄存器是什么,可以简单的理解为一个存放数值的地址,每个地址有不同的作用,写入不同的数值发挥不同的效应
Modbus 报文如何编写?
举几个栗子:
01 功能码示例:- 读取 00A0h 伺服准备状态 (S-RDY) ReadOnly 0:准备 OFF 1:准备 ON
- 01 01 00 A0 00 01 FD E8
- 01 01 01 01 90 48
复制代码 请求报文: 01 ,从站地址 ,一般一个485占一个COM口能接入31轴地址
01 ,Modbus 功能码 读取线圈地址
00 a0 ,读取地址00a0
00 01 ,读取一个字节长度,modbus通讯里,基本上是两个字节为一个地址
FD E8 ,crc 16位校验,可以自行生成
应答报文:01, 从站地址
01, 响应功能码01
01,返回一位字节
01,这时候返回的响应字节,就得看每个厂家是如何解释的了,比如这里,00 就是 off ,01 就是 on
9048,crc 16位校验,可以自行生成
03 功能码示例:- 读取电压
- 01 03 60 2C 00 02 1B C2
- 01 03 04 05 28 00 05 BA F4
- 00050528H = 329000 (D
复制代码 请求报文: 01 ,从站地址 ,一般一个485占一个COM口能接入31轴地址
03 ,Modbus 功能码 读取寄存器地址
602c ,读取地址602c
00 02 ,读取2字节长度,modbus通讯里,基本上是两个字节为一个地址
1B C2 ,crc 16位校验,可以自行生成
应答报文:01, 从站地址
03, 响应功能码03
04,返回4位字节
05280005,这时候返回的响应字节,就得看每个厂家是如何解释的了,比如这里,一般是高位在前低位在后,但是这个厂家,低位在前高位在后,所以两组字节要反过来转换十进制。
0005在前0528在后,所以最后得到的电压是 00050528HEX = 329000 DEC
05 功能码示例:- 01 05 00 61 FF 00 DD E4 ,报警清除 0000h:输入 OFF、FF00h:输入 ON
- 01 05 00 61 00 00 9C 14
复制代码 请求报文: 01 ,从站地址 ,一般一个485占一个COM口能接入31轴地址
05 ,Modbus 功能码 写线圈
0061 ,写线圈0061
FF00,写入FF00,硬件的编码器看到FF00编译为NO,机器开,00000编译为0FF,机器关
DDE4 ,crc 16位校验,可以自行生成
应答报文:05,06的正确应答报文一般都是把请求报文原样输出回来表示已经执行
06 功能码示例:- 加速度减速度速度
- 01 06 46 00 01f4 设置v0=500
复制代码 请求报文: 01 ,从站地址 ,一般一个485占一个COM口能接入31轴地址
06 ,Modbus 功能码 写寄存器
4600,写寄存器4600
01f4, 十六进制的500,modbus中全部都是十六进制字节请求和应答
这里还有两节CRC,因为速度经常改变,所以没有带CRC,每次请求报文的字节发生变化时CRC一定会变化。
应答报文:05,06的正确应答报文一般都是把请求报文原样输出回来表示已经执行
10 功能码示例:- 0E 10 01 5E 00 02 04 00 1E 84 80 //200w
- 0E 10 015E 0002 04 FFE1 7B80 //-200w
复制代码 这里展示一个稍微复杂一点的报文
请求报文: 0E , 是十进制从站地址14 ,
10,Modbus 功能码 写多个寄存器
015E,写寄存器015E
0002, 从015e开始写两个寄存器地址
04,四组字节
00 1E 84 80 ,高位字节在前低位字节在后,两组字节为一个寄存器地址,两个寄存器地址合起来存放一个大数值。比如这里的200w, 00 1E 84 80 转换为十进制=200w
这里还有两节CRC,因为速度经常改变,所以没有带CRC,每次请求报文的字节发生变化时CRC一定会变化。
应答报文:10的正确应答报文一般都是把请求报文原样输出回来表示已经执行
下面一组报文其实同上,只是写入的数值是-200w,
根据计算器可以直观的看到十进制-200w=FFE1 7B80
接下来说说两个通用帮助类如何使用
1. 网口通讯
- ModbusHelper modbusHelper = new ModbusHelper();<br><br>modbusHelper.ConnectForTCP("IP", "端口")<br><br>// 发送数据到硬件
- //00 00 00 00 00 06 01 05 00 00 ff 00 开
- byte[] arr = new byte[12];
- arr[0] = 0x00;
- arr[1] = 0x00;
- arr[2] = 0x00;
- arr[3] = 0x00;
- arr[4] = 0x00;
- arr[5] = 0x06;
- arr[6] = 0x01;
- arr[7] = 0x05;
- arr[8] = 0x00;
- arr[9] = 0x00;
- arr[10] = 0xff;
- arr[11] = 0x00;
- modbusHelper.SendTCPByte(arr);<br>
复制代码 发送的字节数组是上面曾说过的06功能码,每个厂家都有自己的操作指令
2. 串口通讯- using (ModbusHelper com5_modbusHelper = new ModbusHelper())
- {
- com5_modbusHelper.ConnectForSerialPort("COM5", 9600);
- byte slaveAddr = 2; //开盖抓手X
- com5_modbusHelper.Stepping_AR(slaveAddr);//报警清除
- //你操作厂家硬件的指令代码集
- }
复制代码 我的Modbus 通用帮助类 ,你可以选择用Using连接Dispose自动垃圾回收,也可以自己控制连接和关闭,建议每次发完一组操作指令后就断开和硬件的连接
接下来说鸣志步进电机的指令和控制代码
在 region 鸣志步进-多线程不安全模式 endregion,这个折叠标签里
从上到下依次是常用的十几个命令如下:- 步进电机设置加速,减速,速度 支持整数和小数 数值1-10转/秒
- 步进电机读取当前电机的加速度减速度速度
- 设置步进电机移动距离 (支持正负数) 数值1w脉冲/圈
- 电机旋转运行到指定距离 (执行相对移动命令,移动距离和方向来自最后一个DI命令 按给定长度进至距离) 数值同DI
- 设置步进电机强制停止
- 设置步进电机报警复位
- 设置步进电机Y口开关,L开,H关
- 读取步进电机X口开关,0触碰1断开
- 设置步进电机运转时同时输出
复制代码 调用方式如下:- using (ModbusHelper com6_modbusHelper = new ModbusHelper())
- {
- com6_modbusHelper.ConnectForSerialPort("COM6", 9600);<br><br> //从站地址
- byte slaveAddr = 1;<br>
复制代码- com6_modbusHelper.Stepping_SetAccelerationSpeedDeceleration(slaveAddr, "8", "8", "6");//设置加速度减速度速度<br> int[] arr=com6_modbusHelper.Stepping_Read_AC_DE_VE(slaveAddr);//读取指定电机的加速度减速度速度
复制代码- //比如一个电机走一段路,从0米处运转到时速100码的过程是加速度,然后按照速度120码均速前进到终点,再终点前按照减速度逐渐停止到0码是减速度。<br> com6_modbusHelper.Stepping_Distance(slaveAddr, 10000);//1w是脉冲数,一般绝大部分电机都是1w脉冲一圈, -1w就是反转1圈<br> com6_modbusHelper.Stepping_FL(slaveAddr, "同DI脉冲数");//一般设置了DI后在执行FL,电机才会运行<br> com6_modbusHelper.Stepping_SK(slaveAddr);//强制停止电机当前的运转<br> com6_modbusHelper.Stepping_AR(slaveAddr);//报警清除,一般电机运行到限位处或者负载过大,驱动器会拒绝继续执行操作命令,需要先清除报警<br> com6_modbusHelper.Stepping_SO(slaveAddr, 1, "L"); //电机的Y_口开启<br> com6_modbusHelper.Stepping_SO(slaveAddr, 1, "H"); //电机的Y_口关闭<br> com6_modbusHelper.Stepping_IS(slaveAddr)//根据这个从站地址读取这个电机的全部输出口,0开1关<br> com6_modbusHelper.Stepping_MT(slaveAddr, number);//设置步进电机运转时同时输出 1 支持 0 不支持,鸣志步进电机支持此指令,伺服电机不支持<br>
- }
复制代码 接下来说鸣志伺服电机的指令和控制代码
在 #region Servo_Moons endregion,这个折叠标签里
从上到下依次是常用的十几个命令如下:- 设置加减速,减速度,速度
- 读取伺服电机加速度减速度速度
- 设置距离 数值1-100/圈
- 设置距离 脉冲数
- 电机旋转运行到指定距离 (执行相对移动命令,移动距离和方向来自最后一个DI命令 按给定长度进至距离)
- 强制停止
- 报警清除
- Y口输出 L 0x4C H 0x48
- X口输入 ,0触碰1断开
- 伺服使能
- 伺服使能关闭
复制代码 伺服和步进的区别在于,伺服是闭环控制自带编码器,步进是开环控制没有数据反馈容易丢步。伺服更精准更贵。
在软件层面,步进电机通过写入简单明了的字符串指令轻易控制,但是同品牌的伺服电机要写地址操作起来更复杂
调用方式如下:- private static ThreadModbusHelper modbus_com5 = new ThreadModbusHelper();//在这里控制伺服全部使用多线程安全帮助类<br>
复制代码 modbus_com5.Servo_SetAccelerationSpeedDeceleration("com5", 9600, slaveAddr, 3000, 3000, 5000);//设置加速度减速度速度,这里的加减速度要/6,速度要/240,才是真正的RPM(每分钟X转)- ushort[] arr=modbus_com5.ReadAccelerationSpeedDeceleration("com5", 9600, slaveAddr);//读取加速度减速度速度,这个方法在多线程不安全版本里,没有集成进多线程安全版本
复制代码 modbus_com5.Servo_Distance("com5", 9600, slaveAddr, 15);//通过圈数控制电机运转,支持正负数
modbus_com5.DistanceForPulse(slaveAddr, pulse);//通过脉冲控制电机运转,支持正负数
modbus_com5.Servo_FL("com5", 9600, slaveAddr);//让电机运转执行DI命令
modbus_com5.Servo_SK("com6", 9600, slaveAddr);//电机强制停止
modbus_com5.Servo_AX("com5", 9600, slaveAddr);//报警清除
modbus_com5.Servo_SO("com5", 9600, slaveAddr, 0x34, 0x4C);//Y口输出,这里展示的是Y4口,开启。0x34可以替换为 0x31-0x38 对应y1-y8地址,0x4c是开启,0x48是关闭
modbus_com5.Servo_IS("com5", 9600, slaveAddr)//读取X口,0触碰1断开,如果8个输入口都是触碰状态,可能返回的是0,需要强制补零
modbus_com5.Servo_MD("COM6", 9600, slaveAddr);//伺服使能关闭
modbus_com5.Servo_ME("COM6", 9600, slaveAddr);//伺服使能开启,在使用伺服电机需要先伺服使能才能使用其功能
接下来说华庆军继电器模块的指令和控制代码
示例如下:- // 0A05000AFF00AD43 Y11打开
- modbus_com8.HuaqingjunSendByte("com8", 9600, new byte[] { 0x0A, 0X05, 0X00, 0X0A, 0XFF, 0X00, 0XAD, 0X43 });
复制代码 又是一串很熟悉的开关线圈字节数组指令,华庆军官网上下载调试软件QingJunTestV3.0.exe
左侧设置开关量型选择,比如我选择的是32路输入输出
左侧下方输入地址或者IP
右侧点击对应的Y1-32,蓝色的一条操作码就是我们需要的字节数组指令
上面是华庆军输出指令,输入指令如下- //十进制
- var modbusData = modbusHelper.ReadHoldingRegisters_03(0x01, 0x04, 1);
- //十进制转二进制并八位补零
- var binary = modbusData != null && modbusData.Length > 0 ? Convert.ToString(modbusData[0], 2).PadLeft(8, '0') : "00000000";
- //二进制转数组
- var inArray = StringToArray(binary);
- //IN1-IN8数据绑定 //0断开1闭合
复制代码 接下来说松下伺服电机的指令和控制代码
松下modbus请求报文- 00 05 00 60 FF 00 8D F5 ,00 为广播全部从站伺服开启00 05 00 60 00 00 CC 05 ,00 为广播全部从站伺服关闭01 05 00 60 FF 00 8C 24 , 指定从站,伺服使能开启 0060线圈写入FF00 ON01 05 00 60 00 00 CD D4 , 指定从站,伺服使能关闭 0060线圈写入0000 off01 06 44 14 00 00 DD 3E ,指定运行block编号,4414寄存器地址写入0000,指定运行block_0号动作这里解释下block 是什么,松下伺服电机需要先编辑好block动作,然后调用block,电机才会运转。block里包括常用的正转反转加速减速速度,回原点,紧急刹车等功能01 05 01 20 FF 00 8C 0C ,0120线圈对应地址,STB开关, FF00开启01 05 01 20 00 00 CD FC ,0120线圈对应地址,STB开关, 0000关闭05线圈 01 05 00 61 FF 00 DD E4 ,报警清除 0000h:输入 OFF、FF00h:输入 ON
- 01 05 00 61 00 00 9C 1406 寄存器01 06 46 3a 00 00 原点有效化01 06 46 3a 00 01 原点无效化01 06 10 20 61 73 保存到 EEPROM加速度减速度速度
- 01 06 46 00 01f4 设置v0=50001 06 46 10 00 64 设置a0=10001 06 46 20 00 64 设置d0=100读取 00A0h 伺服准备状态 (S-RDY) ReadOnly 0:准备 OFF 1:准备 ON
- 01 01 00 A0 00 01 FD E8
- 01 01 01 01 90 48 读取电压
- 01 03 60 2C 00 02 1B C2
- 01 03 04 05 28 00 05 BA F4
- 00050528H = 329000 (D
复制代码
以下为本人编辑好的Block动作一览
//松下电机 Block相关动作编号
//从站地址10 桶盖
//0 正10w
//1 负10w
//2 正1000
//3 负1000
//4 163w3k
//5 正3k
//6 负3k
//7 绝对定位 0 回原点
//8 减速停止/即刻停止
比如调用紧急刹车如下
这里就要用到CRC动态生成校验数组了- using (ModbusHelper bottle_modbusHelper = new ModbusHelper())
- {
- bottle_modbusHelper.ConnectForSerialPort("COM6", 9600);
- //16 10
- //10 06 44 14 00 08 指定运行block编号
- byteArr = new byte[] { 0x10, 0x06, 0x44, 0x14, 0x00, 0x08 };
- crc = CRC16.CRC16Calc(byteArr);
- newArr = byteArr.Concat(crc).ToArray();
- bottle_modbusHelper.SendSerialByte(newArr);
- Thread.Sleep(50);//松下命令间隔
- //10 05 01 20 FF 00 ,STB开
- byteArr = new byte[] { 0x10, 0x05, 0x01, 0x20, 0xFF, 0x00 };
- crc = CRC16.CRC16Calc(byteArr);
- newArr = byteArr.Concat(crc).ToArray();
- bottle_modbusHelper.SendSerialByte(newArr);
- }
复制代码 以下为工厂部分硬件实拍
以下为部分UI实拍
祝各位在工控/自动化的道路越走越舒坦<br><br>来源:https://www.cnblogs.com/Gao1234/p/18096175
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|