C#串行端口通信协议

本文关键字:通信协议 串行端口 | 更新日期: 2023-09-27 18:20:26

我确实写了一个小型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)
    {
    ......
    }
}

C#串行端口通信协议

串行端口通信通常需要流量控制。发射机知道接收机已准备好接收数据的一种方式。这一点经常被忽视,尤其是在Arduino项目中。这往往还可以,与最初开始使用串行端口的机器相比,串行端口非常慢,而现代机器非常快。

但很明显,在你的场景中,有些事情会发生爆炸!过了一段时间。当电脑中的接收缓冲区已满时,您的Arduino将导致缓冲区溢出。这会导致无法挽回的数据丢失。侦听此情况的通知是经常被跳过的其他事情,您必须为SerialPort.ErrorReceived事件注册一个事件处理程序。在这种情况下,您可能会收到SerialError.Overrun通知。没有干净的方法可以从这种情况中恢复,需要完全重置协议。

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

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

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

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

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

然而,在特殊情况下,能够增加串行输入缓冲器的大小可能是有用的。Windows提供了请求增加缓冲区大小的方法,但不能保证请求会被批准。

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

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