2009-12-08 72 views
6

我很久没有遇到这个问题,而且我最终得到了一个解决方案,但它并不漂亮,我希望从stackoverflow社区获得一些关于如何完成这个任务的智慧。如何通过串行连接有效地使用设备?

基本上我使用的是连接到计算机的电机,使用菊花链式USB连接,我必须使用.Net中的SerialPort类与它们进行通信,并且它会通过安装在计算机上的某个驱动程序与电机进行通信USB。

的问题是电机菊花链连接在一起,当我问

信息从一个,或告诉它做一些事情,我必须等待结果做别的事情与之前回来马达或任何其他人。

我刚刚度过了一段艰难的时期,而且我确信有更好的方式来处理我从未接触过的串行通信。这种事情有没有好的指导方针或最佳实践?这是一个相当标准的事情要做(串行通信 - > USB通过安装在计算机上的驱动程序)

我正在与IMSMDrive23Plus Motion Control电机中的六个。

我可以提供更多的细节,但我不确定这会导致什么。我希望这对StackOverflow足够具体,但我知道它有点模糊。我只是不知道如何更好地问它。

真的是我该如何有效地同步通信,以及如何等待和读取有效返回的数据?我知道这对一些人来说可能很简单,但对我来说这一直不太好。

回答

1

您可能需要多个线程和/或异步操作。在过去,当进行串行通信(而不是.NET)时,我们会在端口上排队读取数据。当读取完成时,回调函数(委托)将会触发,读取的处理将被执行,可能会改变控制状态 - 我们典型的例子是条形码读取,同时还有键盘读取和计时器。其中一个事件会完成,这将导致一个动作(可能会使其他排队的读取到位或取消它们,具体取决于状态正在移动到哪个位置)。

您可能想使用状态机)。在这种情况下,状态机知道正在进行哪些操作,允许哪些转换以及如何在它们之间以及转换导致什么操作。

2

这是工作的多路串行网络的限制.....没有魔法给它,可以缓解一些疼痛的

一般来说,最好的办法是放在一个抽象层,你有一个你想发送的东西的消息队列,每个人都有一个回调,当它得到回应时被调用。

1

我为Zaber Technologies工作,我为精密步进电机控制器构建了一个控制库,它们通过菊花链式串行连接进行通信。我用了三层:

  1. 端口 - 这一层只关心通信协议。它公开了发送消息的方法,并将消息参数转换为字节流。它还监听输入行,将字节流转换为消息结构,并在收到完整消息时引发事件。
  2. 设备 - 此层知道如何将消息发送到菊花链中的特定设备,以及如何过滤掉菊花链中其他设备的响应。
  3. 对话 - 此层协调请求和响应,并让调用代码发出请求,阻止线程,直到响应返回。

调用代码然后可以选择是使用对话层的同步请求还是使用设备层的异步请求。

如果您有兴趣了解更多详细信息,可以下载the source code或查看user documentation,其中讨论了如何针对图书馆编写脚本。

+1

您提供的链接是针对二进制文件的,而不是源代码。 – gonzobrains 2013-04-06 06:11:41

+1

这很奇怪,@gonzo,我想知道我为什么这么做。我现在更新了链接以指向最新的源代码。 – 2013-04-07 04:52:44

+0

谢谢。你可以点击我的链接上的+1来帮助你吗? ;)我现在要检查你的源代码。我对确定如何最好地实现线程化串行端口解决方案非常感兴趣。 – gonzobrains 2013-04-08 05:41:37

1

许多设备对他们的串行通信变得反复无常。有些设备的通信不能正确地以他们指定的波特率读取行。

我发现我必须表征设备的通信。有些供应商在同一型号的两台设备的通信特性不同。表征是一件相当乏味的事情。表征包括发现各种情况的组合,然后考虑可能性。

  1. 在插入延迟之前连续读取/写入的最低阈值字节数。可能性是一次一个字符。
  2. 恢复读/写之前最安全的延迟。
  3. 从初始化通信到稳态通信所需的最小延迟的变化。
  4. 在插入延迟之前,在指定的波特率下可写入的阈值字节数的变化。

最糟糕的情况是影响读/写操作清洁度的状态/可能性组合扩散,并且通过妥协使用读/写操作组中最慢的公分母来减少状态数。必须有一门科学背后的所有这些,但我只是尝试使用强力测试我的伏都教最好。

这当然会导致读/写层将需要通信的例程与直接与端口通信。

或者,我们都知道快速而懒惰但效率低下的方法是在每个字节之后插入10 ms等待。

1

自2004年以来,我也一直在使用.net串口类,我同意状态机可能是这里的一种方式,与发出命令一起,然后等待握手中的相关响应(设备将响应当它准备好回应时)。

考虑将您的serialPort.DataReceived()事件处理程序作为您的前端。 然后有DataReceivedBeginInvoke(),而不是调用()作为串行端口是异步接口的方法,AddReceive() 下,在AddReceive()计数,它认为 如果大于0,则数据追加到StringBuilder的容器的字节数,说sbReceived 终于启动一个定时器处理程序来拾取流中的任何“剩余”数据,它也在方法上执行'beginInvoke',ReadData() 现在我们准备解析数据并传递到终端显示器(最好使用richtext盒子),颜色代码各种提示来指示>>输出数据,< <在数据,配置,错误,状态 因为你有不同的端口监视和每个I/O状态,你可以这样做在一个终端显示。

我同意状态机在这里是好主意,反正进程是非常有状态的;在发送其他端口上的串行端口命令之前,您正在等待serial1解析输出的输出与您所需的匹配。这样做会使事情保持有序,并且不同的串行端口活动被很好地分开。在另一种情况下,您可能会有多个后续命令/查询和设备响应周期发生,最好在while(serial1.ByteCount==0){};之间,以便让设备控制握手中响应的时间。将调试数字I/O设备连接起来也很有帮助,因此您可以通过切换线路来监视延迟时间,并在DSO上观察以验证时序要求是否得到满足。

终于,在每个写入/读取循环中清除您的端口,以便您不会遇到溢出问题,以及重新初始化数据缓冲区,stringbuilder容器等。

祝您有个愉快的日子