C#串口问题 – 太简单失败了,但是

好吧,这应该很简单。 我正在尝试从串行设备读取字符。 这样,如果我发送一个空格字符,它会回显一串数字和EOL。 而已。

我正在使用Unity 3.3(.Net 2.0支持),而’串行端口’是一个Prolific串口转USB适配器。 顺便说一句:使用Hyperterminal,一切都很完美,所以我知道它不是驱动程序,也不是硬件。

我可以打开端口了。 看来我可以用port.Write(“”)发送我的空间; 但是,如果我甚至尝试调用ReadChar,ReadByte或ReadLine(如轮询),它会冻结,直到我拔掉USB,我的控制台输出什么也没显示(exception被捕获)。

所以我设置了一个DataReceviedHandler,但它永远不会被调用。

我读过一些人们用Arduinos等做过这类事情的post(这不是Arduino而是嘿),只使用ReadLine。 他们的代码对我不起作用(到目前为止,这些作者都没有答案)。

那么,有什么提示吗? 我需要使用不同的线程吗? 如果您知道任何Unity(Mono)编码,那么这些行的任何提示都会受到高度赞赏。

此代码来自http://plikker.com/?p=163和http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx#Y537的mashup

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(" "); } } 

使用正确的设置确保打开正确的端口。 以下是如何配置它的示例:

 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终端,它具有丰富的function,可以帮助您调试。 尝试使用此类软件手动编写一个字节,如果有效,则问题出在您的程序中。 否则可能是驱动程序问题(但更可能不是)。

[编辑]

调用SerialPort.ReadLine实际上应该阻塞线程,直到收到SerialPort.NewLineReadCharReadByte也将挂起,直到收到至少一个字节。 你需要确保你实际上是从另一方接收角色,如果你的应用程序卡住而无法发送空间,你就不会收到它们。

由于我从未使用过Unity,因此我不确定如何调用Update ,但我认为它是以固定间隔在前台线程上触发的(否则你的应用程序不会冻结)。

您链接的示例( Arduino和Unity示例 )显示Arduino正在连续发送数据,这就是他们的Update方法不断接收数据的原因(不需要向设备发送空格字符)。 如果他们拔下设备,他们的应用程序也会挂起。

好吧,也许不是,因为在.NET 1.1中, ReadTimeout默认值不是无限的,就像在.NET 2.0中一样。

那么,你能做的是:

一个。ReadTimeout属性设置为合理的值。 .NET 2.0中的默认值是InfiniteTimeout,它不适合您的需要。 缺点:您的更新方法在每次调用时仍会挂起一段时间,但不会无限期。

有人说事件没有在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; } 

免责声明:这是我的头脑,未经测试,所以可能会有一些语法错误,我相信你会处理。

事件未在Mono SerialPort类中实现,因此您不会收到任何通知,您必须显式执行(阻止)读取。 其他可能的问题 – 我不确定Unity Behaviors如何工作,你确定在同一个线程上调用访问SerialPort所有方法吗? 并且您没有处置端口对象,这也会导致问题。

也许你的问题是串口的配置。 重要的是不仅要检查BaudRate还是StopBits。 你也应该配置DTR,RTS,握手,一切。 这很重要,因为可能另一个程序设置了一些丑陋的值,并且必须在每次启动时显式设置配置,否则旧连接的某些设置可能会让您遇到麻烦。

也许可以看一下这些工具之一:

  • com0com
  • 串口监视器

它们可以帮助您存根串行接口或深入了解连接。 也许可以尝试使用HyperTerminal或一些经certificate可行的类似工具与您的串行设备通信。

与Mono有类似的问题,升级到2.6.7有帮助。

不要混合数据事件和阻止读取。 如果数据到达,您期望发生什么? read方法和事件都应该获得相同的接收数据?

你还应该阅读:

  • CTS: http : //en.wikipedia.org/wiki/RS-232_RTS/CTS#RTS.2FCTS_handshaking
  • DTR: http : //en.wikipedia.org/wiki/Data_Terminal_Ready

描述所有状态的小型串口教程: http : //www.wcscnet.com/Tutorials/SerialComm/Page1.htm