1.Mymath
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BIZHexagonalDevice
{
class MyMath
{
/// <summary>
/// 字符串转BYTE数组
/// </summary>
/// <param name="data"></param>
/// <returns>高位在前</returns>
static public byte[] StrToByte(string data)
{
byte[] bt = new byte[data.Length / 2];
for (int i = 0; i < data.Length / 2; i++)
{
bt[i] = Convert.ToByte(data.Substring(i * 2, 2), 16);
}
return bt;
}
/// <summary>
/// byte数组转STRING
/// </summary>
/// <param name="Bytes"></param>
/// <returns></returns>
static public string BytetoStr(byte[] Bytes)
{
string str = string.Empty;
str = BitConverter.ToString(Bytes, 0).Replace("-", string.Empty).ToLower();
return str;
}
/// <summary>
/// 计算CRC-16
/// </summary>
/// <param name="data"></param>
/// <returns>高位在前</returns>
static public string CRC_16(string data)
{
if ((data.Length % 2) != 0) { throw new Exception("Parameter\"data\"length error"); }
byte[] tmp = StrToByte(data);
/*
1、预置16位寄存器为十六进制FFFF(即全为1)。称此寄存器为CRC寄存器;
2、把第一个8位数据与16位CRC寄存器的低位相异或,把结果放于CRC寄存器;
3、把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位;
4、如果最低位为0:重复第3步(再次移位); 如果最低位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
5、重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
6、重复步骤2到步骤5,进行下一个8位数据的处理;
7、最后得到的CRC寄存器即为CRC码。
*/
UInt16 CRCREG = (UInt16)0xffff;
for (int i = 0; i < tmp.Length; i++)
{
CRCREG = (UInt16)(CRCREG ^ (UInt16)tmp[i]);//<< 8;
for (int j = 0; j < 8; j++)
{
UInt16 CRCtmp = (UInt16)(CRCREG & (UInt16)0x0001);
CRCREG = (UInt16)(CRCREG >> (UInt16)1);
if (CRCtmp == (UInt16)1)
{
CRCREG = (UInt16)(CRCREG ^ (UInt16)0xA001);
}
}
}
string strtmp = CRCREG.ToString("X4");
return strtmp.Substring(2, 2) + strtmp.Substring(0, 2);
//return strtmp;
}
}
}
2.modbus rtu通讯协议
using System;
using System.Collections.Generic;
using System.Text;
//using WFDLL;
namespace WfpRTU
{
public class Modbus
{
protected string _PortName;
public string PortName
{
get { return _PortName; }
set
{
_PortName = value;
SP.PortName = _PortName;
}
}
protected int _PortBaud;
public int PortBaud
{
get { return _PortBaud; }
set
{
_PortBaud = value;
SP.PortBaud = _PortBaud;
}
}
protected int _Timeout;
public int Timeout
{
get { return _Timeout; }
set
{
_Timeout = value;
SP.Timeout = _Timeout;
}
}
protected System.IO.Ports.Parity _parity;
public System.IO.Ports.Parity Parity
{
get { return _parity; }
set
{
_parity = value;
SP.Parity = _parity;
}
}
protected MySerialPort SP = new MySerialPort();
public Modbus()
{
}
public Modbus(string PName, int PBaud, System.IO.Ports.Parity parity, int timeout)
{
_PortName = PName;
_PortBaud = PBaud;
_Timeout = timeout;
_parity = parity;
SP.PortName = _PortName;
SP.PortBaud = _PortBaud;
SP.Timeout = timeout;
SP.Parity = parity;
}
/// <summary>
/// 读取设备识别码(F0x2B)
/// </summary>
/// <param name="CommAddr">通讯地址</param>
/// <param name="ReadDevId">ReadDevId</param>
/// <param name="ObjectId">对象ID</param>
/// <param name="data">数据</param>
/// <returns></returns>
public MODBUSRESULT ReadDeviceRegister(string CommAddr, UInt16 ReadDevId, UInt16 ObjectId, out string data)
{
if ((CommAddr.Length % 2) != 0) { throw new Exception("CommAddr data length error"); }
StringBuilder cmd = new StringBuilder();
cmd.Append(CommAddr); //通讯地址
cmd.Append("2B"); //功能码
cmd.Append("0E"); //MEI类型
cmd.Append(ReadDevId.ToString("X2")); //01
cmd.Append(ObjectId.ToString("X2")); //00
cmd.Append(MyMath.CRC_16(cmd.ToString()));
return SP.SendAndReceive(cmd.ToString(),7, out data);
}
/// <summary>
/// 读取多个线圈
/// </summary>
/// <param name="CommAddr">通讯地址</param>
/// <param name="FunCode">功能码</param>
/// <param name="StartAddr">起始地址</param>
/// <param name="RegCount">线圈数</param>
/// <param name="data">数据</param>
/// <returns></returns>
public MODBUSRESULT ReadMultiCoil(string CommAddr, byte FunCode, UInt16 StartAddr, UInt16 RegCount, out string data)
{
if ((CommAddr.Length % 2) != 0) { throw new Exception("CommAddr data length error"); }
StringBuilder cmd = new StringBuilder();
cmd.Append(CommAddr); //通讯地址
cmd.Append(FunCode.ToString("X2"));
cmd.Append(StartAddr.ToString("X4")); //起始地址
cmd.Append(RegCount.ToString("X4")); //线圈数
cmd.Append(MyMath.CRC_16(cmd.ToString()));
double cnt=RegCount / 8;
return SP.SendAndReceive(cmd.ToString(), Convert.ToUInt16(Math.Ceiling(cnt)) + 4 + CommAddr.Length / 2, out data);
}
/// <summary>
/// 写多个线圈
/// </summary>
/// <param name="CommAddr"></param>
/// <param name="StartAddr"></param>
/// <param name="RegCount"></param>
/// <param name="data"></param>
/// <returns></returns>
public MODBUSRESULT WriteMultiCoil(string CommAddr, byte FunCode, UInt16 StartAddr, string data)
{
if ((data.Length % 2) != 0) { throw new Exception("Data length error"); }
StringBuilder cmd = new StringBuilder();
cmd.Append(CommAddr); //通讯地址
cmd.Append(FunCode.ToString("X2"));
cmd.Append(StartAddr.ToString("X4")); //起始地址
//int RegCount = data.Length / 4;
int bytecnt = data.Length / 2;
int RegCount = bytecnt * 8;//--------------------------------------tgw-------------------
cmd.Append(RegCount.ToString("X4")); //寄存器数
//int bytecnt = RegCount * 2;
cmd.Append(bytecnt.ToString("X2")); //字节计数
cmd.Append(data);
cmd.Append(MyMath.CRC_16(cmd.ToString()));
return SP.SendAndReceive(cmd.ToString(), 7 + CommAddr.Length / 2, out data);
}
/ <summary>
/ 读取输入寄存器(F0x04)
/ </summary>
/ <param name="CommAddr">通讯地址</param>
/ <param name="StartAddr">起始地址</param>
/ <param name="RegNum">寄存器数</param>
/ <param name="data">数据</param>
/ <returns></returns>
//public MODBUSRESULT ReadInputRegister(string CommAddr, UInt16 StartAddr, UInt16 RegCount, out string data)
//{
// if ((CommAddr.Length % 2) != 0) { throw new Exception("CommAddr数据长度错误"); }
// StringBuilder cmd = new StringBuilder();
// cmd.Append(CommAddr); //通讯地址
// cmd.Append("04");
// cmd.Append(StartAddr.ToString("X4")); //起始地址
// cmd.Append(RegCount.ToString("X4")); //寄存器数
// cmd.Append(MyMath.CRC_16(cmd.ToString()));
// return SP.SendAndReceive(cmd.ToString(), RegCount * 2 + 4 + CommAddr.Length / 2, out data);
//}
/ <summary>
/ 读取保持寄存器(F0x03)
/ </summary>
/ <param name="CommAddr">通讯地址</param>
/ <param name="StartAddr">起始地址</param>
/ <param name="RegNum">寄存器数</param>
/ <param name="data">数据</param>
/ <returns></returns>
//public MODBUSRESULT ReadHoldingRegister(string CommAddr, UInt16 StartAddr, UInt16 RegCount, out string data)
//{
// if ((CommAddr.Length % 2) != 0) { throw new Exception("CommAddr数据长度错误"); }
// StringBuilder cmd = new StringBuilder();
// cmd.Append(CommAddr); //通讯地址
// cmd.Append("03");
// cmd.Append(StartAddr.ToString("X4")); //起始地址
// cmd.Append(RegCount.ToString("X4")); //寄存器数
// cmd.Append(MyMath.CRC_16(cmd.ToString()));
// return SP.SendAndReceive(cmd.ToString(), RegCount * 2 + 4 + CommAddr.Length / 2, out data);
//}
/// <summary>
/// 读取多个寄存器
/// </summary>
/// <param name="CommAddr">通讯地址</param>
/// <param name="FunCode">功能码</param>
/// <param name="StartAddr">起始地址</param>
/// <param name="RegCount">寄存器数</param>
/// <param name="data">数据</param>
/// <returns></returns>
public MODBUSRESULT ReadMultiRegister(string CommAddr, byte FunCode,UInt16 StartAddr, UInt16 RegCount, out string data)
{
if ((CommAddr.Length % 2) != 0) { throw new Exception("CommAddr data length error"); }
StringBuilder cmd = new StringBuilder();
cmd.Append(CommAddr); //通讯地址
cmd.Append(FunCode.ToString("X2"));
cmd.Append(StartAddr.ToString("X4")); //起始地址
string str = RegCount.ToString("X4");
cmd.Append(str); //寄存器数
cmd.Append(MyMath.CRC_16(cmd.ToString()));
return SP.SendAndReceive(cmd.ToString(), RegCount * 2 + 4 + CommAddr.Length / 2, out data);
}
/// <summary>
/// 写多个寄存器
/// </summary>
/// <param name="CommAddr"></param>
/// <param name="StartAddr"></param>
/// <param name="RegCount"></param>
/// <param name="data"></param>
/// <returns></returns>
public MODBUSRESULT WriteMultiRegister(string CommAddr, byte FunCode, UInt16 StartAddr, string data)
{
if ((data.Length % 4) != 0) { throw new Exception("Data length error"); }
StringBuilder cmd = new StringBuilder();
cmd.Append(CommAddr); //通讯地址
cmd.Append(FunCode.ToString("X2"));
cmd.Append(StartAddr.ToString("X4")); //起始地址
int RegCount = data.Length / 4;
cmd.Append(RegCount.ToString("X4")); //寄存器数
int bytecnt = RegCount * 2;
cmd.Append(bytecnt.ToString("X2")); //字节计数
cmd.Append(data);
cmd.Append(MyMath.CRC_16(cmd.ToString()));
return SP.SendAndReceive(cmd.ToString(), 7 + CommAddr.Length / 2, out data);
}
public static string GetResultMsg(MODBUSRESULT ret)
{
string msg = "";
switch (ret)
{
case MODBUSRESULT.DataAddrInvalid:
msg = "Data address invalid";
break;
case MODBUSRESULT.DataCheckFall:
msg = "Data validation failure";
break;
case MODBUSRESULT.DataFormatError:
msg = "Data format error";
break;
case MODBUSRESULT.DataValueInvalid:
msg = "Data value invalid";
break;
case MODBUSRESULT.OK:
msg = "Correct";
break;
case MODBUSRESULT.PortOpenFall:
msg = "Open port failure";
break;
case MODBUSRESULT.Timeout:
msg = "Communication timeout";
break;
case MODBUSRESULT.UnknownError:
msg = "Unknown error";
break;
case MODBUSRESULT.UnknownFunCode:
msg = "Unsupported function code";
break;
default:
msg = "Unknown error";
break;
}
return msg;
}
public static string GetRegValue(string data,int StartReg,int RegNum)//按字符
{
int offset = 6;
int startpoint = offset + StartReg * 4;
int len = RegNum * 4;
return data.Substring(startpoint, len).ToUpper();
}
public static string GetByteValue(string data, int StartReg, int RegNum)//按字符
{
int offset = 6;
int startpoint = offset + StartReg * 2;
int len = RegNum * 2;
return data.Substring(startpoint, len).ToUpper();
}
}
}
3.csv文件读写
/*
* Created by SharpDevelop.
* User: sz
* Date: 2007/12/10
* Time: 18:09
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace WfpRTU
{
/// <summary>
/// CSVUtil is a helper class handling csv files.
/// </summary>
public class CSVUtil
{
private CSVUtil()
{
}
//write a new file, existed file will be overwritten
public static void WriteCSV(string filePathName,List<String[]>ls)
{
WriteCSV(filePathName,false,ls);
}
//write a file, existed file will be overwritten if append = false
public static void WriteCSV(string filePathName,bool append, List<String[]> ls)
{
StreamWriter fileWriter=new StreamWriter(filePathName,append,Encoding.Default);
foreach(String[] strArr in ls)
{
fileWriter.WriteLine(String.Join(",",strArr));
}
fileWriter.Flush();
fileWriter.Close();
}
public static List<String[]> ReadCSV(string filePathName)
{
List<String[]> ls = new List<String[]>();
StreamReader fileReader=new StreamReader(filePathName);
string strLine="";
while (strLine != null)
{
strLine = fileReader.ReadLine();
if (strLine != null && strLine.Length>0)
{
ls.Add(strLine.Split(','));
//Debug.WriteLine(strLine);
}
}
fileReader.Close();
return ls;
}
}
}
4.串口接收触发事件
private void Com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(1000);
if (Com.IsOpen)
{
try
{
byte[] ReDatas = new byte[Com.BytesToRead];
if (Com.BytesToRead <= 0)
{
txtData.Text = "没查询到数据,请检查设置";
}
else
{
Com.Read(ReDatas, 0, ReDatas.Length);
string temHex = BytesToHex(ReDatas);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "出错提示!!!!!");
txtData.Text = "";
}
}
else
{
txtData.Clear();
txtData.Text = "请检查串口是否打开";
}
}