C#MODBUS通訊
public class ModbusRtu { /// <summary> /// /// </summary> /// <param name="com">埠</param> /// <param name="BaudRate">波特率</param> /// <param name="stopbits">停止位</param> /// <param name="parity">校驗方式</param> /// <param name="databites">資料位</param> public ModbusRtu(string com, int BaudRate, StopBits stopbits, Parity parity, int databites) { try { _Portname = com.ToUpper(); _BaudRate = BaudRate; _StopBites = stopbits; _Parity = parity; _Databites = databites; string[] _allcom = SerialPort.GetPortNames(); for (int i = 0; i < _allcom.Length; i++) { _allcom[i] = _allcom[i].ToUpper(); } _switch1 = ((IList)_allcom).Contains(_Portname); //判斷COM口是否存在。 _SerialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(_serportRece); if (!_SerialPort.IsOpen) { _SerialPort.Open(); } } catch(Exception ex) { } } private void _serportRece(object sender, SerialDataReceivedEventArgs e) { //MessageBox.Show("Test"); } /// <summary> /// 埠名稱 /// </summary> public string _Portname { get; set; } /// <summary> /// 波特率 /// </summary> public int _BaudRate { get; set; } /// <summary> /// 停止位 /// </summary> public StopBits _StopBites { get; set; } /// <summary> /// 校驗位 /// </summary> public Parity _Parity { get; set; } /// <summary> /// 資料位 /// </summary> public int _Databites { get; set; } /// <summary> /// 開關1判斷是否存在COM口 /// </summary> public bool _switch1 = false; private static SerialPort _SerialPort1=new SerialPort(); private SerialPort _SerialPort { get { try { if (!_SerialPort1.IsOpen)//判斷埠是否開啟 { _SerialPort1.DataBits = _Databites; _SerialPort1.BaudRate = _BaudRate; _SerialPort1.PortName = _Portname; _SerialPort1.StopBits = _StopBites; _SerialPort1.Parity = _Parity; _SerialPort1.Open(); return _SerialPort1; } string[] _allcom = SerialPort.GetPortNames(); for (int i = 0; i < _allcom.Length; i++) { _allcom[i] = _allcom[i].ToUpper(); } _switch1 = ((IList)_allcom).Contains(_Portname.ToUpper()); //判斷COM口是否存在。 } catch(Exception ex) { } return _SerialPort1; } } // public byte[] _sendbyte = new byte[30]; private byte[] _bytearr(int _data) { byte[] _s = new byte[2]; try { byte[] s1 = BitConverter.GetBytes(_data); if (_data > 0xFF) { _s[0] = s1[s1.Length - 3]; _s[1]= s1[s1.Length - 4]; } if (_data <=0xFF) { _s[0] = 0; _s[1] = s1[0]; } } catch (Exception ex) { } // s = BitConverter.GetBytes(_data); return _s; } /// <summary> /// CRC16校驗 /// </summary> /// <param name="instructions">校驗的位元組陣列</param> /// <param name="start">開始位置</param> /// <param name="length">長度</param> /// <returns></returns> public byte[] _crcchecking(byte[] instructions, uint start, uint length) { uint i, j; uint crc16 = 0xFFFF;//crc暫存器賦初值 try { length = length + start; for (i = start; i < length; i++) { crc16 ^= instructions[i]; for (j = 0; j < 8; j++) { if ((crc16 & 0x01) == 1) { crc16 = (crc16 >> 1) ^ 0xA001; } else { crc16 = crc16 >> 1; } } } // UInt16 X = (UInt16)(crc16 *256); // UInt16 Y = (UInt16)(crc16/256); //crc16 = (UInt16)(X ^ Y); } catch { } return BitConverter.GetBytes(crc16); } /// <summary> /// 讀取無符號16位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_len">讀取長度</param> /// <returns></returns> public UInt16[] _ruint16(int _addr,byte _stand, int _len) { UInt16[] _s = new UInt16[_len]; byte[] _send = new byte[20]; try { byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_switch1) { _send[0] = _stand; _send[1] = 0x03; _send[2] = _bytearr(_addr)[0]; _send[3] = _bytearr(_addr)[1]; _send[4] = _bytearr(_len)[0]; _send[5] = _bytearr(_len)[1]; _send[6] = _crcchecking(_send, 0, 6)[0]; _send[7] = _crcchecking(_send, 0, 6)[1]; _SerialPort.Write(_send, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 1];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen-2);//重新校驗報文 if (reccrcL == crc[1] && reccrcH == crc[0])//比對校驗碼 { byte fun = _rec[1];//功能碼 if (fun==0x03)//modbus03功能碼 { byte databyteNum = _rec[2];//接收位元組數 for (int i = 0; i < databyteNum; i++) { _s[i] = (UInt16)(_rec[i*2+3]<<8|_rec[i*2+4]); } } } } } } catch(Exception ex) { } return _s; } /// <summary> /// 讀取有符號16位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_len">讀取長度</param> /// <returns></returns> public Int16[] _rint16(int _addr, byte _stand, int _len) { Int16[] _s = new Int16[_len]; byte[] _send = new byte[20]; try { byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_switch1) { _send[0] = _stand; _send[1] = 0x03; _send[2] = _bytearr(_addr)[0]; _send[3] = _bytearr(_addr)[1]; _send[4] = _bytearr(_len)[0]; _send[5] = _bytearr(_len)[1]; _send[6] = _crcchecking(_send, 0, 6)[0]; _send[7] = _crcchecking(_send, 0, 6)[1]; _SerialPort.Write(_send, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 1];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[1] && reccrcH == crc[0])//比對校驗碼 { byte fun = _rec[1];//功能碼 if (fun == 0x03)//modbus03功能碼 { byte databyteNum = _rec[2];//接收位元組數 for (int i = 0; i < databyteNum; i++) { _s[i] = (Int16)(_rec[i * 2 + 3] << 8 | _rec[i * 2 + 4]); } } } } } } catch (Exception ex) { } return _s; } /// <summary> /// 讀取無符號32位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_length">長度</param> /// <returns></returns> public UInt32[] _ruint32(int _addr, byte _stand, int _length) { int _len = _length * 2; UInt32[] _s = new UInt32[_length]; byte[] _send = new byte[20]; try { byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_switch1) { _send[0] = _stand; _send[1] = 0x03; _send[2] = _bytearr(_addr)[0]; _send[3] = _bytearr(_addr)[1]; _send[4] = _bytearr(_len)[0]; _send[5] = _bytearr(_len)[1]; _send[6] = _crcchecking(_send, 0, 6)[0]; _send[7] = _crcchecking(_send, 0, 6)[1]; _SerialPort.Write(_send, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 1];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[1] && reccrcH == crc[0])//比對校驗碼 { byte fun = _rec[1];//功能碼 if (fun == 0x03)//modbus03功能碼 { byte databyteNum = _rec[2];//接收位元組數 for (int j= 0; j < databyteNum/4; j++) { byte[] _nt = { _rec[4 + j * 4], _rec[3 + j * 4], _rec[6 + j * 4], _rec[5 + j * 4] }; _s[j] = BitConverter.ToUInt32(_nt, 0); } } } } } } catch (Exception ex) { } return _s; } /// <summary> /// 讀取有符號32位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_length">讀取長度</param> /// <returns></returns> public Int32[] _rint32(int _addr, byte _stand, int _length) { int _len = _length * 2; Int32[] _s = new Int32[_length]; byte[] _send = new byte[20]; try { byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_switch1) { _send[0] = _stand; _send[1] = 0x03; _send[2] = _bytearr(_addr)[0]; _send[3] = _bytearr(_addr)[1]; _send[4] = _bytearr(_len)[0]; _send[5] = _bytearr(_len)[1]; _send[6] = _crcchecking(_send, 0, 6)[0]; _send[7] = _crcchecking(_send, 0, 6)[1]; _SerialPort.Write(_send, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 1];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[1] && reccrcH == crc[0])//比對校驗碼 { byte fun = _rec[1];//功能碼 if (fun == 0x03)//modbus03功能碼 { byte databyteNum = _rec[2];//接收位元組數 for (int j = 0; j < databyteNum / 4; j++) { byte[] _nt = { _rec[4 + j * 4], _rec[3 + j * 4], _rec[6 + j * 4], _rec[5 + j * 4] }; _s[j] = BitConverter.ToInt32(_nt, 0); } } } } } } catch (Exception ex) { } return _s; } /// <summary> /// 讀取32位浮點數 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_length">讀取長度</param> /// <returns></returns> public Single[] _rfloat(int _addr, byte _stand, int _length) { int _len = _length * 2; Single[] _s = new Single[_length]; byte[] _send = new byte[20]; try { byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_switch1) { _send[0] = _stand; _send[1] = 0x03; _send[2] = _bytearr(_addr)[0]; _send[3] = _bytearr(_addr)[1]; _send[4] = _bytearr(_len)[0]; _send[5] = _bytearr(_len)[1]; _send[6] = _crcchecking(_send, 0, 6)[0]; _send[7] = _crcchecking(_send, 0, 6)[1]; _SerialPort.Write(_send, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 1];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[1] && reccrcH == crc[0])//比對校驗碼 { byte fun = _rec[1];//功能碼 if (fun == 0x03)//modbus03功能碼 { byte databyteNum = _rec[2];//接收位元組數 for (int j = 0; j < databyteNum / 4; j++) { byte[] _nt = { _rec[4 + j * 4], _rec[3 + j * 4], _rec[6 + j * 4], _rec[5 + j * 4] }; _s[j] = BitConverter.ToSingle(_nt, 0); } } } } } } catch (Exception ex) { } return _s; } /// <summary> /// 讀取位狀態 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_length">讀取長度</param> /// <returns></returns> public bool[] _rbite(int _addr, byte _stand, int _length) { int _len = _length * 1; bool[] _s = new bool[1000]; byte[] _send = new byte[20]; try { byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_switch1) { _send[0] = _stand; _send[1] = 0x01; _send[2] = _bytearr(_addr)[0]; _send[3] = _bytearr(_addr)[1]; _send[4] = _bytearr(_len)[0]; _send[5] = _bytearr(_len)[1]; _send[6] = _crcchecking(_send, 0, 6)[0]; _send[7] = _crcchecking(_send, 0, 6)[1]; _SerialPort.Write(_send, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 1];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[1] && reccrcH == crc[0])//比對校驗碼 { byte databyteNum = _rec[2];//接收位元組數 byte fun = _rec[1];//功能碼 if (fun == 0x01)//modbus03功能碼 { for (int j = 0; j < databyteNum ; j++) { for (int i = 0; i < 8; i++) { _s[j*8+i] = (_rec[3 + j] & Convert.ToInt16(Math.Pow(2, i))) == Convert.ToInt16(Math.Pow(2, i)); } } } } } } } catch (Exception ex) { } return _s; } /// <summary> /// 寫單個位狀態 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_bool">BOOL值</param> /// <returns></returns> public bool _wbite(int _addr, byte _stand, bool _bool) { bool s = false; byte bools = 0; byte[] _send = new byte[20]; if (_switch1) { byte[] _addrbyte = BitConverter.GetBytes(_addr); byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; try { if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } if (_bool) { bools = 1; } _send[0] = _stand; _send[1] = 0x05; _send[2] = _addrL; _send[3] = _addrH; _send[4] = bools; _send[5] = _crcchecking(_send, 0, 5)[0]; _send[6] = _crcchecking(_send, 0, 5)[1]; _SerialPort.Write(_send, 0, 7);//傳送報文 int _reclen = _SerialPort.BytesToRead; byte[] _rec = new byte[_reclen]; if (_reclen > 5) { _SerialPort.Read(_rec, 0, _reclen); byte reccrcL = _rec[_reclen - 3];//取接收到的報文 校驗碼低位 byte reccrcH = _rec[_reclen - 2];//取校驗碼高位 byte[] crc = _crcchecking(_rec, 0, (uint)_reclen - 3);//重新校驗報文 if (reccrcL == crc[0] && reccrcH == crc[1])//比對校驗碼 { byte databyteNum = _rec[2];//接收位元組數 byte fun = _rec[1];//功能碼 if (fun == 0x05)//modbus03功能碼 { s = true; } } } } catch (Exception ex) { //throw; } } return s; } /// <summary> /// 寫單個16位有符號資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_data">16位有符號資料</param> /// <returns></returns> public bool _wint16(int _addr, byte _stand, Int16 _data) { bool _successful = false; try { if (_switch1) { byte[] _recebyte = new byte[1000]; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_data < 32767 || _data > -32767) { if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } Int16 _y = Convert.ToInt16(_data); byte[] intBuff = BitConverter.GetBytes(_y); sedbyte[0] = _stand; sedbyte[1] = 0x06; sedbyte[2] = _addrL;//MODBUS地址低位 sedbyte[3] = _addrH;//modbus地址高位 sedbyte[4] = intBuff[1]; sedbyte[5] = intBuff[0]; sedbyte[6] = _crcchecking(sedbyte, 0, 6)[0]; sedbyte[7] = _crcchecking(sedbyte, 0, 6)[1]; _SerialPort.Write(sedbyte, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; _SerialPort.Read(_recebyte, 0,_reclen); if (_reclen>5) { byte reccrcL = _recebyte[_reclen - 2];//取接收到的報文 校驗碼低位 byte reccrcH = _recebyte[_reclen - 1];//取校驗碼高位 byte[] crc = _crcchecking(_recebyte, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[0] && reccrcH == crc[1])//比對校驗碼 { byte fun = _recebyte[1];//功能碼 if (fun == 0x06)//modbus03功能碼 { _successful = true; } } _successful = true; } } } } catch { } return _successful; } /// <summary> /// 寫單個無符號16位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_data">16位無符號資料</param> /// <returns></returns> public bool _wuint16(int _addr, byte _stand, UInt16 _data) { bool _successful = false; try { if (_switch1) { byte[] _recebyte = new byte[1000]; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } UInt16 _y = Convert.ToUInt16(_data); byte[] intBuff = BitConverter.GetBytes(_y); sedbyte[0] = _stand; sedbyte[1] = 0x06; sedbyte[2] = _addrL;//MODBUS地址低位 sedbyte[3] = _addrH;//modbus地址高位 sedbyte[4] = intBuff[1]; sedbyte[5] = intBuff[0]; sedbyte[6] = _crcchecking(sedbyte, 0, 6)[0]; sedbyte[7] = _crcchecking(sedbyte, 0, 6)[1]; _SerialPort.Write(sedbyte, 0, 8);//傳送報文 int _reclen = _SerialPort.BytesToRead; _SerialPort.Read(_recebyte, 0, _reclen); if (_reclen > 5) { byte reccrcL = _recebyte[_reclen - 2];//取接收到的報文 校驗碼低位 byte reccrcH = _recebyte[_reclen - 1];//取校驗碼高位 byte[] crc = _crcchecking(_recebyte, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[0] && reccrcH == crc[1])//比對校驗碼 { byte fun = _recebyte[1];//功能碼 if (fun == 0x06)//modbus03功能碼 { _successful = true; } } } } } catch { } return _successful; } /// <summary> /// 寫入單個有符號32位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_data">32位有符號資料</param> /// <returns></returns> public bool _wint32(int _addr, byte _stand, Int32 _data) { bool _successful = false; try { if (_switch1) { byte[] _recebyte = new byte[1000]; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } byte[] intBuff = BitConverter.GetBytes(_data); sedbyte[0] = _stand; sedbyte[1] = 0x10; sedbyte[2] = _addrL;//MODBUS地址低位 sedbyte[3] = _addrH;//modbus地址高位 sedbyte[4] = 0x00; sedbyte[5] = 0x02; sedbyte[6] = 0x04; sedbyte[7] = intBuff[1]; sedbyte[8] = intBuff[0]; sedbyte[9] = intBuff[3]; sedbyte[10] = intBuff[2]; sedbyte[11] = _crcchecking(sedbyte, 0, 11)[0]; sedbyte[12] = _crcchecking(sedbyte, 0, 11)[1]; _SerialPort.Write(sedbyte, 0, 13);//傳送報文 int _reclen = _SerialPort.BytesToRead; _SerialPort.Read(_recebyte, 0, _reclen); if (_reclen > 5) { byte reccrcL = _recebyte[_reclen - 2];//取接收到的報文 校驗碼低位 byte reccrcH = _recebyte[_reclen - 1];//取校驗碼高位 byte[] crc = _crcchecking(_recebyte, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[0] && reccrcH == crc[1])//比對校驗碼 { byte fun = _recebyte[1];//功能碼 if (fun == 0x10)//modbus03功能碼 { _successful = true; } } } } } catch { } return _successful; } /// <summary> /// 寫入單個無符號32位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_data">無符號32位資料</param> /// <returns></returns> public bool _wuint32(int _addr, byte _stand, UInt32 _data) { bool _successful = false; try { if (_switch1) { byte[] _recebyte = new byte[1000]; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } byte[] intBuff = BitConverter.GetBytes(_data); sedbyte[0] = _stand; sedbyte[1] = 0x10; sedbyte[2] = _addrL;//MODBUS地址低位 sedbyte[3] = _addrH;//modbus地址高位 sedbyte[4] = 0x00; sedbyte[5] = 0x02; sedbyte[6] = 0x04; sedbyte[7] = intBuff[1]; sedbyte[8] = intBuff[0]; sedbyte[9] = intBuff[3]; sedbyte[10] = intBuff[2]; sedbyte[11] = _crcchecking(sedbyte, 0, 11)[0]; sedbyte[12] = _crcchecking(sedbyte, 0, 11)[1]; _SerialPort.Write(sedbyte, 0, 13);//傳送報文 int _reclen = _SerialPort.BytesToRead; _SerialPort.Read(_recebyte, 0, _reclen); if (_reclen > 5) { byte reccrcL = _recebyte[_reclen - 2];//取接收到的報文 校驗碼低位 byte reccrcH = _recebyte[_reclen - 1];//取校驗碼高位 byte[] crc = _crcchecking(_recebyte, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[0] && reccrcH == crc[1])//比對校驗碼 { byte fun = _recebyte[1];//功能碼 if (fun == 0x10)//modbus03功能碼 { _successful = true; } } } } } catch { } return _successful; } /// <summary> /// 寫入單個單精度浮點數 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_stand">站號</param> /// <param name="_data">單精度浮點數</param> /// <returns></returns> public bool _wfloat(int _addr, byte _stand, Single _data) { bool _successful = false; try { if (_switch1) { byte[] _recebyte = new byte[1000]; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } byte[] intBuff = BitConverter.GetBytes(_data); sedbyte[0] = _stand; sedbyte[1] = 0x10; sedbyte[2] = _addrL;//MODBUS地址低位 sedbyte[3] = _addrH;//modbus地址高位 sedbyte[4] = 0x00; sedbyte[5] = 0x02; sedbyte[6] = 0x04; sedbyte[7] = intBuff[1]; sedbyte[8] = intBuff[0]; sedbyte[9] = intBuff[3]; sedbyte[10] = intBuff[2]; sedbyte[11] = _crcchecking(sedbyte, 0, 11)[0]; sedbyte[12] = _crcchecking(sedbyte, 0, 11)[1]; _SerialPort.Write(sedbyte, 0, 13);//傳送報文 int _reclen = _SerialPort.BytesToRead; _SerialPort.Read(_recebyte, 0, _reclen); if (_reclen > 5) { byte reccrcL = _recebyte[_reclen - 2];//取接收到的報文 校驗碼低位 byte reccrcH = _recebyte[_reclen - 1];//取校驗碼高位 byte[] crc = _crcchecking(_recebyte, 0, (uint)_reclen - 2);//重新校驗報文 if (reccrcL == crc[0] && reccrcH == crc[1])//比對校驗碼 { byte fun = _recebyte[1];//功能碼 if (fun == 0x10)//modbus03功能碼 { _successful = true; } } } } } catch(Exception ex) { } return _successful; } } public class ModbusTcp : IDisposable { public ModbusTcp(int _Port, string _Ip) { _ip = _Ip; _port = _Port; _online = false; Ping ping = new Ping(); try { PingReply pingReply = ping.Send(_Ip); if (pingReply.Status == IPStatus.Success) { _online = true; // Console.WriteLine("當前線上,已ping通!"); } else { _online = false; } } catch { } } public ModbusTcp() { } public string _ip { get; set; } public int _port { get; set; } public bool _online { get; set; } /// <summary> /// 獲取伺服器是否線上 /// </summary> public bool _conn { get; } private static Socket _SocketClient; // private Socket clientSocket; private Socket _socket { get { if (_SocketClient == null) { int port = _port; string host = _ip;//伺服器端ip地址 IPAddress ip = IPAddress.Parse(host); IPEndPoint ipe = new IPEndPoint(ip, port); _SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _SocketClient.Connect(ipe); return _SocketClient; } //掉線重連 if (!_SocketClient.Connected) { _SocketClient.Close(); int port = _port; string host = _ip;//伺服器端ip地址 IPAddress ip = IPAddress.Parse(host); IPEndPoint ipe = new IPEndPoint(ip, port); _SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _SocketClient.Connect(ipe); return _SocketClient; } return _SocketClient; } } /// <summary> /// 讀取位狀態 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_len">讀取長度</param> /// <returns></returns> public bool[] _bite(int _addr, int _len) { #region /*—————————————————————————————————————————————————————————— * MODBUS_TCP---01功能碼說明 * 讀取多個位狀態 * 傳送報文: * 00 00 00 00 00 06(此位元組之後共有多少位元組) 01(站號)01(功能碼)61(地址高位)80(地址低位) 00(讀取數量高位) 0A (讀取數量低位) * 返回報文: * 00 00 00 00 00 05 01 01 02(讀取結果有多少個位元組) 33(0---7的位寄存) 03(8---15的位寄存) * 讀取的結果以位元組儲存,8位一個位元組,讀取10個位則需要兩個位元組儲存狀態。將位元組拆分,即為單個位狀態 * 關於返回值: * 返回 bool 陣列,陣列的0號值為連續讀取位 的首地址位狀態,陣列1號值為讀取的第二個地址的位狀態 * —————————————————————————————————————————————————— */ #endregion bool[] _bites = new bool[1000]; if (_online) { if (_len >= 1) { int _LEN = _len * 1; byte[] _recebyte = new byte[1000]; byte _lenH = 0; byte _lenL = 1; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _lengbyte = BitConverter.GetBytes(_LEN); byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_LEN > 0xFF) { _lenL = _lengbyte[_lengbyte.Length - 3]; _lenH = _lengbyte[_lengbyte.Length - 4]; } if (_LEN <= 0xFF) { _lenL = 0; _lenH = _lengbyte[0]; } if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } sedbyte[0] = 0x00; sedbyte[1] = 0x00; sedbyte[2] = 0x00; sedbyte[3] = 0x00; sedbyte[4] = 0x00; sedbyte[5] = 0x06; sedbyte[6] = 0x01; sedbyte[7] = 0x01; sedbyte[8] = _addrL;//MODBUS地址低位 sedbyte[9] = _addrH;//modbus地址高位 sedbyte[10] = _lenL;//讀取長度低位 sedbyte[11] = _lenH;//讀取長度高位 try { _socket.Send(sedbyte, 0, 12, SocketFlags.None);//傳送報文 int _recelen = _socket.Receive(_recebyte, 0); int _recl1 = _recebyte[5] + 6; if (_recelen == _recl1) { for (int i = 0; i < _recebyte[8]; i++) { for (int j = 0; j < 8; j++) { _bites[i * 8 + j] = (_recebyte[9 + i] & Convert.ToInt16(Math.Pow(2, j))) == Convert.ToInt16(Math.Pow(2, j)); } } } } catch { } } } return _bites; } /// <summary> /// 讀取單精度浮點數 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_len">讀取長度</param> /// <returns></returns> public float[] _float(int _addr, int _len) { float[] _float = new float[100]; try { if (_online) { if (_len >= 1) { int _LEN = _len * 2; byte[] _recebyte = new byte[1000]; byte _lenH = 0; byte _lenL = 1; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _lengbyte = BitConverter.GetBytes(_LEN); byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_LEN > 0xFF) { _lenL = _lengbyte[_lengbyte.Length - 3]; _lenH = _lengbyte[_lengbyte.Length - 4]; } if (_LEN <= 0xFF) { _lenL = 0; _lenH = _lengbyte[0]; } if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } sedbyte[0] = 0x00; sedbyte[1] = 0x00; sedbyte[2] = 0x00; sedbyte[3] = 0x00; sedbyte[4] = 0x00; sedbyte[5] = 0x06; sedbyte[6] = 0x01; sedbyte[7] = 0x03; sedbyte[8] = _addrL;//MODBUS地址低位 sedbyte[9] = _addrH;//modbus地址高位 sedbyte[10] = _lenL;//讀取長度低位 sedbyte[11] = _lenH;//讀取長度高位 _socket.Send(sedbyte, 0, 12, SocketFlags.None);//傳送報文 int _recelen = _socket.Receive(_recebyte, 0); int _s1 = _len * 4 + 9; if (_recelen == _s1)//校驗返回的資料 { byte[] _bs = new byte[4]; // rec = rec + 1; for (int i = 0; i < _len; i++) { _bs[0] = _recebyte[10 + i * 4]; _bs[1] = _recebyte[9 + i * 4]; _bs[2] = _recebyte[12 + i * 4]; _bs[3] = _recebyte[11 + i * 4]; _float[i] = BitConverter.ToSingle(_bs, 0); } // MessageBox.Show("ok!"); } } } } catch { } return _float; } /// <summary> /// 讀取有符號32位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_len">讀取長度</param> /// <returns></returns> public Int32[] _int32(int _addr, int _len) { Int32[] _int32 = new Int32[100]; try { if (_online) { if (_len >= 1) { int _LEN = _len * 2; byte[] _recebyte = new byte[1000]; byte _lenH = 0; byte _lenL = 1; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _lengbyte = BitConverter.GetBytes(_LEN); byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_LEN > 0xFF) { _lenL = _lengbyte[_lengbyte.Length - 3]; _lenH = _lengbyte[_lengbyte.Length - 4]; } if (_LEN <= 0xFF) { _lenL = 0; _lenH = _lengbyte[0]; } if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } sedbyte[0] = 0x00; sedbyte[1] = 0x00; sedbyte[2] = 0x00; sedbyte[3] = 0x00; sedbyte[4] = 0x00; sedbyte[5] = 0x06; sedbyte[6] = 0x01; sedbyte[7] = 0x03; sedbyte[8] = _addrL;//MODBUS地址低位 sedbyte[9] = _addrH;//modbus地址高位 sedbyte[10] = _lenL;//讀取長度低位 sedbyte[11] = _lenH;//讀取長度高位 _socket.Send(sedbyte, 0, 12, SocketFlags.None);//傳送報文 int _recelen = _socket.Receive(_recebyte, 0); int _s1 = _len * 4 + 9; if (_recelen == _s1)//校驗返回的資料 { byte[] _bs = new byte[4]; // rec = rec + 1; for (int i = 0; i < _len; i++) { _bs[0] = _recebyte[10 + i * 4]; _bs[1] = _recebyte[9 + i * 4]; _bs[2] = _recebyte[12 + i * 4]; _bs[3] = _recebyte[11 + i * 4]; _int32[i] = BitConverter.ToInt32(_bs, 0); } // MessageBox.Show("ok!"); } } } } catch { } return _int32; } /// <summary> /// 讀取無符號32位資料 /// </summary> /// <param name="_addr">MODBUS地址</param> /// <param name="_len">讀取長度</param> /// <returns></returns> public uint[] _uint32(int _addr, int _len) { uint[] _uint = new uint[100]; try { if (_online) { if (_len >= 1) { int _LEN = _len * 2; byte[] _recebyte = new byte[1000]; byte _lenH = 0; byte _lenL = 1; byte _addrH = 0; byte _addrL = 1; byte[] sedbyte = new byte[20]; byte[] _lengbyte = BitConverter.GetBytes(_LEN); byte[] _addrbyte = BitConverter.GetBytes(_addr); if (_LEN > 0xFF) { _lenL = _lengbyte[_lengbyte.Length - 3]; _lenH = _lengbyte[_lengbyte.Length - 4]; } if (_LEN <= 0xFF) { _lenL = 0; _lenH = _lengbyte[0]; } if (_addr > 0xFF) { _addrL = _addrbyte[_addrbyte.Length - 3]; _addrH = _addrbyte[_addrbyte.Length - 4]; } if (_addr <= 0xFF) { _addrL = 0; _addrH = _addrbyte[0]; } sedbyte[0] = 0x00; sedbyte[1] = 0x00; sedbyte[2] = 0x00; sedbyte[3] = 0x00;