轉 C# 串口編程遇到的問題以及解決方案

來源:互聯網
上載者:User
最近在做的項目中涉及到串口通訊編程,隊友在做這一模 塊的時候遇到了一個相信很多人都可能遇到的問題,那就是接受資料的衝突或者丟失。隊友讓我幫他調試的時候,足足花了近兩個小時才把問題給解決了,現覺得有 必要總結一下以給遇到類似問題的朋友一個思路吧~

      問題是這樣的,從相應的硬體裝置每隔2秒便發送一個大小為15的位元組資料,存的是16進位資料,每條資料以7E開頭以7E結尾。例如:7E 09 01 1A ... 7E。但是PC端在接受顯示的時候卻出現了問題,如前五個資料接受正常,接下來的都是以00填充,而剩下的10個資料卻出現在下條資料顯示的位置。如下所 示: 

      7E 09 01 1A 5C 00 00 00 00 00 00 00 00 00 00 /////// 03 06 1A 2C 3D 09 6C 32 12 7E 00 00 00 00 00 00/////// ........

      總之感覺錯位了,對了,先把PC端代碼貼一下吧:      

     


public partial class Form1 : Form
    {
        /// <summary>
        /// 接受資料的串口類 
        /// </summary>
        SerialPort spReceive;
        delegate void ReceivData(byte[] bytes);

        public Form1()
        {
            Form1.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
          
            spReceive =new SerialPort("COM5", 57600, Parity.None, 8, StopBits.One);             
            spReceive.Open();
            
            //設定觸發 DataReceived事件的閥值,在調試中發現這個不起作用,不解~      
            spReceive.ReceivedBytesThreshold =15;            
            spReceive.DataReceived +=new System.IO.Ports.SerialDataReceivedEventHandler(spReceive_DataReceived);            
        }

        /// <summary>
        /// 更新接受到得資料到UI 介面顯示
        /// </summary>
        /// <param name="bytes"></param>
        public void UpdateReceiveToUI(byte[] bytes)
        {
            if (txtReceive.InvokeRequired)
            {
                ReceivData dl = new ReceivData(UpdateReceiveToUI);
                object arg = bytes;
                txtReceive.Invoke(dl, arg);
            }
            else
                txtReceive.Text += "/////////" + BitConverter.ToString(bytes);
        }

        /// <summary>
        /// 接收到串口資料觸發的事 件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void spReceive_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            byte[] recevied = new byte[15];
            int size = spReceive.Read(recevied, 0, recevied.Length);

            if (size >0)

                UpdateReceiveToUI(recevied);

            

        }

    }

       在調試的過程中,當我spReceive_DataReceived函數中的byte[] recevied = new byte[15]; 後面在加上個初始化,如下:

       for( int i=0; i<recevied.Lengthl;i++)

             recevied[i]=11;

    

       這個時候介面顯示的時候,凡是以00顯示的地方都被11替換了。這肯定了這些00是由於傳送的15個位元組數組未被完全填充到我們定義的位元組數組中,即 Read(byte [] bytes,int offset,int size)函數未一次性將位元組數組填充完,而是分了兩次。但是在此過程中我使用的是SerialPort類的DataReceived事件,即沒收到一條 資料便會觸發,而這兒的現象彷彿是事件被觸發了多次。後來自己在SerialPort類的屬性裡面找了下,突然發現了有個 ReceivedBytesThreshold屬性,從這個屬性可以看出我們可以控制接受多少個位元組觸發一次DataReceived事件。於是,我便將 閥值設為15個位元組,滿以為問題解決了,可是結果卻~

       囧啊,可是這個屬性也給了我們一些提示,也找到了問題的癥結所在。那就是,DataRecevied事件觸發的閥值,即接受到多少個位元組數觸發一次偏小, 結果導致了我們一條大小為15個位元組的資料觸發了兩次DataReceived事件。要解決這個問題,我們可以沿著這個思路走下去,那就是延遲 DataRecevied事件的觸發直到我們一條資料接受完畢。

       所以在spReceive_DataReceived事件函數中,我們做如下修改:

       byte[]  receiveBuffer=new byte[15];  

       public void spReceive_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

       {

              int bytesRead = 0;  

              spReceive.ReceivedBytesThreshold = 100000;     //延遲DataRecevied事件的再次觸發

              

             while (true)

             { 

                   if (bytesRead >= 15)      //這兒的15是我一條資料的大小

                  { 

                        byte[] bytes = new byte[bytesRead]; 

                        Array.Copy(receiveBuffer, 0, bytes, 0, bytesRead);       

                        Array.Clear(receiveBuffer, 0, bytesRead); 

                        UpdateReceiveToUI(bytes);

                        bytesRead = 0; 

                        break; 

                  } 

                  try

                 {

                    receiveBuffer[bytesRead] = (byte)spReceive.ReadByte();

                    ++bytesRead;

                 }

                catch (Exception ex1)

                {

                    MessageBox.Show(ex1.Message);

                    break;

                } 

 

                bytesRead = 0;

                spReceive.ReceivedBytesThreshold = 1;            //將延遲改回正常

             } 

       } 

     

       經過上述的改動,便可以解決讀取串口資料衝突與丟失的問題了~不周之處,還望各位斧正~

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.