C#SerialPort通信协议

时间:2013-06-29 09:50:57

标签: c# arduino port

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

问题:

如果Arduino每500ms发送一个值,但我的C#程序每1s读取一个值,那么C#不会留在Arduino后面吗?如果这是真的,从Arduino发送的数据是否存储在缓冲区中,还是被丢弃?

[编辑]

Bellow是我用来从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)
    {
    ......

    }

}

2 个答案:

答案 0 :(得分: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 :(得分:1)

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

在几乎所有情况下,4096字节的缓冲区通常都足够了。在最高标准波特率(115200波特)下,它首先对应于超过300毫秒的存储(FIFO),因此只要您的程序每秒至少为串行端口服务三次,就不会丢失任何数据。在您的特定情况下,因为您每1秒读取一次串行,如果时序和缓冲数据不匹配,您可能会丢失数据。

但是在特殊情况下,能够增加串行输入缓冲区的大小可能很有用。 Windows提供了请求增加缓冲区大小的方法,但不保证将授予请求。

我个人更喜欢从Arduino获得连续的数据流,并在我的c#app中决定如何处理这些数据,但至少我确信由于所涉及的硬件限制,我不会丢失信息。

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

相关问题