簡體   English   中英

顯然,這不是使用SerialPort讀取的正確方法

[英]Obviously this is not the correct way to read with SerialPort

假設我想擁有一個從SerialPort讀取數據並返回byte []的函數。

public byte[] RequestData(byte[] data)
{
    //See code below
}

像這樣簡單的事情實際上不能很好地工作/執行,也不是很可靠:

byte[] response = new byte[port.ReadBufferSize];

port.Open();    
port.Write(data, 0, data.Length);

Thread.Sleep(300); //Without this it doesn't even work at all

Console.WriteLine("Bytes to read: {0}", port.BytesToRead);

int count = port.Read(response, 0, port.ReadBufferSize);

Console.WriteLine("Read {0} bytes", count);

port.Close();
port.Dispose();       

return response.GetSubByteArray(0, count);

我也嘗試用以下方式替換Thread.Sleep:

while (port.BytesToRead < 14)
{
    //Maybe Thread.Sleep(10) here?
}

但這導致了問題。 (PS:我知道我至少需要14個字節)

當然,更好的方法(我認為)是:

port.ReceivedBytesThreshold = 14;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();

port.Write(data, 0, data.Length);

然后當然有一個處理程序:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var port = (SerialPort)sender;

    while (port.BytesToRead > 0)
    {
        //Read the data here
    }
}

但是,由於我想定義的函數的結果,我不能返回數據嗎? 使用此代碼的客戶端代碼將必須預訂此代碼引發的事件,但是隨后它將如何知道響應實際上是對剛剛發出的請求的響應。

(可能會發送多條消息,我可以想象一條消息在另一側處理所需的時間比另一條或其他消息要長)。

任何建議都將受到歡迎

UPDATE

以下代碼效果更好,但是如果刪除Thread.Sleep()語句,它將再次停止正常工作。 例如,串行端口監視工具清楚地指示在串行線上已寫入17個字節。 第一次BytesToRead = 10,下一次BytesToRead = 4,但是BytesToRead仍然為0,那么最后3個字節去了哪里?

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    Thread.Sleep(100);
    while (port.BytesToRead > 0)
    {
        Console.WriteLine("Bytes to read: {0}", port.BytesToRead);
        var count = port.BytesToRead;

        byte[] buffer = new byte[count];

        var read = port.Read(buffer, 0, count);

        if (count != read)
            Console.WriteLine("Count <> Read : {0} {1}", count, read);

        var collectAction = new Action(() =>
        {
            var response = dataCollector.Collect(buffer);

            if (response != null)
            {
                this.OnDataReceived(response);
            }
        });

        collectAction.BeginInvoke(null, null);
        Thread.Sleep(100);
    }    
}

這是我的操作方法:

我為該類提供了一個包裝器,該包裝器在構造函數中接受連接的重要數據,並在該構造函數中進行基本設置。 該類的使用者調用Connect方法,該方法會激發另一個線程來執行連接(非阻塞)。

連接完成后,將觸發StateEvent指示連接已完成。 這時設置了一個發送隊列,觸發了該隊列的工作線程,並且還設置了一個讀取線程。 讀取線程從SerialPort讀取128個字符的數據,將其轉換為字符串,然后觸發事件以傳遞接收到的數據。 這被包裝在一個while線程中,只要保持連接,該線程就會循環。 當消費者想要發送東西時,Send方法只是使要發送的數據入隊。

就知道響應是對已發送內容的響應而言,實際上並不是連接類的工作。 通過將連接抽象為一個易於處理的類,該類的使用者可以清晰地維護邏輯以確定響應是否是期望的。

串行端口不是很有趣。 我唯一的想法是,假設您的設備已啟用並啟用了設備,則它的FIFO已超載。

問題解決了:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var count = port.BytesToRead;
    byte[] buffer = new byte[count];
    var read = port.Read(buffer, 0, count);

    var response = dataCollector.Collect(buffer);

    if (response != null)
    {
        this.OnDataReceived(response);
    }            
}

似乎問題實際上不是此代碼,而是dataCollector.Collect()方法中的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM