好的,这应该很简单。我正在尝试从串行设备读取字符。这样,如果我发送一个空格字符,它会回显一串数字和EOL。就是这样。
我使用Unity 3.3(.Net 2.0支持),'串口'是Prolific串口转USB适配器。顺便说一句:使用Hyperterminal,一切都很完美,所以我知道它不是驱动程序,也不是硬件。
我可以打开端口了。好像我可以用port.Write(“”)发送我的空间;但是,如果我甚至尝试调用ReadChar,ReadByte或ReadLine(如轮询),它会冻结,直到我拔掉USB,我的控制台输出什么也没显示(异常被捕获)。
所以我设置了一个DataReceviedHandler,但它永远不会被调用。
我读过一些人们用Arduinos等做过这类事情的帖子(这不是Arduino而是嘿),只使用ReadLine。他们的代码对我不起作用(到目前为止,这些作者都没有答案)。
那么,有什么提示吗?我需要使用不同的线程吗?如果您知道任何Unity(Mono)编码,那么这些行的任何提示都会受到高度赞赏。
此代码是来自http://plikker.com/?p=163和http://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(" ");
}
}
答案 0 :(得分:5)
事件未在Mono SerialPort
类中实现,因此您不会收到任何通知,您必须显式执行(阻止)读取。其他可能的问题 - 我不确定Unity Behaviors如何工作,你确定在同一个线程上调用访问SerialPort
的所有方法吗?并且您没有处置端口对象,这也会导致问题。
答案 1 :(得分: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
为止。此外,ReadChar
和ReadByte
将一直挂起,直到收到至少一个字节。你需要确保你实际上是从另一方接收角色,如果你的应用被卡住而无法发送空间,你就不会收到它们。
由于我从未使用过Unity,因此我不确定如何调用Update
,但我认为它是以固定间隔在前台线程上触发的(否则你的应用程序不会冻结)。
您链接的示例(Arduino and Unity example)表明Arduino正在连续发送数据,这就是他们的Update
方法不断接收数据的原因(不需要向设备发送空格字符) )。如果他们拔下设备,他们的应用程序也会挂起。
嗯,也许不是,因为在.NET 1.1中,ReadTimeout
的默认值不是无限的,就像它在.NET 2.0中一样。
所以,你能做的是:
a。将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;
}
免责声明:这是我的头脑,未经测试,因此可能存在一些语法错误,我相信您会处理。
答案 2 :(得分:0)
也许你的问题是串口的配置。重要的是不仅要检查BaudRate还是StopBits。你也应该配置DTR,RTS,握手,一切。这很重要,因为可能另一个程序设置了一些丑陋的值,并且必须在每次启动时显式设置配置,否则旧连接的某些设置可能会让您遇到麻烦。
也可以看一下这些工具之一:
它们可以帮助您存根串行接口或深入了解连接。也可以尝试使用HyperTerminal或一些经证明有效的类似工具与您的串行设备通信。
答案 3 :(得分:0)
与Mono有类似的问题,升级到2.6.7有帮助。
答案 4 :(得分:0)
不要混合数据事件和阻止读取。如果数据到达,您期望发生什么? read方法和事件都应该获得相同的接收数据?
您还应该阅读:
描述所有状态的小型串口教程:http://www.wcscnet.com/Tutorials/SerialComm/Page1.htm