实例介绍
【实例简介】
【实例截图】
【实例截图】
【核心代码】
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.IO.Ports; using System.Threading; using System.Drawing; public class XinJie //信捷PLC通信协议 { SerialPort Port = new SerialPort(); private int PortBusy; private byte cmdType; public object LockcomportObj = new object(); private int returnValue; private int dataCnt = 1; private int[] returnArr; public double comErrorCnt = 0; public bool bConnection = false; public string comStatus = "OK"; private byte modbus = 0x01; public bool readM(int address, out bool M) { int[] re = new int[0]; bool result; result = comPLC(0x01, address, 1, 1, ref re); if (result == true) { if (re[0] == 1) M = true; else M = false; return true; } else { M = false; return false; } } public bool writeM(int address, bool state) { int[] re = new int[0]; bool result; if (state == true) { result = comPLC(0x05, address, 1, 1, ref re); } else { result = comPLC(0x05, address, 0, 1, ref re); } if (result == true) { return true; } else { return false; } } public bool writeHM(int address, bool state) { int[] re = new int[0]; bool result; if (state == true) { result = comPLC(0x105, address, 1, 1, ref re); } else { result = comPLC(0x105, address, 0, 1, ref re); } if (result == true) { return true; } else { return false; } } public bool readSingleD(int address, out int Data) { bool result; int[] re; re = new int[0]; result = comPLC(0x03, address, 1, 1, ref re); if (result == true) { Data = re[0]; return true; } else { Data = 0; return false; } } public bool readDoubleD(int address, out int Data) { bool result; int[] re; re = new int[0]; result = comPLC(0x20, address, 1, 1, ref re); if (result == true) { Data = re[0]; return true; } else { Data = 0; return false; } } public bool readMultipleD(int address, int cnt, out int[] Data) { bool result; int[] re; re = new int[0]; result = comPLC(0x20, address, 1, cnt, ref re); if (result == true) { Data = re; return true; } else { Data = new int[0]; return false; } } //public bool writeSingleD(int address, int state) //{ // bool result; // int[] re; // re = new int[0]; // result = comPLC(0x10, address, state, 1, ref re); // return true; //} public bool writeDoubleD(int address, int state) { bool result; int[] re; re = new int[0]; result = comPLC(0x10, address, state, 1, ref re); if (result == true) { return true; } else { return false; } } public bool writeDoubleHD(int address, int state) { bool result; int[] re; re = new int[0]; result = comPLC(0x110, address, state, 1, ref re); if (result == true) { return true; } else { return false; } } public XinJie() { this.Port.DataReceived = new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived); } public void OpenPort(int PortID, int BaudRate) { try { Port.PortName = "COM" PortID.ToString(); //选择COM端口 Port.BaudRate = BaudRate; //设置波特率 Port.DataBits = 8; //设置每个字节的标准数据位长度 Port.StopBits = StopBits.One; //设置每个字节的标准停止位数 Port.Parity = Parity.Even; //设置奇偶校验检查协议 Port.ReadBufferSize = 2048; //设置输入缓冲区的大小 Port.WriteBufferSize = 2048; //设置输出缓冲区的大小 Port.ReadTimeout = 500; //设置读取操作未完成时发生超时之前的毫秒数 Port.WriteTimeout = 500; //设置写入操作未完成时发生超时之前的毫秒数 Port.ReceivedBytesThreshold = 5; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Open(); PortBusy = 0; } catch (Exception ex) { //MessageBox.Show("COM" PortID.ToString() "打开失败!"); } } public void ClosePort() { Port.Close(); } public bool comPLC(int type, int address, int state, int DataCnt, ref int[] result) { lock (LockcomportObj) { byte[] Mdata = new byte[30]; uint crcbuf; try { if (DataCnt < 1) throw new Exception(); dataCnt = DataCnt;//先声明读数据长度 int returnData = -1; result = new int[DataCnt]; while (PortBusy != 0)//如果串口被占用,则等待 { Application.DoEvents(); } int resendCnt; DateTime sendtime = DateTime.Now; PortBusy = 1; resendCnt = 1; Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); switch (type) { case 0x01://读单个线圈状态 #region 读单个线圈状态 cmdType = 0x01; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x01;//功能码 Mdata[2] = Convert.ToByte(address >> 8); ;//线圈起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//线圈起始地址低位 Mdata[4] = 0x00;//数据总位数高位 Mdata[5] = 0x10;//数据总位数低位 crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 7; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 2)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done1; } } } result[0] = returnArr[0]; returnData = 1; Done1: #endregion break; case 0x03://读单个寄存器 #region 读单个寄存器 cmdType = 0x03; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x03;//功能码 写多个寄存器 Mdata[2] = Convert.ToByte(address >> 8); //起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//起始地址地位 Mdata[4] = 0x00;//寄存器总数高位 Mdata[5] = 0x01;//寄存器总数低位 1 crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 7; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 2)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done3; } } } result[0] = returnArr[0]; returnData = 1; Done3: #endregion break; case 0x05://强制写单个线圈 #region 强制写单个线圈 cmdType = 0x05; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x05;//功能码 强制单个线圈 Mdata[2] = Convert.ToByte(address >> 8); ;//线圈地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//线圈地址地位 if (state == 0) { Mdata[4] = 0x00;//强制OFF Mdata[5] = 0x00; } else { Mdata[4] = 0xFF;//强制ON Mdata[5] = 0x00; } crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 8; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 3)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done5; } } } returnData = 1; Done5: #endregion break; case 0x10://强制写双个寄存器 #region 强制写双个寄存器 cmdType = 0x10; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x10;//功能码 写多个寄存器 Mdata[2] = Convert.ToByte(address >> 8); //起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//起始地址地位 Mdata[4] = 0x00;//寄存器总数高位 Mdata[5] = 0x02;//寄存器总数低位 2 Mdata[6] = 0x04;//寄存数总字节数 4byte Mdata[7] = Convert.ToByte(((state & 0xFFFF) >> 8) & 0xFF); //D0 Mdata[8] = Convert.ToByte((state & 0xFFFF) & 0xFF); Mdata[9] = Convert.ToByte(((state >> 16) >> 8) & 0xFF); //D1 Mdata[10] = Convert.ToByte((state >> 16) & 0xFF); crcbuf = CRC16(Mdata, 11); Mdata[11] = Convert.ToByte(crcbuf & 0xFF); Mdata[12] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 8; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 13); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 5)//超时最多连续发送5次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 13); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done10; } } } returnData = 1; Done10: #endregion break; case 0x20://读多个寄存器 #region 读多个寄存器 cmdType = 0x20; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x03;//功能码 写多个寄存器 Mdata[2] = Convert.ToByte(address >> 8); //起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//起始地址地位 Mdata[4] = 0x00;//寄存器总数高位 Mdata[5] = Convert.ToByte(DataCnt * 2);//寄存器总数低位 crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 5 4 * DataCnt; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 2)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done3; } } } result = returnArr; returnData = 1; Done20: #endregion break; //XDplc case 0x101://读单个线圈状态-HM #region 读单个线圈状态 cmdType = 0x01; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x01;//功能码 address = 49408; Mdata[2] = Convert.ToByte(address >> 8); ;//线圈起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//线圈起始地址低位 Mdata[4] = 0x00;//数据总位数高位 Mdata[5] = 0x10;//数据总位数低位 crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 7; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 2)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done101; } } } result[0] = returnArr[0]; returnData = 1; Done101: #endregion break; case 0x103://读单个寄存器-HD #region 读单个寄存器 cmdType = 0x03; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x03;//功能码 写多个寄存器 address = 41088; Mdata[2] = Convert.ToByte(address >> 8); //起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//起始地址地位 Mdata[4] = 0x00;//寄存器总数高位 Mdata[5] = 0x01;//寄存器总数低位 1 crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 7; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 2)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done103; } } } result[0] = returnArr[0]; returnData = 1; Done103: #endregion break; case 0x105://强制写单个线圈-HM #region 强制写单个线圈 cmdType = 0x05; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x05;//功能码 强制单个线圈 address = 49408; Mdata[2] = Convert.ToByte(address >> 8); ;//线圈地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//线圈地址地位 if (state == 0) { Mdata[4] = 0x00;//强制OFF Mdata[5] = 0x00; } else { Mdata[4] = 0xFF;//强制ON Mdata[5] = 0x00; } crcbuf = CRC16(Mdata, 6); Mdata[6] = Convert.ToByte(crcbuf & 0xFF); Mdata[7] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 8; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 8); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 3)//超时最多连续发送2次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 8); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done105; } } } returnData = 1; Done105: #endregion break; case 0x110://强制写双个寄存器-HD #region 强制写双个寄存器 cmdType = 0x10; Mdata[0] = modbus;//modbus站号 Mdata[1] = 0x10;//功能码 写多个寄存器 address = 41088; Mdata[2] = Convert.ToByte(address >> 8); //起始地址高位 Mdata[3] = Convert.ToByte(address & 0xFF);//起始地址地位 Mdata[4] = 0x00;//寄存器总数高位 Mdata[5] = 0x02;//寄存器总数低位 2 Mdata[6] = 0x04;//寄存数总字节数 4byte Mdata[7] = Convert.ToByte(((state & 0xFFFF) >> 8) & 0xFF); //D0 Mdata[8] = Convert.ToByte((state & 0xFFFF) & 0xFF); Mdata[9] = Convert.ToByte(((state >> 16) >> 8) & 0xFF); //D1 Mdata[10] = Convert.ToByte((state >> 16) & 0xFF); crcbuf = CRC16(Mdata, 11); Mdata[11] = Convert.ToByte(crcbuf & 0xFF); Mdata[12] = Convert.ToByte(crcbuf >> 8); Port.ReceivedBytesThreshold = 8; //设置 DataReceived 事件发生前内部输入缓冲区中的字节数 Port.Write(Mdata, 0, 13); resendCnt = 1; while (PortBusy != 0) { if (sendtime.AddMilliseconds(100) < DateTime.Now)//串口通讯超时 { if (resendCnt < 5)//超时最多连续发送5次 { Port.DiscardInBuffer();//清空接收缓冲区 Port.DiscardOutBuffer(); Port.Write(Mdata, 0, 13); sendtime = DateTime.Now; resendCnt = resendCnt 1; } else { returnData = -1; goto Done110; } } } returnData = 1; Done110: #endregion break; default: returnData = -1; break; } PortBusy = 0; if (returnData == -1) { comErrorCnt ; comStatus = "NG"; return false; } else { comStatus = "OK"; return true; } } catch (Exception ex) { result = new int[1]; PortBusy = 0; comErrorCnt ; comStatus = "NG"; return false; } } } private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) { try { byte[] readBuf = new byte[Port.ReadBufferSize];//返回字节数据 int readcnt = Port.Read(readBuf, 0, Port.ReadBufferSize); //uint readcrc; //byte readcrcHi, readcrcLo; //readcrc = CRC16(readBuf, readcnt - 2); //readcrcHi = Convert.ToByte(readcrc & 0xFF); //readcrcLo = Convert.ToByte(readcrc >> 8); //if ((readcrcHi == readBuf[readcnt - 2]) & (readcrcLo == readBuf[readcnt - 1]))//CRC校验码正确 if (readBuf[0] == modbus)//modbus站号正确 { switch (cmdType)//功能码 { case 0x01://读单个线圈状态 if ((readBuf[1] == cmdType) && (readcnt >= (7 - 2)))//功能码正确并且返回字节长度 { if ((readBuf[3] & 0x0001) == 0x01) { returnValue = 1; returnArr = new int[dataCnt]; returnArr[0] = returnValue; PortBusy = 0; } if ((readBuf[3] & 0x0001) == 0x00) { returnValue = 0; returnArr = new int[dataCnt]; returnArr[0] = returnValue; PortBusy = 0; } } break; case 0x03://读单个寄存器 if ((readBuf[1] == cmdType) && (readcnt >= (7 - 2)))//功能码正确并且返回字节长度正确 { returnValue = readBuf[3] * 256 readBuf[4] * 1; if (returnValue >= 32768) { returnValue = returnValue - 65536; } returnArr = new int[dataCnt]; returnArr[0] = returnValue; PortBusy = 0; } break; case 0x05://强制写单个线圈 if ((readBuf[1] == cmdType) && (readcnt >= (8 - 2)))//功能码正确并且返回字节长度正确 { PortBusy = 0; } break; case 0x10://强制写双个寄存器 if ((readBuf[1] == cmdType) && (readcnt >= (8 - 2)))//功能码正确并且返回字节长度正确 { PortBusy = 0; } break; case 0x20://读取多个寄存器 if ((readBuf[1] == 0x03) && (readcnt >= (5 4 * dataCnt - 2)))//功能码正确并且返回字节长度正确 { returnArr = new int[dataCnt]; for (int i = 0; i < dataCnt; i ) { long d0 = readBuf[3 i * 4] * 256 readBuf[4 i * 4] * 1; long d1 = readBuf[5 i * 4] * 256 readBuf[6 i * 4] * 1; double dd = d1 * 65536 d0; if (dd >= 2147483648) { dd = dd - 2147483648 - 2147483648; } returnArr[i] = Convert.ToInt32(dd); } PortBusy = 0; } break; default: break; } } } catch (Exception ex) { } } private uint CRC16(byte[] cmdstring, int lenstring) { int i, j; uint tmp; uint crc = 0xFFFF; for (i = 0; i < lenstring; i ) { crc = crc ^ cmdstring[i]; for (j = 0; j < 8; j ) { tmp = crc & 0x0001; crc = crc >> 1; if (tmp == 1) { crc = crc ^ 0xA001; } } } return (crc); } }
好例子网口号:伸出你的我的手 — 分享!
网友评论
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
支持(0) 盖楼(回复)