C# 串列埠通訊的資料丟失和同步非同步問題
串列埠通訊最痛苦的在於無法深入瞭解串列埠內部的規則,只能呼叫c#提供的SerialPort類,但是使用的時候也出現了很多問題,有的是自身的有的是由於不瞭解造成的。
首先SerialPort類提供了很多很好的方法,對於讀寫都很有幫助,但是有的讀是同步,有的是非同步,同步就是和主程式保持一致,只有執行完了ReadByte之後才能執行程式之後的程式碼,非同步就是重新開啟一個執行緒來處理這些問題,主程式不受到干擾,繼續執行。
serialPort中有6個讀的方法:
Read();
ReadLine()
ReadByte();
ReadChar();
ReadExisting();
ReadTo();
ReadTo和ReadExisting是非同步讀取,剩下的都是同步讀取。
其次就是一般來說對於這種串列埠的讀取我們會用到多執行緒,所以要用委託來改變視窗中的一些值,所以就要用到
this.Invoke(new weituo(Setinfo));
Invoke和BeginInvoke 在http://www.cnblogs.com/mashang/archive/2009/08/01/1536730.html解釋的很清楚了,Invoke是同步,後面的是非同步。
我最開始就是使用了BeginInvoke ,所以總會出現讀取不到資料的情況,就是因為委託方法執行的太快了,所以導致了資料的丟失,顯示不出來了,如果你也碰到了這種問題,也可以在
while
(true)
{
//resultLength = _serialPort.Read(result, 0, result.Length);
//legheit = resultLength;
//string Currentword = Encoding.UTF8.GetString(result, 0, resultLength);
byte[] data = new byte[1];
data[0]=(byte)_serialPort.ReadByte();
ss = ToHexString(data);
this.BeginInvoke
Thread.Sleep(500);
}
也可以在讀取函式中加上Sleep停頓一段時間就行了,但是這只是權宜之計,還是使用同步最好了。
如果你也是發現數據出現了丟失情況,多半是這個問題,因為串列埠有緩衝區,如果不是資料被讀取出去了,一般來說資料是不會自己清空的。
接下來就是因為串列埠通訊多半是16進位制的通訊方式,所以把找到了一些16進位制轉換函式貼出來:
public static char[] hexDigits = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static string ToHexString(byte[] bytes)
{
char[] chars = new char[bytes.Length * 3];
for (int i = 0; i < bytes.Length; i++)
{
int b = bytes[i];
chars[i * 3] = hexDigits[b >> 4];
chars[i * 3 + 1] = hexDigits[b & 0xF];
chars[i * 3 + 2] = ' ';
}
return new string(chars);
}
以上是將讀取到了byte型別轉換成16進位制並以string形式輸出的函式。
還有一些大家自己看吧都很不錯:
private byte[] getdata()
{
int len = tsend.Text.Length;
int j = 0;
byte []datat = new byte[len];
for(int i=0;i<len-2;i++)
{
if((tsend.Text[i]<='9')&&(tsend.Text[i]>='0')&&(tsend.Text[i+1]>='0')&&(tsend.Text[i+1]<='9')&&(tsend.Text[i+2]<=' '))
{
datat[j] = (byte)((tsend.Text[i]-'0')*16+(tsend.Text[i+1]-'0'));
j++;
}
}
byte[] datarev = new byte[j];
for(int k=0;k<j;k++)
{
datarev[k] = datat[k];
}
return datarev;
}
private bool ishex(char x)
{
bool re = false;
if((x<='9')&&(x>='0'))
{
re = true;
}
else if((x<='F')&&(x>='A'))
{
re = true;
}
else if ((x <= 'f') && (x >= 'a'))
{
re = true;
}
return re;
}
private byte[] GetByteData(string s)
{
byte[] data = new byte[s.Length / 2];
for (int i = 0; i < s.Length / 2; i++)
{
if (s[i * 2] <= '9')
{
data[i] = (byte)((s[i * 2] - '0') * 16);
}
else if (s[i * 2] <= 'f' && s[i * 2] >= 'a')
{
data[i] = (byte)((s[i * 2] - 'a' + 10) * 16);
}
else if (s[i * 2] <= 'F' && s[i * 2] >= 'A')
{
data[i] = (byte)((s[i * 2] - 'A' + 10) * 16);
}
if (s[i * 2 + 1] <= '9')
{
data[i] = (byte)(data[i] + (byte)((s[i * 2 + 1] - '0')));
}
else if (s[i * 2 + 1] <= 'f' && s[i * 2 + 1] >= 'a')
{
data[i] = (byte)(data[i] + (byte)((s[i * 2 + 1] - 'a' + 10)));
}
else if (s[i * 2 + 1] <= 'F' && s[i * 2 + 1] >= 'A')
{
data[i] = (byte)(data[i] + (byte)((s[i * 2 + 1] - 'A' + 10)));
}
}
return data;
}
private string GetHexString(string str)
{
int len = str.Length;
string datarev = "";
int i=0;
for(i=0;i<(len)/3;i++)
{
if ((ishex(str[3 * i])) && (ishex(str[3 * i + 1])) && (str[3 * i + 2] == ' '))
{
datarev = datarev + str[3 * i] + str[3 * i + 1];
}
else if ((ishex(str[3 * i])) && (ishex(str[3 * i + 1])) && (3 * i + 2 == len))
{
datarev = datarev + str[3 * i] + str[3 * i + 1];
}
}
if(len-i*3==2)
{
if ((ishex(str[len-1])) && (ishex(str[len-2])))
{
datarev = datarev + str[len-2] + str[len-1];
}
}
return datarev;
}
private bool ishexstring(string strl)
{
string del = " ";
string str = strl.Trim(del.ToCharArray());
int len = str.Length;
bool re = false;
for (int i = 0; i < (len) / 3; i++)
{
if ((ishex(str[3 * i])) && (ishex(str[3 * i + 1])) && (str[3 * i + 2] == ' '))
{
re = true;
}
else if ((ishex(str[3 * i])) && (ishex(str[3 * i + 1])) && (3 * i + 2 == len))
{
re = true;
}
else
{
re = false;
}
}
return re;
}