C#串行端口问题-太简单而无法失败,但是 [英] C# serial port problem - too simple to fail, but

查看:89
本文介绍了C#串行端口问题-太简单而无法失败,但是的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,这应该很简单.我正在尝试从串行设备读取字符.这样的话,如果我发送一个空格字符,它将回显一串数字和EOL.就是这样.

Ok, this should be dirt simple. I'm trying to read charactes from a serial device. It's such that if I send a space character, it echos back a string of numbers and EOL. That's it.

我正在使用Unity 3.3(支持.Net 2.0),串行端口"是一个多产的串行USB适配器.顺便说一句:使用超级终端,一切都可以完美运行,所以我知道它既不是驱动程序也不是硬件.

I'm using Unity 3.3 (.Net 2.0 support), and the 'serial port' is a Prolific serial-to-USB adaptor. BTW: Using Hyperterminal, it all works perfectly, so I know it's not driver nor hardware.

我可以打开端口了.看来我可以使用port.Write(");发送我的空间了但是,如果我什至尝试调用ReadChar,ReadByte或ReadLine(如轮询),它会冻结直到我拔下USB为止,并且我的控制台输出什么也没显示(捕获了异常).

I can open the port ok. It seems I can send my space with port.Write(" "); But if I even TRY to call ReadChar, ReadByte, or ReadLine (like polling), it freezes up until I unplug the USB, and my console output shows nothing (exceptions were caught).

因此,我设置了一个DataReceviedHandler,但从未调用过它.

So instead I set up a DataReceviedHandler, but it's never called.

我读过一些帖子,人们使用Arduino等完成了这种事情(这不是Arduino,但嘿),仅使用ReadLine.他们的代码对我不起作用(到目前为止,这些作者都没有答案).

I've read some posts where people have done just this type of thing with Arduinos etc. (this is not an Arduino but hey), using nothing more than ReadLine. Their code does not work for me (and no answers thus far from those authors).

那么,有什么建议吗?我是否需要使用其他线程?如果您知道任何Unity(Mono)编码,那么沿这些方面的任何技巧都将非常有用.

So, any tips? Do I need to use a different thread? If you know any Unity (Mono) coding, any tips along those lines greatly appreciated.

此代码通过 http://plikker.com/?p=163 http://msdn.microsoft.com/zh-cn/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(" ");
 }
}

推荐答案

请确保使用正确的设置打开正确的端口.这是如何配置它的示例:

Make sure that you are opening the right port, using correct settings. Here is an example of how you could configure it:

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

I recommend the open source RealTerm terminal, it has a rich set of features and can help you debug. Try writing a byte manually using such software, and if it works, then the problem is in your program. Otherwise it might be a driver problem (but more likely it isn't).

呼叫 SerialPort.ReadLine 实际上应该阻塞线程,直到

Calling SerialPort.ReadLine is actually supposed to block the thread until SerialPort.NewLine is received. Also ReadChar and ReadByte will hang until at least one byte is received. You need to make sure that you are actually receiving characters from the other side, and you won't be receiving them if your app is stuck and cannot send the space.

由于我从未使用过Unity,因此不确定如何调用Update,但是我假设它会定期在前台线程上触发(否则您的应用程序将不会冻结).

Since I never used Unity, I am not sure how Update is called, but I am presuming it's fired on a foreground thread in regular intervals (otherwise your app wouldn't freeze).

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

The example that you linked (Arduino and Unity example) shows that Arduino is sending the data continuously, and that is why their Update method is constantly receiving data (no space character needs to be sent towards the device). If they unplug the device, their app will hang just as well.

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

Well, maybe not, because in .NET 1.1, default value for ReadTimeout was not infinite, like it is in .NET 2.0.

所以,您可以做的是:

a..将ReadTimeout属性设置为合理的值. .NET 2.0中的默认值是InfiniteTimeout,它不符合您的需求.缺点:您的更新方法仍会在每次调用时暂停一段时间,但不会无限期地持续.

a. Set the ReadTimeout property to a reasonable value. Default in .NET 2.0 is InfiniteTimeout, which doesn't suit your needs. Cons: your update method will still hang for a while on each call, but not infinitely.

b..有人说事件未在MONO SerialPort中实现,因此我猜想仅使用DataReceived是不可行的.

b. Someone said that events are not implemented in MONO SerialPort, so I guess using DataReceived only is not an option.

c.还将发送逻辑移至Update方法,这样您才可以读取数据,直到可以读取为止:

c. Move your sending logic to the Update method also, so that you don't read data at all, until it's time to read it:

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设置为合理的值.您也将希望在某些时候停止发送,但我留给您.

Note that, if your device is not sending data, it will also block at stream.ReadLine(), so make sure your ReadTimeout is set to a reasonable value. You will also want to stop sending at some point, but I leave that to you.

d.像现在一样在OnGui中发送空格,但是在读取缓冲区之前,请始终检查缓冲区中是否有数据:

d. Send the space in OnGui like you are doing now, but always check if there is data in your buffer before reading it:

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;
 }

免责声明:这是我的脑筋,未经测试,因此可能会出现一些语法错误,我相信您会处理的.

Disclaimer: this is directly out of my head, untested, so there may be some syntax errors which I am sure you will handle.

这篇关于C#串行端口问题-太简单而无法失败,但是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