/// <summary> /// 根据类型地址以及需要写入的数据来生成指令头 /// </summary> /// <param name="type"></param> /// <param name="address"></param> /// <param name="data"></param> /// <returns></returns> protected byte[] GetWriteCommand(MelsecDataType type, ushort address, byte[] data) { byte[] _PLCCommand = new byte[21 + data.Length]; //默认信息----注意:高低字节交错 _PLCCommand[0] = 0x50; //副标题 _PLCCommand[1] = 0x00; _PLCCommand[2] = NetworkNumber; //网络号 _PLCCommand[3] = 0xFF; //PLC编号 _PLCCommand[4] = 0xFF; //目标模块IO编号 _PLCCommand[5] = 0x03; _PLCCommand[6] = NetworkStationNumber; //目标模块站号 _PLCCommand[7] = (byte)((_PLCCommand.Length - 9) % 256); //请求数据长度 _PLCCommand[8] = (byte)((_PLCCommand.Length - 9) / 256);; _PLCCommand[9] = 0x0A; //CPU监视定时器 _PLCCommand[10] = 0x00; _PLCCommand[11] = 0x01; //批量读取数据命令 _PLCCommand[12] = 0x14; _PLCCommand[13] = type.DataType; //一点为单位成批读取 _PLCCommand[14] = 0x00; _PLCCommand[15] = (byte)(address % 256);; //起始地址的地位 _PLCCommand[16] = (byte)(address / 256); _PLCCommand[17] = 0x00; _PLCCommand[18] = type.DataCode;//指明写入的数据 if (type.DataType == 1) { _PLCCommand[19] = (byte)(data.Length * 2 % 256);//软元件长度的地位 _PLCCommand[20] = (byte)(data.Length * 2 / 256); } else { _PLCCommand[19] = (byte)(data.Length / 2 % 256);//软元件长度的地位 _PLCCommand[20] = (byte)(data.Length / 2 / 256); } Array.Copy(data, 0, _PLCCommand, 21, data.Length); return(_PLCCommand); }
/// <summary> /// 向PLC写入数据,针对D和W的方式,数据格式为有符号的short数组 /// </summary> /// <param name="type">写入的数据类型</param> /// <param name="address">初始地址</param> /// <param name="data">有符号的short数组</param> /// <returns>结果</returns> public OperateResult WriteIntoPLC(MelsecDataType type, ushort address, short[] data) { byte[] temp = GetBytesFromArray(data, false); return(WriteIntoPLC(type, address, temp)); }
/// <summary> /// 使用Unicode编码向PLC写入字符串数据,针对W,D的方式,数据为字符串 /// </summary> /// <param name="type">写入的数据类型</param> /// <param name="address">初始地址</param> /// <param name="data">字符串数据信息</param> /// <returns>结果</returns> public OperateResult WriteUnicodeStringIntoPLC(MelsecDataType type, ushort address, string data) { byte[] temp = Encoding.Unicode.GetBytes(data); return(WriteIntoPLC(type, address, temp)); }
/// <summary> /// 向PLC写入ASCII编码字符串数据,针对W,D的方式,数据为字符串 /// </summary> /// <param name="type">写入的数据类型</param> /// <param name="address">初始地址</param> /// <param name="data">字符串数据信息</param> /// <returns>结果</returns> public OperateResult WriteAsciiStringIntoPLC(MelsecDataType type, ushort address, string data) { byte[] temp = Encoding.ASCII.GetBytes(data); temp = SingularTurnEven(temp); return(WriteIntoPLC(type, address, temp)); }
/// <summary> /// 从三菱PLC中读取想要的数据,返回读取结果 /// </summary> /// <param name="type">想要读取的数据类型</param> /// <param name="address">读取数据的起始地址</param> /// <param name="length">读取的数据长度,字最大值960,位最大值7168</param> /// <returns>带数据头的字节数组</returns> public OperateResult <byte[]> ReadFromPLC(MelsecDataType type, ushort address, ushort length) { OperateResult <byte[]> result = new OperateResult <byte[]>(); //获取指令 byte[] _PLCCommand = GetReadCommand(type, address, length); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); HslTimeOut timeout = new HslTimeOut() { WorkSocket = socket }; try { ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCheckConnect), timeout); socket.Connect(new IPEndPoint(PLCIpAddress, GetPort())); timeout.IsSuccessful = true; } catch { ChangePort(); result.Message = StringResources.ConnectedFailed;; socket.Close(); return(result); } byte[] DataHead = null; try { socket.Send(_PLCCommand); //先接收满9个数据 int NeedReceived = 9; DataHead = NetSupport.ReadBytesFromSocket(socket, NeedReceived); NeedReceived = BitConverter.ToUInt16(DataHead, 7); DataHead = NetSupport.ReadBytesFromSocket(socket, NeedReceived); //获取读取代码 result.ErrorCode = BitConverter.ToUInt16(DataHead, 0); result.Content = new byte[DataHead.Length - 2]; Array.Copy(DataHead, 2, result.Content, 0, DataHead.Length - 2); if (type.DataType == 1) { result.Content = ReceiveBytesTranslate(result.Content); } result.IsSuccess = true; } catch (Exception ex) { result.Message = StringResources.SocketIOException + ex.Message; socket.Close(); return(result); } socket.Shutdown(SocketShutdown.Both); socket.Close(); socket = null; if (result.ErrorCode > 0) { result.IsSuccess = false; } return(result); }
/// <summary> /// 解析数据地址 /// </summary> /// <param name="address">数据地址</param> /// <param name="type">类型</param> /// <param name="startAddress">其实地址</param> /// <param name="result">结果数据对象</param> /// <returns></returns> private bool AnalysisAddress(string address, out MelsecDataType type, out ushort startAddress, OperateResult result) { try { switch (address[0]) { case 'M': case 'm': { type = MelsecDataType.M; break; } case 'X': case 'x': { type = MelsecDataType.X; break; } case 'Y': case 'y': { type = MelsecDataType.Y; break; } case 'D': case 'd': { type = MelsecDataType.D; break; } case 'W': case 'w': { type = MelsecDataType.W; break; } case 'L': case 'l': { type = MelsecDataType.L; break; } default: throw new Exception("输入的类型不支持,请重新输入"); } startAddress = Convert.ToUInt16(address.Substring(1)); } catch (Exception ex) { result.Message = ex.Message; type = null; startAddress = 0; return(false); } return(true); }