寻找编写串行设备通信应用程序的最佳实践
我对串行通信相当陌生,但希望了解如何最好地实现与串行设备通信和监听的强大应用程序。
我已经成功地利用了 System.IO.SerialPort,并成功连接到我的设备、向我的设备发送数据以及从我的设备接收数据。事情的运作方式是这样的。
我的应用程序连接到 Com 端口并打开该端口...然后我将我的设备连接到 com 端口,它检测到与 PC 的连接,因此发送一些文本。它实际上只是版权信息以及固件版本。除了将其显示在我的“活动”窗口中之外,我对此没有做任何事情。
然后设备等待。
然后我可以查询信息,但发送诸如“QUERY PARAMETER1”之类的命令。然后它回复如下内容:
'QUERY PARAMETER1\r\n\r\n76767\r\n\r\n'
然后我对其进行处理。然后我可以通过发送“SET PARAMETER1 12345”来更新它,它会回复“QUERY PARAMETER1\r\n\r\n12345\r\n\r\n”。
一切都很基本。
所以,我所做的是创建一个通信类。这个调用在它自己的线程中调用,并将数据发送回主窗体......并且还允许我向它发送消息。
发送数据很容易。接收有点棘手。我已经使用了 datareceived 事件,当数据传入时,我会将其回显到屏幕上。我的问题是这样的:
当我发送命令时,我觉得我的处理非常狡猾。我正在做的是,假设我正在发送“QUERY PARAMETER1”。我将命令发送到设备,然后将“PARAMETER1”放入全局变量中,然后执行 Thread.Sleep(100)。
在收到的数据上,我有一些逻辑来检查传入的数据,并查看字符串是否包含全局变量中的值。由于回复可能是“QUERY PARAMETER1\r\n\r\n76767\r\n\r\n”,它看到它包含我的参数,解析字符串,并返回我正在查找的值,但将其放置到另一个全局变量中。
我的发送方法休眠了 100 毫秒。然后它醒来并检查返回的全局变量。如果它有数据......那么我很高兴,并且我处理数据。问题是......如果睡眠太短......它就会失败。我觉得它很不稳定.. 将东西放入变量中.. 然后等待...
另一种选择是使用 ReadLine 来代替,但这非常阻塞。因此,我删除了接收数据的方法,而是...只需发送数据...然后调用 ReadLine()
。这可能会给我更好的结果。除了我们最初连接时之外,没有时间,数据来自设备,而无需我请求。那么,也许 ReadLine
会更简单、更安全?这就是所谓的“阻塞”读取吗?另外,我可以设置超时吗?
希望有人可以指导我。
I am pretty new to serial comms, but would like advise on how to best achieve a robust application which speak to and listens to a serial device.
I have managed to make use of System.IO.SerialPort
, and successfully connected to, sent data to and recieved from my device. The way things work is this.
My application connects to the Com Port and opens the port.... I then connect my device to the com port, and it detects a connection to the PC, so sends a bit of text. it's really just copyright info, as well as the version of the firmware. I don't do anything with that, except display it in my 'activity' window.
The device then waits.
I can then query information, but sending a command such as 'QUERY PARAMETER1'. It then replies with something like:
'QUERY PARAMETER1\r\n\r\n76767\r\n\r\n'
I then process that. I can then update it by sending 'SET PARAMETER1 12345', and it will reply with 'QUERY PARAMETER1\r\n\r\n12345\r\n\r\n'.
All pretty basic.
So, what I have done is created a Communication Class. this call is called in it's own thread, and sends data back to the main form... and also allows me to send messages to it.
Sending data is easy. Recieving is a bit more tricky. I have employed the use of the datarecieved event, and when ever data comes in, I echo that to my screen. My problem is this:
When I send a command, I feel I am being very dodgy in my handling. What I am doing is, lets say I am sending 'QUERY PARAMETER1'. I send the command to the device, I then put 'PARAMETER1' into a global variable, and I do a Thread.Sleep(100).
On the data received, I then have a bit of logic that checks the incoming data, and sees if the string CONTAINS the value in the global variable. As the reply may be 'QUERY PARAMETER1\r\n\r\n76767\r\n\r\n', it sees that it contains my parameter, parses the string, and returns the value I am looking for, but placing it into another global variable.
My sending method was sleeping for 100ms. It then wakes, and checks the returned global variable. If it has data... then I'm happy, and I process the data. Problem is... if the sleep is too short.. it will fail. And I feel it's flaky.. putting stuff into variables.. then waiting...
The other option is to use ReadLine
instead, but that's very blocking. So I remove the data received method, and instead... just send the data... then call ReadLine()
. That may give me better results. There's no time, except when we connect initially, that data comes from the device, without me requesting it. So, maybe ReadLine
will be simpler and safer? Is this known as 'Blocking' reads? Also, can I set a timeout?
Hopefully someone can guide me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
嗯,Thread.Sleep() 也是阻塞的。实际上,更糟糕的是,因为即使机器负载很重,您也必须指定始终安全的睡眠时间。使用 ReadLine()总是更好,它会更快并且不会失败。
请注意,您的示例不需要客户端代码等待响应。它可以简单地假设该命令是有效的。您所需要的只是一个错误事件来表明出现了问题。
如果有一个命令需要客户端代码获取响应,您应该提供等待以及异步获取结果的选项。这为客户端代码提供了选择:等待很慢但很容易,异步很难编程。这是.NET框架中非常常见的模式,异步方法名称以“Begin”开头。查看有关它的 MSDN 库文章。
您还应该考虑在客户端代码喜欢的线程上传递异步通知。 SynchronizingObject 属性是一个很好的模式为此。
Well, Thread.Sleep() is blocking too. Much worse, actually, because you'd have to specify a sleep time that is always safe, even if the machine is under heavy load. Using ReadLine() is always better, it will be quicker and it cannot fail.
Note that your example doesn't require the client code to wait for a response. It can simply assume that the command was effective. All you need is an Error event to signal that something went wrong.
If there is a command that requires the client code to get the response that you should offer the option to wait as well as get the result asynchronously. That gives the client code options: waiting is slow but easy, async is difficult to program. It is a very common pattern in the .NET framework, the asynchronous method name starts with "Begin". Check the MSDN Library article about it.
You also should consider delivering asynchronous notifications on the thread that the client code prefers. The SynchronizingObject property is a good pattern for that.
如果您在后台线程上执行所有读取操作,那么我认为使用 ReadLine 没有任何问题。这是最简单、最可靠的解决方案。
您可以使用 ReadTimeout 属性设置读取操作的超时时间。
If you do all of your reads on a background thread, then I don't see any problem with using
ReadLine
. It's the simplest and most robust solution.You can use the ReadTimeout property to set the timeout for read operations.
您可能想阅读此串口
You may want to read this Serial Port