1. 程式人生 > >C# 串列埠通訊的資料丟失和同步非同步問題

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 

(new weituo(Setinfo));//Invoke這個更好
               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;
        }