2012-04-12 109 views
0

嗯,我一直在C#中使用此SerialPort控件在过去的4天中苦苦挣扎,没有令人满意的结果。让我解释一下:串行端口异步读取(非阻塞)+线程

我有一个与ac#prog通信的设备(Arduino UNO板卡),它模拟一个规模(简单的请求/响应模式),设备发送一个由3个字节组成的命令序列):CHR(27)+ P + CHR(13),所以模拟器用一个模拟重量进行响应(我已经理清了设备如何捕获并解析这个重量,所以这不再是问题)。 使用DataReceive事件似乎我使用Serialport.Read()丢失数据,所以我浪费了这种方法到目前为止。 模拟器必须始终倾听所述seq。的字节和必须有一个GUI。我明白为此我必须使用一个线程为了防止GUI被锁定(可能是后台工作?)和一种在(现在)这2个线程之间共享的缓冲区,并且防止线程同时读/写到缓冲区(我是否需要一个状态机?)(我要求这方面的帮助,因为我不知道这是一个好方法,还是我的假设是错误的,或者如果这是更简单的方法来解决这个问题),所以我寻求建议和(运气很好)代码片段,或者如果您需要开发类似的应用程序,您是如何解决它的。

如果需要进一步阐明,我可以提供我迄今为止所做的代码。希望你可以对此有所了解。

在此先感谢。

UPDATE 1


这是代码我迄今为止:

ConcurrentQueue<byte> queue = new ConcurrentQueue<byte>(); 
.... 
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    bool listening = true; 
    while(listening) 
    { 
    if(serialPort.BytesToRead > 0) 
    { 
     byte b = (byte)serialPort.ReadByte(); 
     queue.Enqueue(b); 
    } 
    } 
} 

如此以来,一个命令具有字符13来结束(CR在ASCII):

public string GetCommand() 
{ 
    string ret = ""; 
    byte[] ba = new byte[1]; 
    byte b = (byte)' '; 

    while(b!=13) 
    { 
     if(queue.TryDequeue(out b)) 
     { 
      ba[0] = b; 
      ret += ASCIIEncoding.ASCII.GetString([ba]); 
     } 
    } 
    return ret; 
} 

为了测试这个GetCommand()方法,我从buton_click事件中的主UI线程调用它,但它挂起了应用程序,do我需要创建另一个线程来调用GetCommand()?

+0

我更新了我的问题。我尝试了什么hitechrider,但我再次卡住,似乎线程是一个相当复杂的主题。 – favner85 2012-04-12 19:20:25

回答

1

请参阅this answer了解如何实现发送端。

对于读取端使用专用线程,在该线程中从端口读取消息,将其排列在合适的并发数据结构(例如ConcurrentQueue)中并立即循环以等待来自串行的下一个输入港口。

从单独线程上的队列中获取输入。

可能有更有效的方法,但这个很容易实现和万无一失。

2

对于少量数据这是可以的。但是如果数据比较大,就像传递一些http信息一样,那么队列大小可能不够。所以我认为你应该使用非阻塞类型的体系结构。