PySerial 在发送时处理 serial.serialutil.SerialException

1 投票
2 回答
8992 浏览
提问于 2025-04-18 02:24

我有一个应用程序,想从一个微控制器获取调试信息。这个微控制器的工作方式是每5分钟开机,10秒钟关机。它通过USB连接,使用Windows的 usbser.sys 驱动程序作为虚拟串口设备。当设备断开再重新连接时,如果我的应用程序(比如putty、tera term或者我的Python应用)尝试读取数据,就什么都读不到;如果尝试写数据,就会出现超时错误,然后断开连接。

所以,如果我知道可以捕捉到这个错误(尝试写数据时),我该怎么关闭端口再重新打开呢?如果我简单地用 ser.close()ser.open(),似乎总是无法重新连接。

下面是一个特别的 send 函数,它尝试写入数据并捕捉错误。

def send(ser, message):
    if ser.isOpen():
        try:
            ser.write(message)
        except serial.serialutil.SerialException:
            # attempt to reconnect?
            # already tried making new serial object
            # which just fails when trying to open
            # check if reconnected?
        else:
            return True
    else:
        return False

希望有人有过类似的经验,或者有什么建议可以尝试,或者对Windows中的串口处理和控制有一些见解。

2 个回答

0

你可以尝试通过使用 ser.setDTR(False)ser.setDTR(True) 这两个函数来改变 DTR 信号。也许这个 链接 会对你有帮助。

另外,你还可以使用像 ser.getDTR() 这样的命令来检查串口接口的状态。

1

我刚意识到我从来没有为这个问题发过答案。结果发现是USB虚拟串口驱动的问题,我没法解决,但我想出了一个变通的方法。

注意:这个问题和答案是针对Windows平台的

微软提供了一个叫做 devcon.exe 的程序。这是Windows设备控制台,类似于设备管理器的命令行版本。

最终,当我发现可以在不拔掉设备的情况下移除设备并重新扫描(就像“虚拟”拔掉它一样)时,我意识到可以调用这个程序来帮我移除特定的设备,然后在检测到断开连接时重新扫描设备结构。所以这里是我在转储串口数据时用来实现这个功能的Python代码片段。可能不是最干净的代码,但这只是一个快速且简单的日志记录脚本。希望这能帮助一些遇到相同问题的你们。

import serial
from subprocess import call
from time import sleep

def remove(ser):
    try:
        ser.close()
    except:
        print "Could not close port"
    call(["devcon.exe","remove","USB\VID_0D59&PID_0005*"])

def rescan():
    call(["devcon.exe","rescan"])
    sleep(30)

def send(ser, message):
    if ser.isOpen():
        try:
            ser.write(message)
        except serial.serialutil.SerialException:
            remove(ser)
            rescan()
            try:
                ser.open()
            except serial.serialutil.SerialException:
                try:
                    remove(ser)
                    rescan()
                except:
                    print 'Could not reconnect'
                    return False
            else:
                print 'Reconnected to %s' % (ser.portstr)
                ser.write(message)
                return True
        else:
            return True

重要提示:尝试向端口发送数据然后接收异常是唯一能判断设备是否重启的方法。无论是打开、关闭还是检查连接,都无法成功与这个驱动程序配合,所以这是我当时能想到的最佳解决方案。

另外,注意在 rescan() 函数中有一个任意的30秒延迟。这是为了给电脑足够的时间来识别设备并找到合适的驱动程序。这个时间因系统和设备而异。

这个代码片段是Python 2的。

最后,这可能很明显,但这个解决方案需要 devcon.exe 在同一个目录下或者在 PATH 中。

撰写回答