【发布时间】:2014-11-03 12:49:12
【问题描述】:
我很尴尬不得不问这样一个问题,但我很难弄清楚如何使用 .NET SerialPort 类通过串行端口可靠地读取数据。
我的第一种方法:
static void Main(string[] args)
{
_port = new SerialPort
{
PortName = portName,
BaudRate = 57600,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One,
RtsEnable = true,
DtrEnable = false,
WriteBufferSize = 2048,
ReadBufferSize = 2048,
ReceivedBytesThreshold = 1,
ReadTimeout = 5000,
};
_port.DataReceived += _port_DataReceived;
_port.Open();
// whatever
}
private void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var buf = new byte[_port.BytesToRead];
var bytesRead = _port.Read(buf, 0, buf.Length);
_port.DiscardInBuffer();
for (int i = 0; i < bytesRead; ++i)
{
// read each byte, look for start/end values,
// signal complete packet event if/when end is found
}
}
所以这有一个明显的问题;我正在调用DiscardInBuffer,因此在事件触发后传入的任何数据都将被丢弃,即我正在删除数据。
现在,the documentation for SerialPort.Read() 甚至没有说明它是否推进了流的当前位置(真的吗?),但我发现其他来源声称它确实如此(这是有道理的)。但是,如果我不调用DiscardInBuffer,我最终会收到RXOver 错误,也就是说,我处理每条消息的时间太长并且缓冲区溢出。
所以...我真的不喜欢这个界面。如果我必须在单独的线程上处理每个缓冲区,我会这样做,但这会带来一系列问题,我希望我错过了一些东西,因为我对这个接口没有太多经验。
【问题讨论】:
-
听起来您需要将阅读与处理分离。如果你删除所有的处理,你会得到一个干净的阅读吗? TPL DataFlow 浮现在脑海中。
-
这个问题非常有问题。 DisardInBuffer() 实际上丢弃任何东西的几率非常低。您刚刚使用 Read() 调用清空了接收缓冲区。首先打开握手,这是防止超支的主要防御措施。如果这不起作用(DtrEnable = false 是 非常 奇数)然后降低波特率。
-
@HansPassant:嗯,我知道数据正在被删除,但你可能是对的。我盲目地遵循设备制造商的指示。我会调查的。
-
文档没有说明
Read()是否推进位置,因为串行端口不可搜索——它甚至没有有 位置。 (缓冲区也是 FIFO,不提供随机访问) -
@BenVoigt:当然,但底层流肯定是。当然,它从流中缓冲,因此并不简单。我只是不明白没有指定我是否真的从流中删除字节。你真的需要知道这一点。
标签: c# io serial-port