2011-04-20 67 views
3

好的,這應該很簡單。我正在嘗試從串口設備讀取字符。這就是說,如果我發送一個空格字符,它會回顯一串數字和EOL。而已。C#串口問題 - 太簡單了,不能失敗,但是

我使用Unity 3.3(.NET 2.0支持),和「串行端口」是一個多產的串行到USB適配器。順便說一下:使用超級終端,這一切都完美,所以我知道這不是驅動程序和硬件。

我可以打開端口確定。看來我可以發送我的空間與port.Write(「」);但是,如果我甚至試圖調用ReadChar,ReadByte或ReadLine(如輪詢),它會凍結,直到我拔掉USB,並且我的控制檯輸出什麼也沒有顯示(異常被捕獲)。

所以不是我設置了一個DataReceviedHandler,但它從來沒有所謂。

我讀過一些帖子裏的人已經做到了這種類型的與Arduinos等東西(這不是一個Arduino但嘿),僅僅使用的ReadLine以上。他們的代碼對我不起作用(迄今爲止還沒有答案)。

所以,任何提示?我需要使用不同的線程嗎?如果您知道任何Unity(單聲道)編碼,那麼非常感謝這些提示。

此代碼混搭從http://plikker.com/?p=163http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx#Y537

using UnityEngine; 
using System.Collections; 
using System.IO.Ports; 
using System; 

public class SerialTest : MonoBehaviour { 

SerialPort stream; 

void Start() { 
    try { 
    stream = new SerialPort("COM3", 9600); 
    stream.Parity = Parity.None; 
    stream.StopBits = StopBits.One; 
    stream.DataBits = 8; 
    stream.Handshake = Handshake.None; 
    stream.DataReceived += new SerialDataReceivedEventHandler(DataReceviedHandler); 


    stream.Open(); 
    Debug.Log("opened ok"); // it DOES open ok! 
    } catch (Exception e){ 
    Debug.Log("Error opening port "+e.ToString()); // I never see this message 
    } 
} 

void Update() { // called about 60 times/second 
    try { 
    // Read serialinput from COM3 
    // if this next line is here, it will hang, I don't even see the startup message 
    Debug.Log(stream.ReadLine()); 
    // Note: I've also tried ReadByte and ReadChar and the same problem, it hangs 
    } catch (Exception e){ 
    Debug.Log("Error reading input "+e.ToString()); 
    } 
} 

private static void DataReceviedHandler(
         object sender, 
         SerialDataReceivedEventArgs e) 
{ 
    SerialPort sp = (SerialPort)sender; // It never gets here! 
    string indata = sp.ReadExisting(); 
    Debug.Log("Data Received:"); 
    Debug.Log(indata); 
} 

void OnGUI() // simple GUI 
{ 
    // Create a button that, when pressed, sends the 'ping' 
    if (GUI.Button (new Rect(10,10,100,20), "Send")) 
stream.Write(" "); 
} 
} 
+3

你應該張貼你的代碼,在特別是您打開設備的代碼。 – 2011-04-20 08:30:50

+0

已添加代碼。 – Dave 2011-04-20 19:16:33

+0

你可以嘗試另一種方式,你可以驗證你的程序實際上可以發送出這個端口的東西嗎? – IanNorton 2011-04-20 19:21:48

回答

2

確保您打開正確的端口,使用正確的設置。下面是如何可以配置它的一個例子:

serial = new SerialPort(); 

serial.ReadBufferSize = 8192; 
serial.WriteBufferSize = 128; 

serial.PortName = "COM1"; 
serial.BaudRate = 115200; 
serial.Parity = Parity.None; 
serial.StopBits = StopBits.One; 

// attach handlers 
// (appears to be broken in some Mono versions?) 
serial.DataReceived += SerialPort_DataReceived; 
serial.Disposed += SerialPort_Disposed; 

serial.Open(); 

我推薦的開源RealTerm終端,它具有豐富的功能,可以幫助您進行調試。嘗試使用這種軟件手動編寫一個字節,如果它能正常工作,那麼問題出在你的程序中。否則,它可能是一個驅動程序問題(但更可能不是)。

[編輯]

中調用SerialPort.ReadLine實際上應該直到接收到SerialPort.NewLine阻塞線程。另外ReadCharReadByte會掛起,直到收到至少一個字節。您需要確保您實際上接收來自另一方的角色,並且如果您的應用程序卡住並且無法發送該空間,您將不會收到他們。因爲我從來沒有使用Unity,我不知道如何調用Update,但我假設它定期在前臺線程上觸發(否則您的應用程序不會凍結)。

您鏈接的示例(Arduino and Unity example)表明Arduino正在連續發送數據,這就是爲什麼他們的方法不斷接收數據(不需要向設備發送空間字符)。如果他們拔掉設備,他們的應用也會掛起。

嗯,也許不是,因爲在.NET 1.1中,ReadTimeout的默認值不是無限的,就像在.NET 2.0中一樣。

所以,你可以做的是:

一個。ReadTimeout屬性設置爲合理的值。 .NET 2.0中的默認值是InfiniteTimeout,它不適合您的需求。缺點:您的更新方法在每次通話中仍會暫停一段時間,但不會無限次。

b。有人說MONO SerialPort沒有實現事件,所以我猜想只使用DataReceived不是一種選擇。

c。將您發送邏輯Update方法,也讓你不讀的任何數據,直到它的時間來閱讀:

private volatile bool _shouldCommunicate = false; 
void Update() 
{ 
    if (_shouldCommunicate) // this is a flag you set in "OnGui" 
    { 
    try { 
     stream.Write(" "); 
     Debug.Log(stream.ReadLine()); 
    } catch (Exception e){ 
     Debug.Log("Error reading input "+e.ToString()); 
    } 
    } 
} 

