我用c#寫的串口通訊
窗口數據發送和接受的類 新建 PortControl
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace SPC
{
/// <summary>
/// 串口控製
/// </summary>
public class PortControl
{
/// <summary>
/// 定義一個串口類
/// </summary>
private SerialPort MyPort;
/// <summary>
/// 初始化類
/// </summary>
public PortControl()
{
MyPort = new SerialPort();
setup();
}
/// <summary>
/// 直接使用給某個串口
/// </summary>
/// <param name="port">COM1,COM2。。。。。。</param>
public PortControl(string port)
{
_portname = port;
MyPort = new SerialPort(_portname);
setup();
}
private void setup()
{
MyPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived);
}
public bool Open()
{
try
{
if (MyPort.IsOpen != true) { MyPort.Open(); };
return true ;
}
catch
{
return false;
}
}
public void Open(string port)
{
MyPort.PortName = _portname;
MyPort.Open();
}
public void Close()
{
MyPort.Close();
}
private string _portname;
/// <summary>
/// 端口名稱
/// </summary>
/// <example>COM1 COM2</example>
public string PortName
{
get { return _portname; }
set { _portname = value; }
}
public Exception LastException;
/// <summary>
/// 最後收到的信息
/// </summary>
public string LastReceived
{
get { return hex_return; }
}
public bool Received = false;//是否收到了信息。 發送完數據,如果需要車檢器返回數據,該屬性設置為false;
//當收到消息,並解析完成後。這個設置為true;
string hex_return = "";//收到數據後把十六進製存到這個字符串中。
byte[] bin_return = new byte[] { };
double _timeout = 0.8;
public double TimeOut
{
get { return _timeout; }
set { _timeout = value; }
}
/// <summary>
/// 向端口中發送命令。
/// </summary>
/// <param name="cmdstring">"0A 46 0B 31 30 30 32 35"</param>
/// <example> Send("0A 46 0B 31 30 30 32 35")</example>
/// <remarks>超時設置為5秒,一般來說,端口速度不會延時超過1秒。</remarks>
/// <summary>
/// 向端口中發送命令。
/// </summary>
/// <param name="cmdstring">"0A 46 0B 31 30 30 32 35"</param>
/// <param name="timeout">指定超時,按秒計算。端口速度一般不會遲延超過1秒。</param>
/// <example> Send("0A 46 0B 31 30 30 32 35")</example>
public string Send(string cmdstring)
{
byte[] buff = Funs.HexStringToBinary(cmdstring.Trim());//轉換命令字符串為字節數組
hex_return = "";//十六進製返回設置為空。
bin_return = new byte[] { };//重新初始化返回字節數組。
Received = false;//設置標識為沒有接受到信息
MyPort.Write(buff, 0, buff.Length);//寫入串口命令。
double tmpx = DateTime.Now.TimeOfDay.TotalSeconds;//記錄下當前總計秒數
do
{
Application.DoEvents();//釋放CPU
} while ((Received != true) && (DateTime.Now.TimeOfDay.TotalSeconds - tmpx < _timeout));
if (Received == false) { return null; }
//如果接受到了數據或者已超時就不再循環。
string rt;//初始化返回內容。
int sum = 0;//初始化命令總數。
for (int i = 3; i < bin_return.Length - 2; i++)
{
sum += bin_return[i];
}
int sum1 = bin_return[bin_return.Length - 2] + bin_return[bin_return.Length - 1]*256;
if (
sum != sum1
&&
bin_return[bin_return.Length - 3] == 3
)
{ rt = null; }
else
{
rt = Funs.BinaryToHexString(bin_return);
}
return rt;
}
/// <summary>
/// 如果接受到了數據。
/// </summary>
/// <param name="sender">發送者</param>
/// <param name="e">時間參數</param>
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//MyPort.DiscardInBuffer(); //丟棄事件發生前的數據。
int n = MyPort.BytesToRead;//讀取當前有多少數據可讀。
byte[] binary = new byte[n];//新建內容。
MyPort.Read(binary, 0, n);//讀取
Array.Resize(ref bin_return, bin_return.Length + n);//改寫數組大小
if (bin_return.Length < 1) { return; }
binary.CopyTo(bin_return, bin_return.Length - binary.Length );//複製數據。
int infleng = 0;
//16 16 02 10 01 02 00 07 00 03 1D 00
if (bin_return.Length > 7)//基本信息頭應該是7個字節。
{
if (bin_return[0] == bin_return[1] && bin_return[0]== 22 && bin_return[2] == 2)
//如果第零字節和第一字節相等,並且第二自己為0,那麼表示信息的開頭 。
{
//計算第五字節和第六字節。這兩個字節表示長度。
infleng = bin_return[5] + bin_return[6] * 256;
}
}
else if (bin_return.Length == 3)
{
Received = true;
return;
}
Received = ((10 + infleng) == bin_return.Length);//命令基本格式包含10個字節。
//加上信息長度如果等於bin接收到的長度的話。說明接受完了。接受完了就設置receive為真。
Console.WriteLine(String.Format("讀取字節數:{0}:內容:{1}----{2}", n, hex_return,e.EventType));
}
}
}
using System.IO.Ports;
using System.Windows.Forms;
namespace SPC
{
/// <summary>
/// 串口控製
/// </summary>
public class PortControl
{
/// <summary>
/// 定義一個串口類
/// </summary>
private SerialPort MyPort;
/// <summary>
/// 初始化類
/// </summary>
public PortControl()
{
MyPort = new SerialPort();
setup();
}
/// <summary>
/// 直接使用給某個串口
/// </summary>
/// <param name="port">COM1,COM2。。。。。。</param>
public PortControl(string port)
{
_portname = port;
MyPort = new SerialPort(_portname);
setup();
}
private void setup()
{
MyPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived);
}
public bool Open()
{
try
{
if (MyPort.IsOpen != true) { MyPort.Open(); };
return true ;
}
catch
{
return false;
}
}
public void Open(string port)
{
MyPort.PortName = _portname;
MyPort.Open();
}
public void Close()
{
MyPort.Close();
}
private string _portname;
/// <summary>
/// 端口名稱
/// </summary>
/// <example>COM1 COM2</example>
public string PortName
{
get { return _portname; }
set { _portname = value; }
}
public Exception LastException;
/// <summary>
/// 最後收到的信息
/// </summary>
public string LastReceived
{
get { return hex_return; }
}
public bool Received = false;//是否收到了信息。 發送完數據,如果需要車檢器返回數據,該屬性設置為false;
//當收到消息,並解析完成後。這個設置為true;
string hex_return = "";//收到數據後把十六進製存到這個字符串中。
byte[] bin_return = new byte[] { };
double _timeout = 0.8;
public double TimeOut
{
get { return _timeout; }
set { _timeout = value; }
}
/// <summary>
/// 向端口中發送命令。
/// </summary>
/// <param name="cmdstring">"0A 46 0B 31 30 30 32 35"</param>
/// <example> Send("0A 46 0B 31 30 30 32 35")</example>
/// <remarks>超時設置為5秒,一般來說,端口速度不會延時超過1秒。</remarks>
/// <summary>
/// 向端口中發送命令。
/// </summary>
/// <param name="cmdstring">"0A 46 0B 31 30 30 32 35"</param>
/// <param name="timeout">指定超時,按秒計算。端口速度一般不會遲延超過1秒。</param>
/// <example> Send("0A 46 0B 31 30 30 32 35")</example>
public string Send(string cmdstring)
{
byte[] buff = Funs.HexStringToBinary(cmdstring.Trim());//轉換命令字符串為字節數組
hex_return = "";//十六進製返回設置為空。
bin_return = new byte[] { };//重新初始化返回字節數組。
Received = false;//設置標識為沒有接受到信息
MyPort.Write(buff, 0, buff.Length);//寫入串口命令。
double tmpx = DateTime.Now.TimeOfDay.TotalSeconds;//記錄下當前總計秒數
do
{
Application.DoEvents();//釋放CPU
} while ((Received != true) && (DateTime.Now.TimeOfDay.TotalSeconds - tmpx < _timeout));
if (Received == false) { return null; }
//如果接受到了數據或者已超時就不再循環。
string rt;//初始化返回內容。
int sum = 0;//初始化命令總數。
for (int i = 3; i < bin_return.Length - 2; i++)
{
sum += bin_return[i];
}
int sum1 = bin_return[bin_return.Length - 2] + bin_return[bin_return.Length - 1]*256;
if (
sum != sum1
&&
bin_return[bin_return.Length - 3] == 3
)
{ rt = null; }
else
{
rt = Funs.BinaryToHexString(bin_return);
}
return rt;
}
/// <summary>
/// 如果接受到了數據。
/// </summary>
/// <param name="sender">發送者</param>
/// <param name="e">時間參數</param>
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//MyPort.DiscardInBuffer(); //丟棄事件發生前的數據。
int n = MyPort.BytesToRead;//讀取當前有多少數據可讀。
byte[] binary = new byte[n];//新建內容。
MyPort.Read(binary, 0, n);//讀取
Array.Resize(ref bin_return, bin_return.Length + n);//改寫數組大小
if (bin_return.Length < 1) { return; }
binary.CopyTo(bin_return, bin_return.Length - binary.Length );//複製數據。
int infleng = 0;
//16 16 02 10 01 02 00 07 00 03 1D 00
if (bin_return.Length > 7)//基本信息頭應該是7個字節。
{
if (bin_return[0] == bin_return[1] && bin_return[0]== 22 && bin_return[2] == 2)
//如果第零字節和第一字節相等,並且第二自己為0,那麼表示信息的開頭 。
{
//計算第五字節和第六字節。這兩個字節表示長度。
infleng = bin_return[5] + bin_return[6] * 256;
}
}
else if (bin_return.Length == 3)
{
Received = true;
return;
}
Received = ((10 + infleng) == bin_return.Length);//命令基本格式包含10個字節。
//加上信息長度如果等於bin接收到的長度的話。說明接受完了。接受完了就設置receive為真。
Console.WriteLine(String.Format("讀取字節數:{0}:內容:{1}----{2}", n, hex_return,e.EventType));
}
}
}
其他一些相關的函數

