2

我正在使用 Python 2.5.4 和 Windows 7。

我正在尝试创建一个使用 pygame 从微控制器传输和接收信息的程序。当微控制器仅将数据写入 pygame 时,此代码工作正常,但是当该行包含在接收信息的微控制器代码(readline)中时,pygame 窗口冻结(不只是关闭窗口,所以我可以看到问题出在哪里)。我想知道是否有人在微控制器和 pygame/pyserial 相互交谈和倾听方面有任何经验?

我读过一篇可能类似的帖子,但我不理解代码,也不确定是否是同一个问题。我在这些论坛上阅读了“流量控制”一词,我想知道这是否是我的问题?

我的代码是:

import os, pygame, math, serial   
from pygame.locals import *
from pygame.compat import geterror
from time import clock, time
pygame.init()
w = 1100   #sets pygame screen width
h = 642   #sets pygame screen height
screen = pygame.display.set_mode((w, h),0,32)  #make and display screen

pygame.display.flip()   #Update screen
running = 1
font = pygame.font.Font(None, 36)
clock = pygame.time.Clock()
port = serial.Serial("COM2", 115200)

while running:          #Loop this
   for event in pygame.event.get():    #get user input
      if event.type == pygame.QUIT:    #if user clicks the close X
           running = 0                 #make running 0 to break out of loop

   temp = float(port.readline())
   clock.tick(100)
   value = font.render(str(temp), 1, (100, 100, 100))
   screen.blit(value, (280,165))
   pygame.display.flip()   #Update screen
   port.write('3')
4

2 回答 2

2

readline 在等待行终止字符时可能会阻塞;回车和/或换行的某种组合。您的微控制器需要在 readline 返回之前发送一个或两个字符。您应该检查 pyserial 文档以查看 chars readline 期望的行术语,并通过查看终端甚至在串行流上执行 hexdump 来验证您的 uC 正在发送它们。

于 2012-06-22T14:00:59.320 回答
1

似乎最有可能出现的问题:死锁

稍微扩展一下 Jeff Laughlin 的帖子:

很多很多人都遇到过这个死锁问题:

  • PC 不能发送任何字符,因为它处于阻塞 readline() 命令的中间,等待微控制器发送换行符。
  • 微控制器无法发送任何字符,因为它处于阻塞 readline() 命令的中间,等待 PC 发送换行符。

双方最终都永远等待对方做某事。

双向通信系统有很多方法会陷入这种僵局。也许通过串行电缆的换行符被损坏了一点点,以至于它看起来不再像换行符了。也许一个长字符串的传输速度比接收器处理它的速度快,溢出了一些缓冲区,丢失的字节之一是换行符。这条换行符是朝微型到 PC 还是 PC 到微型方向发展都没有关系;无论哪种方式,我们都会陷入同样的​​僵局。

解决方法 1:超时

由“import serial”加载的 pyserial 包的文档对此问题有一个部分解决方法:设置超时。该文档特别建议:

打开串行端口时请指定超时。否则,如果没有收到换行符,它可能会永远阻塞。

您能否在 PC 和微型计算机两端都实施该变通方案?

解决方法 2:非阻塞读取行

许多人实现了一个非阻塞的 readline() 子例程,它的工作原理如下:

def try_readline():
  • 串行端口中是否有新字节,或者串行缓冲区是否为空?(也许检查类似inWaiting())。
  • 如果它仍然是空的,try_readline() 立即返回空字符串。
  • (可选)距离我们上一次得到一个字节已经很久了吗?如果是这样,请将缓冲区重置为空字符串。
  • 从串行端口读取一个字节,并将其附加到内部缓冲区的末尾。
  • 缓冲区(比任何有效消息长几个字节)是否即将溢出?如果是这样,则将缓冲区重置为空字符串。
  • 我们刚刚读取的字节是换行符吗?
  • 如果不是换行符,try_readline() 会立即返回空字符串。
  • 嘿,这是换行符。最后!
  • 将消息从内部缓冲区复制到返回字符串。
  • 将缓冲区重置为空字符串。
  • try_readline() 在返回字符串中返回消息。

进一步讨论

使用任一解决方法,设置您的程序,使其定期且无条件地——无论 try_readline 函数是否返回空字符串以外的任何内容;以及 readline() 函数是否超时或接收到有效消息——无条件地发送信息行。

您可能还会考虑,如果您在消息中途插入串行电缆,并且您的软件收到半条消息,然后是换行符,那么究竟会发生什么。另外,如果发送器连续发送一堆换行符会发生什么?

双向交流是人类几乎无意识地做的事情之一,因此我们对它的复杂程度感到惊讶。

ps:你见过这个用 Pyserial 做 PC-to-Arduino 的小程序吗?

ps:也许你可以浏览一下最新的Serial Programming Wikibook的草稿并填上一两个空洞,或者至少帮助我们指出需要填补的空洞在哪里?

于 2012-06-23T02:35:39.030 回答