void OnGUI() // simple GUI 
{ 
    if (GUI.Button (new Rect(10,10,100,20), "Send")) 
     _shouldCommunicate = true; 
} 

需要注意的是,如果您的設備不發送數據時,也會阻止在stream.ReadLine(),所以請確保您的ReadTimeout設置爲合理的值。你也想在某個時候停止發送,但是我會把它留給你。

d。看完前OnGui發送的空間就像你現在正在做,但總是檢查是否有您的緩衝區中的數據:

void Update() { // called about 60 times/second 
try { 
    // call our new method 
    Debug.Log(ReadLineNonBlocking()); 
} catch (Exception e){ 
    Debug.Log("Error reading input "+e.ToString()); 
} 
} 

private StringBuilder sb = new StringBuilder(); 
string ReadLineNonBlocking() 
{ 
    int len = stream.BytesToRead; 
    if (len == 0) 
     return ""; 

    // read the buffer 
    byte[] buffer = new byte[len]; 
    stream.Read(buffer, 0, len); 
    sb.Append(ASCIIEncoding.ASCII.GetString(buffer)); 

    // got EOL? 
    if (sb.Length < 2 || 
     sb[sb.Length-2] != '\r' || 
     sb[sb.Length-1] != '\n') 
     return ""; 

    // if we are here, we got both EOL chars 
    string entireLine = sb.ToString(); 
    sb.Length = 0; 
    return entireLine; 
} 

免責聲明:這是直接從我的頭,未經檢驗的,所以可能會有一些我相信你會處理的語法錯誤。

+0

就像我說的,我確實使用超級終端,它在那裏工作,但RealTerm聽起來不錯。我會嘗試你的建議。我在SerialPort構造函數中設置了端口,波特,奇偶校驗,停止,並且在打開之前握手=無。打開工作正常。這是Read,Readline,'掛起'和DataReceived從來沒有被調用,讓我感到困擾。也許它的緩衝等 – Dave 2011-04-20 18:56:54

+0

好吧,試過這個,但它不喜歡DiscardNull或ReceivedBytesThreshold(我在.NET 2.0),評論這些。還是行不通。 – Dave 2011-04-20 20:32:31

+0

[ReceivedBytesThreshold](http://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport.receivedbytesthreshold%28v=VS.80%29.aspx#Y228)和[DiscardNull](http: //msdn.microsoft.com/en-us/library/system.io.ports.serialport.discardnull%28v=VS.80%29.aspx)實際上存在於.NET 2.0中,你的意思是.NET 1.1嗎?但他們的默認值實際上是'1'和'false',所以沒關係(我只是從一個較舊的項目中複製它而不檢查)。 – Groo 2011-04-22 11:40:22

0

也許你的問題是串行端口的配置。不僅要檢查BaudRate或StopBits,這一點很重要。你也應該配置DTR,RTS,Handshake,一切。這很重要,因爲另一個程序可能會設置一些醜陋的值,並且必須在每次啓動時明確設置配置,否則舊連接的某些設置可能會讓您陷入困境。

而且也許看一看到這些工具之一:

他們可以幫助你來,踩你的串行接口或採取更深入地瞭解連接。也可以嘗試使用HyperTerminal或經過驗證的某些類似工具與串口設備通信。

+0

我已經使用超級終端如上所述,工作正常,但這些工具聽起來很有希望,謝謝 – Dave 2011-04-20 18:51:10

+0

使用串行端口監視器,看起來像我的'平'字發送,或至少SPM看到他們。但沒有數據進來。我用超級終端做了它,除了數據進來之外它看起來很相似.Diff是HypTerm'設置當前事件掩碼'(??)並且發送的字符是(之前是?)的子節點'等待事件'和IRP_MJ_READ(然後它寫我的ping字符),然後IRP_MJ_READs發生,那裏的數據是。我如何在我的代碼中發生這種情況? – Dave 2011-04-20 20:46:03

0

與Mono有類似的問題,升級到2.6.7幫助。

+0

Unity可能在2.6版本(不知道之後的子版本如果有的話)。你從哪個版本升級? – Dave 2011-04-20 20:59:43

+0

發現團結是2.6.3 :-( – Dave 2011-04-21 20:30:00

+0

它是2.6.3或2.6.4。那麼,不會升級Unity嗎?也許你應該聯繫他們 – 2011-05-17 09:18:09

4

事件不會在Mono SerialPort類中實現,所以您不會收到任何通知,您必須顯式執行(阻止)讀取。其他可能的問題 - 我不確定Unity Behaviors是如何工作的,你確定訪問SerialPort的所有方法是在同一個線程上調用的嗎?而且你沒有處理你的端口對象,這也會導致問題。

+0

我將刪除事件處理程序。所有相同的線程,我應該使用一個不同的?或者協程(我沒有意識到讀取阻塞)在調用Read之前,我也嘗試過檢查BytesToRead,但是這似乎也是掛起的,我會再試一次,也許我有一個錯字。 – Dave 2011-04-21 20:32:26

+0

確切地說,原始C#和Mono實現SerialPort之間的差異細節在這裏描述:http://www.mono-project.com/archived/howtosystemioports/#limitations – Ben 2016-09-30 21:41:00

0

請勿混合數據事件並阻止讀取。如果數據到達,你預計會發生什麼?讀取方法和事件都應該得到相同的接收數據?

你也應該瞭解:

小串口教程描述了所有的狀態:http://www.wcscnet.com/Tutorials/SerialComm/Page1.htm

+0

謝謝。我試圖兩個看看是否會產生一個結果,將刪除事件處理程序。我的硬件預計沒有握手,但串行日誌(超級終端)似乎暗示它可能有幫助(?)感謝您的鏈接 – Dave 2011-04-21 20:29:31