using System;
using Microsoft.VisualBasic;
namespace SPC
{
public class Funs
{
/// <summary>
/// 十六進製字符串到日期時間的轉換 。
/// </summary>
/// <param name="hexstring"></param>
/// <returns></returns>
public static DateTime HexString2DateTime(string hexstring)
{
int nian, yue, ri, xiaoshi, fenzhong, miao;
//08 21 14 19 05 04 //時分秒天月年
string tmp = hexstring.Trim();
xiaoshi = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
fenzhong = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
miao = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
ri = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
ri = (ri != 0) ? ri : 1;
yue = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
yue = (yue != 0) ? yue : 1;
nian = Hex2Int(Strings.Left(tmp, 3).Trim());
nian = (nian != 0) ? 2000 + nian : 2000;
return (new DateTime(nian, yue, ri, xiaoshi, fenzhong, miao));
}
/// <summary>
/// 把時間轉換為車檢器需要的字符串 。
/// </summary>
/// <param name="dt">時間</param>
/// <returns>格式為時分秒日月年</returns>
public static string DateTime2HexString(DateTime dt)
{
string info = ToHex(dt.Hour) + " ";
info += ToHex(dt.Minute) + " ";
info += ToHex(dt.Second) + " ";
info += ToHex(dt.Day) + " ";
info += ToHex(dt.Month) + " ";
info += ToHex(dt.Year-2000) + " ";
return info.Trim();
}
/// <summary>
/// 設置事件
/// </summary>
/// <param name="dt">時間</param>
/// <returns>轉換為秒分時日月年</returns>
public static string DateTime2HexString2(DateTime dt)
{
string info = ToHex(dt.Second) + " ";
info += ToHex(dt.Minute) + " ";
info += ToHex(dt.Hour) + " ";
info += ToHex(dt.Day) + " ";
info += ToHex(dt.Month) + " ";
info += ToHex(dt.Year - 2000) + " ";
return info.Trim();
}
/// <summary>
/// 轉換為符合本程序的十六進製格式
/// </summary>
/// <param name="var">1 2 3 等。</param>
/// <returns>返回十六進製字符串,如果是1-9的話,前麵帶零</returns>
/// <example>例如: 5 ="05" 12 ="0C" 無論何時,都是兩位數。 </example>
public static string ToHex(int var)
{
int cs = var;
string tmp = "";
if (cs == 0) { tmp = "00"; }
while (cs > 0)
{
int ys;
cs = Math.DivRem(cs, 256, out ys);
tmp += string.Format(" {0}", Strings.Right("00" + Convert.ToString(ys, 16), 2).ToUpper());
}
return tmp.Trim();
}
/// <summary>
/// 轉換為符合本程序的十六進製格式
/// </summary>
/// <param name="var">1 2 3 等。</param>
/// <param name="tianbu">填補</param>
/// <param name="lng">長度</param>
/// <returns>返回指定長度字符串,缺少的用 tianbu 來補齊</returns>
public static string ToHex(int var,string tianbu,int lng)
{
string tmp = ToHex(var);
tmp = Strings.Left(tmp +" "+ tianbu,lng );
return tmp;
}
/// <summary>
/// 統計和
/// </summary>
/// <param name="v">被統計的變量</param>
/// <returns></returns>
public static int Sum(byte[] v)
{
int s = 0;
foreach (int var in v)
{
s += var;
}
return s;
}
/// <summary>
/// 統計和
/// </summary>
/// <param name="v">被統計的變量</param>
/// <returns></returns>
/// <param name="istart">開始位置</param>
public static int Sum(byte[] v, int istart)
{
int s = 0;
for (int i = istart; i < v.Length; i++)
{
s += v[i];
}
return s;
}
/// <summary>
/// 統計和
/// </summary>
/// <param name="v">被統計的變量</param>
/// <returns></returns>
/// <param name="istart">開始位置</param>
/// <param name="iend">結束位置</param>
public static int Sum(byte[] v, int istart, int iend)
{
int s = 0;
for (int i = istart; i < iend; i++)
{
s += v[i];
}
return s;
}
/// <summary>
/// 轉換16進製字符串為int
/// </summary>
/// <param name="hexstring">字符串,低字節在前,高字節在後</param>
/// <returns></returns>
public static int Hex2Int(string hexstring)
{
return Hex2Int(hexstring ,false );
}
/// <summary>
/// 轉換16進製字符串為int
/// </summary>
/// <param name="hexstring">字符串</param>
/// <param name="Reverse">是否反轉為高字節在前,低字節在後</param>
/// <returns></returns>
/// <remarks> 高字節在前,低字節在後</remarks>
public static int Hex2Int(string hexstring,bool Reverse)
{
//02 00
byte[] b = HexStringToBinary(hexstring);
if (Reverse) { Array.Reverse(b); };
int r = b[0];
for (int i = 1; i < b.Length - 1; i++)
{
if (b[i] != 0)
{
r += Convert.ToInt32(Math.Pow(16, b[i]));
}
}
return r;
}
/// <summary>
/// 16進製字符串轉換為二進製數組
/// </summary>
/// <param name="hexstring">字符串每個字節之間都應該有空格,大多數的串口通訊資料上麵的16進製都是字節之間都是用空格來分割的。</param>
/// <returns>返回一個二進製字符串</returns>
public static byte[] HexStringToBinary(string hexstring)
{
string[] tmpary = hexstring.Trim().Split(' ');
byte[] buff = new byte[tmpary.Length];
for (int i = 0; i < buff.Length; i++)
{
buff[i] = Convert.ToByte(tmpary[i], 16);
}
return buff;
}
/// <summary>
/// 把二進製轉換為十六進製字符串。
/// </summary>
/// <param name="buff">要被轉換的二進製數組</param>
/// <returns>返回十六進製字符串,以空格隔開每個字節 。</returns>
public static string BinaryToHexString(byte[] buff)
{
string tmpstring = "";
foreach (byte var in buff)
{
tmpstring += " " + Strings.Right("00" + Convert.ToString(var, 16), 2);
}
return tmpstring.Trim().ToUpper();
}
}
}
using Microsoft.VisualBasic;
namespace SPC
{
public class Funs
{
/// <summary>
/// 十六進製字符串到日期時間的轉換 。
/// </summary>
/// <param name="hexstring"></param>
/// <returns></returns>
public static DateTime HexString2DateTime(string hexstring)
{
int nian, yue, ri, xiaoshi, fenzhong, miao;
//08 21 14 19 05 04 //時分秒天月年
string tmp = hexstring.Trim();
xiaoshi = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
fenzhong = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
miao = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
ri = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
ri = (ri != 0) ? ri : 1;
yue = Hex2Int(Strings.Left(tmp, 3).Trim()); tmp = tmp.Remove(0, 3);
yue = (yue != 0) ? yue : 1;
nian = Hex2Int(Strings.Left(tmp, 3).Trim());
nian = (nian != 0) ? 2000 + nian : 2000;
return (new DateTime(nian, yue, ri, xiaoshi, fenzhong, miao));
}
/// <summary>
/// 把時間轉換為車檢器需要的字符串 。
/// </summary>
/// <param name="dt">時間</param>
/// <returns>格式為時分秒日月年</returns>
public static string DateTime2HexString(DateTime dt)
{
string info = ToHex(dt.Hour) + " ";
info += ToHex(dt.Minute) + " ";
info += ToHex(dt.Second) + " ";
info += ToHex(dt.Day) + " ";
info += ToHex(dt.Month) + " ";
info += ToHex(dt.Year-2000) + " ";
return info.Trim();
}
/// <summary>
/// 設置事件
/// </summary>
/// <param name="dt">時間</param>
/// <returns>轉換為秒分時日月年</returns>
public static string DateTime2HexString2(DateTime dt)
{
string info = ToHex(dt.Second) + " ";
info += ToHex(dt.Minute) + " ";
info += ToHex(dt.Hour) + " ";
info += ToHex(dt.Day) + " ";
info += ToHex(dt.Month) + " ";
info += ToHex(dt.Year - 2000) + " ";
return info.Trim();
}
/// <summary>
/// 轉換為符合本程序的十六進製格式
/// </summary>
/// <param name="var">1 2 3 等。</param>
/// <returns>返回十六進製字符串,如果是1-9的話,前麵帶零</returns>
/// <example>例如: 5 ="05" 12 ="0C" 無論何時,都是兩位數。 </example>
public static string ToHex(int var)
{
int cs = var;
string tmp = "";
if (cs == 0) { tmp = "00"; }
while (cs > 0)
{
int ys;
cs = Math.DivRem(cs, 256, out ys);
tmp += string.Format(" {0}", Strings.Right("00" + Convert.ToString(ys, 16), 2).ToUpper());
}
return tmp.Trim();
}
/// <summary>
/// 轉換為符合本程序的十六進製格式
/// </summary>
/// <param name="var">1 2 3 等。</param>
/// <param name="tianbu">填補</param>
/// <param name="lng">長度</param>
/// <returns>返回指定長度字符串,缺少的用 tianbu 來補齊</returns>
public static string ToHex(int var,string tianbu,int lng)
{
string tmp = ToHex(var);
tmp = Strings.Left(tmp +" "+ tianbu,lng );
return tmp;
}
/// <summary>
/// 統計和
/// </summary>
/// <param name="v">被統計的變量</param>
/// <returns></returns>
public static int Sum(byte[] v)
{
int s = 0;
foreach (int var in v)
{
s += var;
}
return s;
}
/// <summary>
/// 統計和
/// </summary>
/// <param name="v">被統計的變量</param>
/// <returns></returns>
/// <param name="istart">開始位置</param>
public static int Sum(byte[] v, int istart)
{
int s = 0;
for (int i = istart; i < v.Length; i++)
{
s += v[i];
}
return s;
}
/// <summary>
/// 統計和
/// </summary>
/// <param name="v">被統計的變量</param>
/// <returns></returns>
/// <param name="istart">開始位置</param>
/// <param name="iend">結束位置</param>
public static int Sum(byte[] v, int istart, int iend)
{
int s = 0;
for (int i = istart; i < iend; i++)
{
s += v[i];
}
return s;
}
/// <summary>
/// 轉換16進製字符串為int
/// </summary>
/// <param name="hexstring">字符串,低字節在前,高字節在後</param>
/// <returns></returns>
public static int Hex2Int(string hexstring)
{
return Hex2Int(hexstring ,false );
}
/// <summary>
/// 轉換16進製字符串為int
/// </summary>
/// <param name="hexstring">字符串</param>
/// <param name="Reverse">是否反轉為高字節在前,低字節在後</param>
/// <returns></returns>
/// <remarks> 高字節在前,低字節在後</remarks>
public static int Hex2Int(string hexstring,bool Reverse)
{
//02 00
byte[] b = HexStringToBinary(hexstring);
if (Reverse) { Array.Reverse(b); };
int r = b[0];
for (int i = 1; i < b.Length - 1; i++)
{
if (b[i] != 0)
{
r += Convert.ToInt32(Math.Pow(16, b[i]));
}
}
return r;
}
/// <summary>
/// 16進製字符串轉換為二進製數組
/// </summary>
/// <param name="hexstring">字符串每個字節之間都應該有空格,大多數的串口通訊資料上麵的16進製都是字節之間都是用空格來分割的。</param>
/// <returns>返回一個二進製字符串</returns>
public static byte[] HexStringToBinary(string hexstring)
{
string[] tmpary = hexstring.Trim().Split(' ');
byte[] buff = new byte[tmpary.Length];
for (int i = 0; i < buff.Length; i++)
{
buff[i] = Convert.ToByte(tmpary[i], 16);
}
return buff;
}
/// <summary>
/// 把二進製轉換為十六進製字符串。
/// </summary>
/// <param name="buff">要被轉換的二進製數組</param>
/// <returns>返回十六進製字符串,以空格隔開每個字節 。</returns>
public static string BinaryToHexString(byte[] buff)
{
string tmpstring = "";
foreach (byte var in buff)
{
tmpstring += " " + Strings.Right("00" + Convert.ToString(var, 16), 2);
}
return tmpstring.Trim().ToUpper();
}
}
}
命令的提取和剔除。

using Microsoft.VisualBasic;
namespace SPC
{
public class CommandString
{
public const string Sync2STX = "16 16 02";
/// <summary>
/// 從返回的字符串中取得信息部分。
/// </summary>
/// <param name="returnstring">返回的字符串。</param>
/// <param name="loc">取得地址部分的字符串。</param>
/// <returns>返回字符串的信息部分</returns>
public static string GetCmdFromReturnString(string returnstring,out string loc)
{
/*
SYNC|SYNC | STX | 地址 | 長度 |信息 |ETX |2字節校驗和。
16 | 16 | 02 | 10 01 | 02 00 |07 00 |03 |1D 00
解釋:
開始的16 16 02 是信息的開頭;
10 01 即為該車檢的地址,
02 00是命令的長度低字節在前,高字節在後,代表查詢的命令值是兩個字節;
07 00 即為查詢的命令,具體解析在後;
03為停止位;
最後兩位是校驗位,為STX之後(不包括STX)到ETX(包括)所有字節的和。
*/
string tmp = returnstring.Remove(0, Sync2STX.Length).Trim();//去掉頭信息
loc = Strings.Left(tmp, 5);//取得位置
tmp = tmp.Remove(0, 5).Trim();//去掉 位置
int lng=Funs.Hex2Int(Strings.Left(tmp,5));//取得信息長度。
tmp = tmp.Remove(0, 5).Trim();//去掉信息長度
string r = Strings.Left(tmp, lng * 3).Trim();//取得信息。
//校驗和這裏不驗證了。在 PortControl 中接受的時候就驗證過了。
return r;
}
/// <summary>
/// 從返回的字符串中取得信息部分。
/// </summary>
/// <param name="returnstring">返回的字符串</param>
/// <returns>返回字符串的信息部分</returns>
public static string GetCmdFromReturnString(string returnstring)
{
string loc;
string r =GetCmdFromReturnString(returnstring , out loc);
return r ;
}
/// <summary>
/// 計算完整的命令字符串
/// </summary>
/// <param name="pm0_dizhi">The pm0_dizhi.</param>
/// <param name="pm2_mingling">The pm2_mingling.</param>
/// <returns>
/// 返回完整的十六進製字符串,包括信息頭,地址,命令,校正碼等內容。可以直接發送給車檢器。
/// </returns>
public static string GetFullCommandString(string pm0_dizhi,string pm2_mingling )
{
/*
SYNC|SYNC | STX | 地址 | 長度 |信息 |ETX |2字節校驗和。
16 | 16 | 02 | 10 01 | 02 00 |07 00 |03 |1D 00
解釋:
開始的16 16 02 是信息的開頭;
10 01 即為該車檢的地址,
02 00是命令的長度低字節在前,高字節在後,代表查詢的命令值是兩個字節;
07 00 即為查詢的命令,具體解析在後;
03為停止位;
最後兩位是校驗位,為STX之後(不包括STX)到ETX(包括)所有字節的和。
*/
//SYNC、SYNC、STX、地址、長度、信息、ETX、2字節校驗和。
string tmpstring = "16 16 02 {0} {1} {2} 03";
//0 地址,1 長度,2 信息 3 校驗和。
string pm1_changdu = Funs.ToHex(pm2_mingling.Split(' ').Length,"00",5);
tmpstring=string.Format(tmpstring,pm0_dizhi,pm1_changdu,pm2_mingling);
int pm3_jiaoyanhe = Funs.Sum(Funs.HexStringToBinary(tmpstring), 3);
tmpstring +=" "+ Funs.ToHex ( pm3_jiaoyanhe,"00",5);
return tmpstring ;
}
}
}
如何調用:

#region 獲取版本號
private const string _ver = "6C";
private const string _ver_r = "6D";
/// <summary>
/// 得到車檢器版本號
/// </summary>
/// <param name="loc">地址: 10 01</param>
/// <returns>返回車檢器版本號</returns>
public static string GetVer(string loc)
{
string tmp = DoCmd(loc, _ver, _ver_r);
if (_doresult == r_OK)
{
double dx = Funs.Hex2Int(tmp);
double d = dx/10;
return d.ToString();
}
else
{
return tmp;
}
}
#endregion
#region 公用常量
/// <summary>
/// 表示設置成功
/// </summary>
public const string r_ACK = "ACK";
/// <summary>
/// 表示查詢失敗
/// </summary>
public const string r_FAILED = "FAILED";
/// <summary>
/// 設置失敗
/// </summary>
public const string r_NACK = "NACK";
/// <summary>
/// 出現錯誤。可能是接收的數據不符合要求等。
/// </summary>
public const string r_ERROR = "ERROR";
/// <summary>
/// 超時。
/// </summary>
public const string r_TIMEOUT = "TIMEOUT";
/// <summary>
/// 未知。不知道是什麼原因,也就是說返回的內容目前程序還無法識別。
/// </summary>
public const string r_UNKNOW = "UNKNOW";
/// <summary>
/// 端口可能被占用
/// </summary>
public const string r_NULL = "NULL";
/// <summary>
/// 執行成功。
/// </summary>
public const string r_OK = "OK";
/// <summary>
/// 你給出的參數無法解析
/// </summary>
public const string r_PARAM_ERROR = "PARAM_ERROR";
#endregion
#region 執行命令
private static string _doresult;
/// <summary>
/// 命令執行結果
/// </summary>
public static string DoResult
{
set { _doresult = value; }
get { return _doresult; }
}
/// <summary>
/// 執行一條命令
/// </summary>
/// <param name="loc">地址</param>
/// <param name="cmd">命令</param>
/// <param name="r">車檢器的應答代碼。</param>
/// <returns>返回來的數據是不帶r 的。</returns>
/// <example> string tmp = DoCmd(loc, _ver, _ver_r);</example>
public static string DoCmd(string loc, string cmd)
{
return DoCmd(loc, cmd, "", true);
}
/// <summary>
/// 執行一條命令
/// </summary>
/// <param name="loc">地址</param>
/// <param name="cmd">命令</param>
/// <param name="r">車檢器的應答代碼。</param>
/// <returns>返回來的數據是不帶r 的。</returns>
/// <example> string tmp = DoCmd(loc, _ver, _ver_r);</example>
public static string DoCmd(string loc, string cmd, string r)
{
return DoCmd(loc, cmd, r, false);
}
/// <summary>
/// 執行一條命令
/// </summary>
/// <param name="loc">地址</param>
/// <param name="cmd">命令</param>
/// <param name="r">車檢器的應答代碼。</param>
/// <param name="noreturn">是否需要返回值。如果不需要則為真,如果需要則否。</param>
/// <returns>返回來的數據是不帶r 的。</returns>
/// <example> string tmp = DoCmd(loc, _ver, _ver_r);</example>
public static string DoCmd(string loc, string cmd, string r, bool noreturn)
{
string inputstring = CommandString.GetFullCommandString(loc, cmd);
Console.WriteLine("正在執行車檢器指令:" + inputstring);
PortControl pc = new PortControl("COM1");
if (pc.Open())
{
string returnstring = pc.Send(inputstring);
Console.WriteLine("車檢器答複:" +returnstring );
//如果不需要返回,直接退出函數。
if (noreturn)
{
pc.Close();
if (pc.Received)
{
string ixxx = (returnstring == "16 16 06"
? r_ACK
: (returnstring == "16 16 07"
? r_FAILED
: (returnstring == "16 16 15" ? r_NACK : r_UNKNOW)));
_doresult = ixxx;
return ixxx;
}
else
{
_doresult = r_ERROR;
return r_ERROR;
}
}
//如果接受超時。
if (pc.Received != true)
{
pc.Close();
_doresult = r_TIMEOUT;
return r_TIMEOUT;
}
string inf = CommandString.GetCmdFromReturnString(returnstring);
if (Strings.Left(inf, 2) == r)
{
pc.Close();
_doresult = r_OK;
return inf.Remove(0, r.Length).Trim();
}
else
{
pc.Close();
_doresult = r_UNKNOW;
return r_UNKNOW;
} //返回的內容不正確。
}
else
{
_doresult = r_NULL;
return r_NULL;
} //串口沒有打開。
}
#endregion
}
單元測試

[Test]
public void GetVer()
{
string tmp = DoCommand.GetVer(_地址);
Assert.AreEqual("3.3", tmp, "如果是 null ,表示車檢器的端口通訊失敗,如果是 - 表示車檢器回應的數據不正確");
}
最後更新:2017-04-02 00:06:22