using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Ports; namespace serial { public class ModBus { /// <summary> /// modbus状态 /// </summary> public static string modbusStatus; /// <summary> /// 定义SerialPort变量 /// </summary> public static SerialPort Port = new SerialPort(); /// <summary> /// 打开串口 /// </summary> /// <param name="m_Port">串口号</param> /// <param name="BaudRate">波特率</param> /// <param name="m_dataBits">数据位</param> /// <param name="m_Parity">奇偶校验</param> /// <param name="m_StopBits">停止位</param> /// <returns>返回BOOL型,True为成功,False为失败</returns> public static bool OpenPort(string m_Port, int BaudRate, int m_dataBits, Parity m_Parity, StopBits m_StopBits) { if (Port.IsOpen) { return true; } else { Port.PortName = m_Port; Port.BaudRate = BaudRate; Port.DataBits = m_dataBits; Port.Parity = m_Parity; Port.StopBits = m_StopBits; Port.Open(); if (Port.IsOpen) { return true; } else { return false; } } } /// <summary> /// 关闭串口 /// </summary> /// <returns>返回BOOL型,True为成功,False为失败</returns> public static bool PortClose() { if (Port.IsOpen) { Port.Close(); return true; } else { return false; } } public static void GetCRC(byte[] message, byte[] CRC) { //Function expects a modbus message of any length as well as a 2 byte CRC array in which to //return the CRC values: ushort CRCFull = 0xFFFF; byte CRCHigh = 0xFF, CRCLow = 0xFF; char CRCLSB; for (int i = 0; i < (message.Length) -2; i++) { CRCFull = (ushort)(CRCFull ^ message[i]); for (int j = 0; j < 8; j++) { CRCLSB = (char)(CRCFull & 0x0001); CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF); if (CRCLSB == 1) CRCFull = (ushort)(CRCFull ^ 0xA001); } } CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF); CRC[0] = CRCLow = (byte)(CRCFull & 0xFF); } /// <summary> /// CRC16算法 /// </summary> /// <param name="te">原始数组</param> /// <param name="message">保存变量</param> public static void BuildMessage(byte[] te, ref byte[] message) { //Array to receive CRC bytes: byte[] CRC = new byte[2]; for (int i = 0; i < te.Length; i++) { message[i] = te[i]; } GetCRC(message, CRC); message[message.Length - 2] = CRC[0]; message[message.Length - 1] = CRC[1]; } /// <summary> /// 发送数据 /// </summary> /// <param name="m_date">需写入的数据</param> /// <param name="type">操作类型0为多输出口控制与open参数不共用,1为单控制口输出open为255时线圈闭合0时线圈释放</param> /// <param name="open">1为单控制口输出open为255时线圈闭合0时线圈释放</param> /// <returns>返回True或false</returns> public static bool SendMessage(byte m_date,int type,bool open=true) { if (!Port.IsOpen) { return false; } else { switch (type) { case 0://多个DO输出控制数据位{ 地址, 功能, 线圈起始地址前位, 线圈起始地址后位, 线圈结束地址前位, 线圈结束地址后位, 数据字节, 线圈状态 }; byte[] data = new byte[10]; byte[] dd = { 1, 15, 0, 0, 0, 8, 1, m_date }; ModBus.BuildMessage(dd, ref data); Port.Write(data, 0, data.Length); break; case 1://单个控制输出{ 地址, 功能, 线圈起始地址前位, 需控制的线圈地址, 开关状态255为开0为关, 线圈开关后位 }; byte[] data_one = new byte[8]; byte temp0; if (open) { temp0 = 255; } else { temp0 = 0; } byte[] dd1 = { 1, 5, 0, m_date, temp0, 0 }; ModBus.BuildMessage(dd1, ref data_one); Port.Write(data_one, 0, data_one.Length); break; case 2: byte[] getsig = new byte[8]; byte[] getsige = { 1, 2, 0, 0, 0, m_date }; ModBus.BuildMessage(getsige, ref getsig); Port.Write(getsig, 0, getsig.Length); break; case 3: break; } return true; } } #region Check Response private static bool CheckResponse(byte[] response) { //Perform a basic CRC check: byte[] CRC = new byte[2]; GetCRC(response, CRC); if (CRC[0] == response[response.Length - 2] && CRC[1] == response[response.Length - 1]) return true; else return false; } #endregion #region Get Response private static void GetResponse(ref byte[] response) { //There is a bug in .Net 2.0 DataReceived Event that prevents people from using this //event as an interrupt to handle data (it doesn‘t fire all of the time). Therefore //we have to use the ReadByte command for a fixed length as it‘s been shown to be reliable. for (int i = 0; i < response.Length; i++) { response[i] = (byte)(Port.ReadByte()); } } #endregion public static bool GetModbusData(ref byte[] values) { if (Port.IsOpen) { int count = Port.BytesToRead; if (count > 0) { byte[] readBuffer = new byte[count]; GetResponse(ref readBuffer); // CRC 验证 if (CheckResponse(readBuffer)) { //显示输入数据 values = readBuffer; Port.DiscardInBuffer(); return true; } else { Port.DiscardInBuffer(); return false; } } else return false; } else return false; } } }
原文:https://www.cnblogs.com/qq1151219115/p/10937022.html