2013-06-29 250 views
3

我写了一个小型的C#应用​​程序,它从COM端口读取由Arduino板发送的一系列数字。C#SerialPort通信协议

问:

如果Arduino的发送单个值每500ms,但我的C#程序读取单个值每1秒不会在C#被甩在Arduino的背后?如果这是真的,从Arduino发送的数据是否存储在缓冲区中,还是只是被丢弃?

[编辑]

娄是我使用从COM


阅读代码
System.Windows.Forms.Timer tCOM; 
... 

tCOM.Interval = 1000; 
tCOM.Tick += new System.EventHandler(this.timer1_Tick); 
... 

SerialPort port = new SerialPort(); 
port.PortName = defaultPortName; 
port.BaudRate = 9600; 
port.Open(); 
..... 

private void timer1_Tick(object sender, EventArgs e) 
{ 
    log("Time to read from COM"); 

    //read a string from serial port 
    string l; 
    if ((l = port.ReadLine()) != null) 
    { 
    ...... 

    } 

} 
+0

亚历克斯,你如何从串行读取。发布您的代码。 – FeliceM

+0

@FeliceM更新了我的代码 – Alex

回答

4

串口通信通常需要流量控制。发射机知道接收机已准备好接收数据的一种方式。这经常被忽视,特别是在Arduino项目中。这往往会奏效,串口速度非常慢,而现代机器与首次使用串口的机器相比速度非常快。

但很明显,在你的情况下会发生一些事情!过了一会儿。当PC中的接收缓冲区满容量时,您的Arduino将导致缓冲区溢出情况。这会导致无法挽回的数据丢失。监听这种情况的通知是经常跳过的事情,您必须为SerialPort.ErrorReceived事件注册一个事件处理程序。在这种情况下,您会期待SerialError.Overrun通知。有没有干净的方式来恢复这种情况,需要一个完整的协议重置。

在串口上实现流量控制有两种基本方法可以避免这种错误。最常见的是使用硬件握手,使用RTS(请求发送)和CTS(清除发送)信号。由Handshake.RequestToSend提供。当接收缓冲区太满时,PC将自动关闭RTS信号。您的Arduino必须注意CTS信号,并在关闭时不发送任何内容。

第二种方式是软件握手,接收方发送一个特殊字节来指示它是否准备好接收数据。由Handshake.XonXoff提供,它使用标准控制字符Xon(Ctrl + Q)和Xoff(Ctrl + S)。只有当通信协议不在其数据中使用这些控制代码时才适用。换句话说,当你传输文本而不是二进制数据。

第三种方式是一种完全不同的方法,非常常见,您可以让设备只在PC要求时发送任何东西。主从协议。在接收缓冲区中有足够的空间用于响应,很容易保证。您可以在协议中指定特定的命令,这是PC发送的用于查询特定数据项的命令。

1

当您打开一个串行端口进行输入时,会自动创建一个缓冲区(队列)来保存传入数据,直到您的程序读取它为止。该缓冲区的大小通常为4096字节(尽管这可能因Windows的版本,串口驱动程序等而异)。

几乎在所有情况下,一个4096字节的缓冲区通常就足够了。在最高标准波特率(115200波特)下,它相当于先进先出超过300毫秒的存储容量(FIFO),因此只要您的程序每秒至少处理三次串行端口,就不会丢失任何数据。在您的具体情况中,由于您每隔1秒读取一次串行数据,如果时序和缓冲数据不匹配,则可能会丢失数据。

但是,在特殊情况下,增加串行输入缓冲区的大小可能很有用。 Windows提供了请求增加缓冲区大小的方法,但不能保证请求将被授予。我个人更喜欢从Arduino连续传输数据流,并在我的C#应用​​程序中决定如何处理这些数据,但至少我确信由于涉及的硬件限制我不会丢失信息。

更新: 经常玩Arduino,我也同意Hans在他的回答中给出的第三个选项。基本上你的应用程序应该向Arduino发送一个命令来打印出你需要的数据(Serial.Print或Serial.Println)并准备好读取它。