Python 如何使用UART通信构建GUI应用程序,以保持对用户的响应

Python 如何使用UART通信构建GUI应用程序,以保持对用户的响应,python,pyqt5,Python,Pyqt5,我正在用PyQt5编写一个应用程序,用于校准和测试产品。重要细节: 被测产品使用9600波特的老式UART/串行通信链路 …测试/校准操作涉及与另一个设备通信,该设备具有300波特(!)的UART/串行通信链路 在这两种情况下,通信协议都是ASCII文本,消息以换行符\r\n终止 在测试/校准周期期间,GUI需要与设备通信,读取读数,并将这些读数记录到屏幕中的各个框中。问题是,由于UART通信速度慢(如果通信中断,则超时时间长),如何保持GUI的响应性 最低限度可接受的解决方案(已经开始工作

我正在用PyQt5编写一个应用程序,用于校准和测试产品。重要细节:

  • 被测产品使用9600波特的老式UART/串行通信链路
  • …测试/校准操作涉及与另一个设备通信,该设备具有300波特(!)的UART/串行通信链路
  • 在这两种情况下,通信协议都是ASCII文本,消息以换行符
    \r\n
    终止
在测试/校准周期期间,GUI需要与设备通信,读取读数,并将这些读数记录到屏幕中的各个框中。问题是,由于UART通信速度慢(如果通信中断,则超时时间长),如何保持GUI的响应性

最低限度可接受的解决方案(已经开始工作)是创建一个通过串行端口进行通信的GUI,但是当GUI等待调用
serial.read()
完成或超时时,用户界面会变得非常迟钝和急促

理想的解决方案是一个GUI,即使在发送和接收串行数据时,它也具有良好的平滑响应感觉

扩展目标是一个GUI,它将串行通信的每个字符记录到用于调试的文本显示中,同时仍然为应用程序的实际逻辑提供一些很好的“消息级”抽象

我目前的“最低可接受”实现使用一个状态机,其中我运行一系列短函数,通常包括
serial.write()
serial.read()
命令,并暂停以允许GUI更新。但是状态机使得GUI逻辑有点难以遵循;如果与设备通信的程序流是以简单的线性方式编写的,那么代码将更容易理解

我真的很犹豫在整个代码中加入一堆
processEvents()
调用。在等待
serial.read()
时,即使这些也没有帮助。所以正确的解决方案可能涉及线程、信号和插槽,但我猜“线程”与“优化”有两条黄金法则:规则1:不要这样做。规则2(仅限专家):现在不要这样做


是否有任何现有的体系结构或设计模式可用作此类应用程序的起点?

好的,在过去几天中,我一直在挖掘,并找到了如何做到这一点。由于还没有任何回应,而且我确实认为这个问题也适用于其他人,我将继续发布我的解决方案。简而言之:

  • 是的,解决这个问题的最佳方法是使用PyQt线程,并使用信号和插槽在线程之间进行通信
  • 对于基本功能(上面的“所需”解决方案),只需遵循PyQt多线程GUI应用程序的现有基本设计模式:
    • GUI线程,其唯一任务是显示数据和中继用户输入/命令,以及
    • 执行所有其他操作(在本例中,包括串行通信)的工作线程
  • 一个绊脚石是:我很想将工作线程作为一个线性代码流来编写,但不幸的是,这是不可能的,因为工作线程有时需要从GUI获取信息。
    • 在两个线程之间来回获取数据的唯一方法是通过信号和时隙,并且时隙(即接收端)必须是可调用的,所以在函数的中间无法实现某种类型的<代码> GETDATA()/<代码>操作。相反,工作线程必须构造为一组单独的函数,每个函数在从GUI接收到适当的信号后都会启动
  • 获得串行数据监控功能(上面的“拉伸目标”)实际上相当简单——只要让代码中已有的低级串行发送和接收例程为该数据发出信号,GUI线程接收并记录这些信号

总而言之,它最终是对现有原则的一个非常简单的应用,但我正在写下它,希望下一个家伙不必像我一样走这么多死路。

Qt不仅是一个用于制作GUI的库,而且是一个具有其他模块的库,如Qt Networt、Qt WebEngine、Qt Mqtt,在这种情况下,最好使用避免总是带来线程的问题。例如,在中,我展示了使用Qt SerialPort和threads+pyserial实现相同的解决方案。

您的繁重任务是读取UART还是另一项繁重的任务?@eyllanesc如果“繁重”是指计算密集型任务,那么实际上没有一项任务是计算繁重的。但是UART任务需要很多时间,因为我需要频繁轮询UART或等待超时间隔。请尝试回答我的问题谢谢,我将查看Qt SerialPort。这看起来会很有帮助,因为我可以用信号来接收数据,而不是轮询端口。但我相信我仍然需要一个线程化应用程序,因为我的步骤可能涉及五个串行写入+读取周期,而且速度非常慢,所以我需要将其分解为一组小函数,或者将其移动到一个单独的线程。@Mr.Snrub我建议您实现一个状态机,目前正在将c++示例从转换为python。另一方面,如果你用一个真实的例子清楚地解释,你可以用qstatemachine给出一个状态机的例子,如果可以的话,我会尽量避免使用状态机。我的原始代码有点像状态机——我有一系列小函数与对QTimer.singleShot的调用绑定在一起。但是我感觉像这样