[Modbus] 如何 用 C# 開發 Modbus Master Protocol - (11) 實作 HexModbusDataConvert
續上篇,產出的資料若都是 byte[] 實在很難閱讀,所以這個 HexModbusDataConvert 類別專處理資料格式轉換
這只是很簡單的進制轉換,要參考的資料很多
[C#.NET] 開發通訊協定必須要會的技巧
[C#.NET] 處理通訊協定的事前準備
[C#.NET] 浮點數 轉 Hexadecimal
[C#.NET] Hexadecimal 字串格式轉時間格式
[C#][VB.NET] 進制轉換 (2進制、8進制、16進制)轉10進制
[VB6][C#][VB.Net] 進制轉換,2進制轉(10進制、8進制、16進制)
{
public override byte[] ResultArray { get; internal set; }
public override IEnumerable<long> ToDecimal(byte[] ResultArray, EnumModbusIntegralUnit Unit)
{
var length = (int)Unit;
if (ResultArray == null)
{
throw new ArgumentNullException("ResultArray");
}
if (ResultArray.Length <= 0 || ResultArray.Length < length)
{
throw new FormatException("ResultArray");
}
this.ResultArray = ResultArray;
List<long> resultList = new List<long>();
for (int i = 0; i < ResultArray.Length; i = i + length)
{
using (MemoryStream memory = new MemoryStream())
{
memory.Write(ResultArray, i, length);
var tempArray = memory.ToArray();
long result = 0;
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tempArray);
}
switch (Unit)
{
case EnumModbusIntegralUnit.Byte:
result = tempArray[0];
break;
case EnumModbusIntegralUnit.Word:
result = BitConverter.ToInt16(tempArray, 0);
break;
case EnumModbusIntegralUnit.DWord:
result = BitConverter.ToInt32(tempArray, 0);
break;
case EnumModbusIntegralUnit.QWord:
result = BitConverter.ToInt64(tempArray, 0);
break;
default:
throw new ArgumentOutOfRangeException("Unit");
}
resultList.Add(result);
}
}
return resultList;
}
public override IEnumerable<long> ToOctal(byte[] ResultArray, EnumModbusIntegralUnit Unit)
{
var length = (int)Unit;
if (ResultArray == null)
{
throw new ArgumentNullException("ResultArray");
}
if (ResultArray.Length <= 0 || ResultArray.Length < length)
{
throw new FormatException("ResultArray");
}
this.ResultArray = ResultArray;
List<long> resultList = new List<long>();
for (int i = 0; i < ResultArray.Length; i = i + length)
{
using (MemoryStream memory = new MemoryStream())
{
memory.Write(ResultArray, i, length);
var tempArray = memory.ToArray();
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tempArray);
}
switch (Unit)
{
case EnumModbusIntegralUnit.Byte:
var dec = tempArray[0];
var oct = int.Parse(Convert.ToString(dec, 8));
resultList.Add(oct);
break;
case EnumModbusIntegralUnit.Word:
var decShort = BitConverter.ToInt16(tempArray, 0);
var octShort = int.Parse(Convert.ToString(decShort, 8));
resultList.Add(octShort);
break;
case EnumModbusIntegralUnit.DWord:
var decInt = BitConverter.ToInt32(tempArray, 0);
var octInt = long.Parse(Convert.ToString(decInt, 8));
resultList.Add(octInt);
break;
case EnumModbusIntegralUnit.QWord:
var decLong = BitConverter.ToInt32(tempArray, 0);
var octLong = long.Parse(Convert.ToString(decLong, 8));
resultList.Add(octLong);
break;
default:
throw new ArgumentOutOfRangeException("Unit");
}
}
}
return resultList;
}
public override IEnumerable<string> ToHexadecimal(byte[] ResultArray, EnumModbusIntegralUnit Unit)
{
var length = (int)Unit;
if (ResultArray == null)
{
throw new ArgumentNullException("ResultArray");
}
if (ResultArray.Length <= 0 || ResultArray.Length < length)
{
throw new FormatException("ResultArray");
}
this.ResultArray = ResultArray;
List<string> resultList = new List<string>();
for (int i = 0; i < ResultArray.Length; i = i + length)
{
using (MemoryStream memory = new MemoryStream())
{
memory.Write(ResultArray, i, length);
var tempArray = memory.ToArray();
var result = BitConverter.ToString(tempArray).Replace("-", "");
resultList.Add(result);
}
}
return resultList;
}
public override IEnumerable<string> ToBinary(byte[] ResultArray, EnumModbusIntegralUnit Unit)
{
var length = (int)Unit;
if (ResultArray == null)
{
throw new ArgumentNullException("ResultArray");
}
if (ResultArray.Length <= 0 || ResultArray.Length < length)
{
throw new FormatException("ResultArray");
}
this.ResultArray = ResultArray;
List<string> resultList = new List<string>();
for (int i = 0; i < ResultArray.Length; i = i + length)
{
using (MemoryStream memory = new MemoryStream())
{
memory.Write(ResultArray, i, length);
var tempArray = memory.ToArray();
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tempArray);
}
var bin = "";
switch (Unit)
{
case EnumModbusIntegralUnit.Byte:
bin = Convert.ToString(tempArray[0], 2).PadLeft(8, '0');
break;
case EnumModbusIntegralUnit.Word:
var decShort = BitConverter.ToInt16(tempArray, 0);
bin = Convert.ToString(decShort, 2).PadLeft(16, '0');
break;
case EnumModbusIntegralUnit.DWord:
var decInt = BitConverter.ToInt32(tempArray, 0);
bin = Convert.ToString(decInt, 2).PadLeft(32, '0');
break;
case EnumModbusIntegralUnit.QWord:
var decLong = BitConverter.ToInt64(tempArray, 0);
bin = Convert.ToString(decLong, 2).PadLeft(64, '0');
break;
default:
throw new ArgumentOutOfRangeException("Unit");
}
resultList.Add(bin);
}
}
return resultList;
}
public override IEnumerable<float> ToFloat(byte[] ResultArray)
{
var length = 4;
if (ResultArray == null)
{
throw new ArgumentNullException("ResultArray");
}
if (ResultArray.Length <= 0 || ResultArray.Length < length)
{
throw new FormatException("ResultArray");
}
this.ResultArray = ResultArray;
int count = ResultArray.Length / length;
List<float> resultList = new List<float>();
for (int i = 0; i < count * length; i = i + length)
{
using (MemoryStream memory = new MemoryStream())
{
memory.Write(ResultArray, i + 1, 1);
memory.Write(ResultArray, i, 1);
memory.Write(ResultArray, i + 3, 1);
memory.Write(ResultArray, i + 2, 1);
var resultArray = memory.ToArray();
float result = BitConverter.ToSingle(resultArray, 0);
resultList.Add(result);
}
}
return resultList;
}
public override IEnumerable<double> ToDouble(byte[] ResultArray)
{
var length = 8;
if (ResultArray == null)
{
throw new ArgumentNullException("ResultArray");
}
if (ResultArray.Length <= 0 || ResultArray.Length < length)
{
throw new FormatException("ResultArray");
}
this.ResultArray = ResultArray;
int count = ResultArray.Length / length;
List<double> resultList = new List<double>();
for (int i = 0; i < count * length; i = i + length)
{
using (MemoryStream memory = new MemoryStream())
{
memory.Write(ResultArray, i + 1, 1);
memory.Write(ResultArray, i, 1);
memory.Write(ResultArray, i + 3, 1);
memory.Write(ResultArray, i + 2, 1);
memory.Write(ResultArray, i + 5, 1);
memory.Write(ResultArray, i + 4, 1);
memory.Write(ResultArray, i + 7, 1);
memory.Write(ResultArray, i + 6, 1);
var resultArray = memory.ToArray();
double result = BitConverter.ToDouble(resultArray, 0);
resultList.Add(result);
}
}
return resultList;
}
}
此類別,會用到的列舉
{
Byte = 1, Word = 2, DWord = 4, QWord = 8
}
前面幾篇文章都會看的到的 ModbusUtility 類別,收納了一些雜像功能,不知如何分類的都被丟到這裡來,比如計算CRC / LRC
{
public readonly static string ASCII_START_SYMBOL = ":";
public readonly static string ASCII_END_SYMBOL = "\r\n";
private CRCManager m_CrcManager = new CRCManager();
private AbsCRCProvider m_CrcProvider;
private string[] s_Symbol = new string[] { " ", ",", "-" };
public string BytesToBinaryString(byte[] HexArray)
{
StringBuilder sb = new StringBuilder();
foreach (var b in HexArray)
{
sb.Append(Convert.ToString(b, 2).PadLeft(8, '0'));
}
return sb.ToString();
}
public byte[] HexStringToBytes(string Hex)
{
string filter = s_Symbol.Aggregate(Hex, (current, symbol) => current.Replace(symbol, ""));
return Enumerable.Range(0, filter.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(filter.Substring(x, 2), 16))
.ToArray();
}
public string BytesToHexString(byte[] HexArray)
{
StringBuilder sb = new StringBuilder();
foreach (var b in HexArray)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
public string CalculateLRC(byte[] DataArray)
{
if (DataArray == null)
throw new ArgumentNullException("data");
byte lrc = 0;
foreach (byte b in DataArray)
{
lrc += b;
}
lrc = (byte)((lrc ^ 0xFF) + 1);
var hex = lrc.ToString("X2");
return hex;
}
public byte[] CalculateCRC(byte[] DataArray)
{
if (m_CrcProvider == null)
{
m_CrcProvider = m_CrcManager.CreateCRCProvider(EnumCRCProvider.CRC16Modbus);
}
var crcArray = m_CrcProvider.GetCRC(DataArray).CrcArray;
Array.Reverse(crcArray);
return crcArray;
}
}
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET