如何通过串行连接有效地使用设备?
我已经为此奋斗了很长一段时间,最终我确实得到了一个可行的解决方案,但它并不漂亮,我希望从 stackoverflow 社区获得一些关于如何完成此操作的智慧。
基本上,我正在使用使用菊花链 USB 连接连接到计算机的电机,并且我必须使用 .Net 中的 SerialPort 类与它们进行通信,并且它通过计算机上安装的一些驱动程序通过 USB 与电机进行通信。
问题在于,电机是菊花链式连接的,当我
向其中一个电机询问信息或告诉它做某事时,我必须等待结果返回,然后才能对该电机或任何其他电机执行其他操作。
我刚刚经历了一段艰难的时期,我确信有更好的方法来处理我从未接触过的串行通信。对于此类事情有什么好的指导方针或最佳实践吗?这是一个相当标准的事情吗(串行通信 -> USB 通过计算机上安装的驱动程序)
我正在使用六个 MDrive23Plus 运动控制 来自 IMS 的电机。
我可以提供更多细节,但我不太确定这会导致什么结果。我希望这对 StackOverflow 来说足够具体,尽管我知道它有点模糊。我只是真的不知道如何更好地问它。
实际上,归根结底是如何有效地同步通信,以及如何有效地等待和读取返回的数据?我知道这对某些人来说可能很简单,但对我来说效果不佳。
I have struggled with this for a long time, and I did get a solution working eventually but it wasn't pretty, and I am hoping to gain a little wisdom from the stackoverflow community about how this should be done.
Basically I am working with motors that connect to the computer using a daisychained USB connection and I have to communicate with them using the SerialPort class in .Net and it goes through some driver installed on the computer to talk with the motors over USB.
The problem is that the motors are daisy chained, and when I ask
for information from one, or tell it to do something, i have to wait on the result to come back before doing something else with that motor or with any of the others.
I've just had a generally hard time with it, and I'm sure there are better ways of working with serial communication that I've just never been exposed to. Are there any good guidelines or best practices for this kind of thing? Is this a fairly standard thing to do be doing (serial communication -> usb via a driver installed on computer)
I'm working with six of the MDrive23Plus Motion Control motors from IMS.
I can provide plenty more details, but I'm not really sure where this will lead. I hope this is specific enough for StackOverflow, though I know it is sort of vague. I just don't really know how to ask it any better.
Really what it comes down to is how do I synchronize communication effectively, and how do I wait and read the data coming back effectively? I know this is probably very simple to some people, but it just hasn't been working well for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是多点串行网络工作的限制......它没有什么魔力,你可以减轻一些痛苦
通常最好的方法是放入一个抽象层,其中你有一个你想要的东西的消息队列发送,并且每个都有一个回调,当收到响应时会调用该回调。
this is the limit of working multi drop serial networks.....there is no magic to it, you can ease some of the pain
Generally the best approach is to put in an abstraction layer where you have a message queue of things you want to send, and each of those have a callback that gets called when it gets a response.
您可能需要多个线程和/或异步操作。过去,在进行串行通信(不是在 .NET 中)时,我们会对端口上的读取进行排队。当读取完成时,回调函数(委托)将触发,将执行读取处理,可能会更改控制状态 - 我们的典型示例是条形码读取,同时具有键盘读取和计时器。其中一个事件将完成,这将导致一项操作(可能将其他排队的读取留在原地或取消它们,具体取决于状态要移动到的位置。)
您可能需要考虑使用状态机。在这种情况下,状态机知道正在进行什么操作、允许哪些转换、如何在它们之间进行转换以及转换会导致什么操作。
You might need multiple threads and/or asynchronous operations. In the past, when doing serial comms (not in .NET), we would queue up reads on the port(s). When a read would complete, the callback function (delegate) would fire, the processing of the read would be carried out, potentially changing the control state - our typical example was a barcode read, while simultaneously having a keyboard read and a timer. One of the events would complete, which would cause an action (potentially leaving the other queued reads in place or cancelling them, depending on what the state was moving to.)
You might want to look into using state machine(s). In this case, the state machine knows what operations are going on, which transitions are allowed and how to get between them and what actions the transitions cause.
许多设备的串行通信都变化无常。有些设备的通信无法正常运行,无法以指定的波特率读取线路。
我发现我必须表征设备的通信。有些供应商的同一型号的两个设备的通信特性不同。人物塑造是一件相当乏味的事情。表征涉及发现各种情况的组合,然后思考可能性。
最坏的情况是影响读/写操作清洁度的状态/可能性组合的激增,并且您可以通过妥协使用读/写操作组中最慢的公分母来减少状态数量。这一切背后一定有科学依据,但我只是用暴力测试尽了最大的努力。
当然,这会导致有一个读/写层将需要通信的例程与直接与端口通信分开。
或者,我们都知道快速、懒惰但效率低下的方法是在每个字节后插入 10 毫秒的等待。
Many devices are fickle on their serial comms. There are devices whose comms cannot behave properly with a line read at the baud rate they specified.
I find that I have to characterize the comms of a device. There are vendors where the comms characteristics of two devices of the same model are different. Characterization is a rather tedious affair. Characterization involves discovering various combination of situations and then think of the possibilities.
The worst case scenario is a proliferation of states/combinations of possibilities influencing the cleanliness of the read/write operations and you reduce the number of states by compromising to use the slowest common denominator among groups of read/write operations. There must be a science behind all this but I just try my voodooistic best using brute force testing.
Which, of course, would lead to having a read/write layer separating the routines needing communication from directly communicating with the port.
Alternatively, we all know the quick and lazy but inefficient way is inserting a 10 ms wait after every byte.
自 2004 年以来,我也一直在使用 .net 串行端口类,我同意状态机可能是这里的方法,除了发送命令,然后等待握手中的相关响应(设备准备就绪时将响应)来回应)。
将您的
serialPort.DataReceived()
事件处理程序视为您的前端。然后让
DataReceived
执行BeginInvoke()
,而不是 Invoke(),因为串行端口是方法的异步接口,AddReceive()
接下来,在
AddReceive()
中计算它看到的字节数如果大于 0,则将数据附加到 stringbuilder 容器,例如 sbReceived
最后触发一个计时器处理程序来拾取流中的任何“剩余”数据,其中它还在方法
ReadData()
上执行“beginInvoke”现在我们准备解析数据并传递到终端显示(这里最好使用富文本框),用颜色编码各种提示来指示>>输出数据,<<在数据、配置、错误、状态中
由于您有多个端口需要监控以及每个端口上的 I/O 状态,因此您可以在一个终端显示器内执行此操作。
我同意状态机在这里是个好主意,无论如何,进程都是有状态的;在其他端口上发送串行端口命令之前,您正在等待串行 1 解析输出的输出来匹配您需要的内容。这样做可以使事情井井有条,并且不同的串行端口活动可以很好地划分出来。在另一种情况下,您可能会发生多个后续命令/查询输出和设备响应周期,最好在两者之间执行
while(serial1.ByteCount==0){};
以便让设备控制握手中响应的时间。连接调试数字 I/O 设备也很有帮助,这样您就可以切换线路来监控延迟时间并在 DSO 上观察以验证是否满足时序要求。最后,一定要在每个写入/读取周期清除端口,这样就不会遇到溢出问题,以及数据缓冲区、字符串生成器容器等的重新初始化。
祝你有美好的一天
I have also been using the .net serial port class since 2004, i agree state machines are probably the way to go here, that along with sending out command, then wait for the associated response in the handshake(device will respond when it is ready to respond).
Consider your
serialPort.DataReceived()
event handler as your front end.then have
DataReceived
do aBeginInvoke()
, not an Invoke() as serial port is asynchronous interface to a method,AddReceive()
next, in
AddReceive()
count the number of bytes that it seesif more than 0, then append data to stringbuilder container, say sbReceived
finally fire a timer handler to pickup any 'left over' data in the stream where it also does a 'beginInvoke' on method,
ReadData()
now we are ready to parse data out and pass to terminal display(best to use richtext box here), color code various prompts to indicate >> out data, << in data, configuration, error, status
since you have various ports to monitor and i/o status on each one, you could do so inside of one terminal display.
I agree state machine is good idea here, process is very stateful anyways; you are waiting for output of serial1 parsed output to match what you need, before sending serial port commands on other ports. doing it this way would keep things organized and different serial port activities are nicely partitioned out. in the other case where you might have several subsequent command/query out and device response cycles happening, it might be better to do
while(serial1.ByteCount==0){};
in between to just let the device control the timing of the response in the handshake. it can also be helpful to have a debug digital i/o device hooked up so you can toggle line to monitor latency times and watch on DSO to verify timing requirement is being met.finally, be certain to purge your port on each write/read cycle so you don't experience overflow issues, along with re-initialization of data buffers, stringbuilder containers and the like.
have a good day
我在 Zaber Technologies 工作,我为通过菊花通信的精密步进电机控制器构建了一个控制库-链式串行连接。我使用了三层:
然后,调用代码可以选择是对会话层使用同步请求,还是对设备层使用异步请求。
如果您对更多详细信息感兴趣,可以下载源代码 或者查看用户文档,其中讨论了针对库编写脚本的内容。
I work for Zaber Technologies, and I built a control library for our precision stepper motor controllers that communicate over a daisy-chained serial connection. I used three layers:
Calling code then has the choice of whether to use synchronous requests with the conversation layer, or use asynchronous requests with the device layer.
If you're interested in more details, you can download the source code or look at the user documentation that talks about writing scripts against the library.