繁体   English   中英

Python串行模块无法配置端口

[英]Python serial module failing to configure port

我正在使用Python3.5.1 串行模块 当我打开端口时,它将失败并显示OS错误22(Windows错误87),这表明failure to configure port, one of the arguments in OPEN system call were incorrect, or malformed.

我的代码在串行设置上使用循环-将错误的数据包发送到设备,直到设备响应(可读)错误消息(因此我知道我的串行端口配置正确)为止。 是的,我应该只知道设备的设置,但这并不是一个完美的世界。

  import serial
  import time
  baud_rate = [50,75,110,134,150,200,300600,1200,1800,2400,4800,9600,19200,38400,57600,115200]
  parity = [serial.PARITY_ODD,serial.PARITY_EVEN,serial.PARITY_NONE]
  stop_bits = [serial.STOPBITS_TWO, serial.STOPBITS_ONE]
  bytesize = [serial.SEVENBITS,serial.EIGHTBITS]
  timeout = 5000
  for b in baud_rate:
     for p in parity:
         for s in stop_bits:
             for bs in bytesize:
                 ser = serial.Serial(port='COM3',baudrate=b,parity=p,stopbits=s,bytesize=bs)
                 try:
                     if ser.isOpen():
                         ser.write(b'TEST')
                         ser.reset_output_buffer()
                         time.sleep(1)
                         out = ser.read(3)
                         if out[0] == 64 and out[1] == 67 and out[2] == 32:
                             print("dumping settings")
                             print(ser.get_settings())
                     else:
                         ser.close()
                 except SerialException:
                    print("Serial Exception occured.")
                    pass

该问题在Windows 7 x64 Service Pack 1下发生。python版本为3.5。 该cmd.exe实例以管理员身份运行。

我非常确定运行脚本时COM3存在

 import serial.tools.list_ports
 ports = list(serial.tools.list_ports.comports())
 for p in ports:
     print(p)

我收到输出:

 >python list_serial.py
 COM3 - Prolific USB-to-Serial Comm Port (COM3)

因此,我相信端口URL / URI(idfk)是正确的。

完整的错误文字:

 Traceback (most recent call last):
   File "serial_reader.py", line 13, in <module>
     ser = serial.Serial(port='COM3',baudrate=b,parity=p,stopbits=s,bytesize=bs)
   File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialwin32.py", line 31, in __init__
     SerialBase.__init__(self, *args, **kwargs)
   File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialutil.py", line 180, in __init__
     self.open()
   File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialwin32.py", line 78, in open
     self._reconfigure_port()
   File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialwin32.py", line 220, in _reconfigure_port
     raise SerialException("Cannot configure port, something went wrong. Original message: %r" % ctypes.WinError())
 serial.serialutil.SerialException: Cannot configure port, something went wrong. Original message: OSError(22, 'The parameter is incorrect.', None, 87)

我已经确保正确安装了驱动程序,但是使用2个不同的串行转换器时会收到此错误。 因此,我认为问题与硬件或驱动程序无关。

您说您“应该只知道设备的设置,但这不是一个完美的世界”。 但是Windows确实允许通过GetCommProperties查询通信设备的属性。 pySerial似乎不支持此功能,但是您可以使用ctypes直接调用此函数。

下面定义了一个get_comm_properties函数,用于查询通讯端口的可设置属性。 它接受现有的设备句柄(例如pySerial端口的_handle属性)或DOS设备名称(例如COM1或WinAPI设备名称(例如\\\\.\\COM1

import collections
import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

GENERIC_READ  = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 3

INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
ERROR_FILE_NOT_FOUND = 0x0002

class COMMPROP(ctypes.Structure):
    _fields_= (('wPacketLength',       wintypes.WORD),
               ('wPacketVersion',      wintypes.WORD),
               ('dwServiceMask',       wintypes.DWORD),
               ('dwReserved1',         wintypes.DWORD),
               ('dwMaxTxQueue',        wintypes.DWORD),
               ('dwMaxRxQueue',        wintypes.DWORD),
               ('dwMaxBaud',           wintypes.DWORD),
               ('dwProvSubType',       wintypes.DWORD),
               ('dwProvCapabilities',  wintypes.DWORD),
               ('dwSettableParams',    wintypes.DWORD),
               ('dwSettableBaud',      wintypes.DWORD),
               ('wSettableData',       wintypes.WORD),
               ('wSettableStopParity', wintypes.WORD),
               ('dwCurrentTxQueue',    wintypes.DWORD),
               ('dwCurrentRxQueue',    wintypes.DWORD),
               ('dwProvSpec1',         wintypes.DWORD),
               ('dwProvSpec2',         wintypes.DWORD),
               ('wcProvChar',          wintypes.WCHAR * 1))

    class _CONST:
        COMMPROP_INITIALIZED = 0xE73CF52E
        SP_SERIALCOMM = 0x00000001
        BAUD_USER = 0x10000000 # programmable baud rate
        DATABITS_16X = 0x0020 # hardware wide data path

        PROV_SUBTYPE = collections.OrderedDict([
            ('UNSPECIFIED',    0x00000000),
            ('RS232',          0x00000001),
            ('PARALLELPORT',   0x00000002),
            ('RS422',          0x00000003),
            ('RS423',          0x00000004),
            ('RS449',          0x00000005),
            ('MODEM',          0x00000006),
            ('FAX',            0x00000021),
            ('SCANNER',        0x00000022),
            ('NETWORK_BRIDGE', 0x00000100),
            ('LAT',            0x00000101),
            ('TCPIP_TELNET',   0x00000102),
            ('X25',            0x00000103),
        ])

        PROV_CAPABILITIES = collections.OrderedDict([
            ('DTRDSR',        0x0001), # data-terminal-ready / data-set-ready
            ('RTSCTS',        0x0002), # request-to-send / clear-to-send
            ('RLSD',          0x0004), # receive-line-signal-detect
            ('PARITY_CHECK',  0x0008),
            ('XONXOFF',       0x0010), # XON/XOFF flow control
            ('SETXCHAR',      0x0020), # settable XON/XOFF
            ('TOTALTIMEOUTS', 0x0040), # total (elapsed) time-outs
            ('INTTIMEOUTS',   0x0080), # interval time-outs
            ('SPECIALCHARS',  0x0100),
            ('16BITMODE',     0x0200),
        ])

        SETTABLE_PARAMS = collections.OrderedDict([
            ('PARITY',       0x0001),
            ('BAUD',         0x0002),
            ('DATABITS',     0x0004),
            ('STOPBITS',     0x0008),
            ('HANDSHAKING',  0x0010), # flow control
            ('PARITY_CHECK', 0x0020),
            ('RLSD',         0x0040), # receive-line-signal-detect
        ])

        SETTABLE_BAUD = collections.OrderedDict([
            (75,     0x00000001),
            (110,    0x00000002),
            (134.5,  0x00000004),
            (150,    0x00000008),
            (300,    0x00000010),
            (600,    0x00000020),
            (1200,   0x00000040),
            (1800,   0x00000080),
            (2400,   0x00000100),
            (4800,   0x00000200),
            (7200,   0x00000400),
            (9600,   0x00000800),
            (14400,  0x00001000),
            (19200,  0x00002000),
            (38400,  0x00004000),
            (56000,  0x00008000),
            (57600,  0x00040000),
            (115200, 0x00020000),
            (128000, 0x00010000),
        ])

        SETTABLE_DATA = collections.OrderedDict([
            (5,  0x0001), # 5 data bits
            (6,  0x0002), # 6 data bits
            (7,  0x0004), # 7 data bits
            (8,  0x0008), # 8 data bits
            (16, 0x0010), # 16 data bits
        ])

        SETTABLE_STOP = collections.OrderedDict([
            (1,   0x0001), # 1 stop bit
            (1.5, 0x0002), # 1.5 stop bits
            (2,   0x0004), # 2 stop bits
        ])

        SETTABLE_PARITY = collections.OrderedDict([
            ('NONE',  0x0100), # no parity
            ('ODD',   0x0200), # odd parity
            ('EVEN',  0x0400), # even parity
            ('MARK',  0x0800), # mark parity
            ('SPACE', 0x1000), # space parity
        ])

    @property
    def max_baud(self):
        s = self.dwMaxBaud
        m = self._CONST.SETTABLE_BAUD
        if s == self._CONST.BAUD_USER:
            return 0
        else:
            return m[s]

    @property
    def prov_subtype(self):
        s = self.dwProvSubType
        m = self._CONST.PROV_SUBTYPE
        return [x for x, c in m.items() if c & s]

    @property
    def prov_capabilities(self):
        s = self.dwProvCapabilities
        m = self._CONST.PROV_CAPABILITIES
        return [x for x, c in m.items() if c & s]

    @property
    def settable_params(self):
        s = self.dwSettableParams
        m = self._CONST.SETTABLE_PARAMS
        return [x for x, c in m.items() if c & s]

    @property
    def settable_baud(self):
        s = self.dwSettableBaud
        m = self._CONST.SETTABLE_BAUD
        return [x for x, c in m.items() if c & s]

    @property
    def user_settable_baud(self):
        return bool(self.dwSettableBaud & self._CONST.BAUD_USER)

    @property
    def settable_data(self):
        s = self.wSettableData
        m = self._CONST.SETTABLE_DATA
        return [x for x, c in m.items() if c & s]

    @property
    def wide_settable_data(self):
        return bool(self.wSettableData & self._CONST.DATABITS_16X)

    @property
    def settable_stop(self):
        s = self.wSettableStopParity
        m = self._CONST.SETTABLE_STOP
        return [x for x, c in m.items() if c & s]

    @property
    def settable_parity(self):
        s = self.wSettableStopParity
        m = self._CONST.SETTABLE_PARITY
        return [x for x, c in m.items() if c & s]


LPCOMMPROP = ctypes.POINTER(COMMPROP)

class SECURITY_ATTRIBUTES(ctypes.Structure):
    _fields_ = (('nLength',              wintypes.DWORD),
                ('lpSecurityDescriptor', wintypes.LPVOID),
                ('bInheritHandle',       wintypes.BOOL))

LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES)

kernel32.CreateFileW.restype = wintypes.HANDLE
kernel32.CreateFileW.argtypes = (
    wintypes.LPCWSTR,      # _In_     lpFileName
    wintypes.DWORD,        # _In_     dwDesiredAccess
    wintypes.DWORD,        # _In_     dwShareMode
    LPSECURITY_ATTRIBUTES, # _In_opt_ lpSecurityAttributes
    wintypes.DWORD,        # _In_     dwCreationDisposition
    wintypes.DWORD,        # _In_     dwFlagsAndAttributes
    wintypes.HANDLE)       # _In_opt_ hTemplateFile

kernel32.CloseHandle.argtypes = (wintypes.HANDLE,)

kernel32.GetCommProperties.argtypes = (
    wintypes.HANDLE, # _In_  hFile
    LPCOMMPROP)      # _Out_ lpCommProp

def get_comm_properties(handle_or_port):
    if isinstance(handle_or_port, str):
        handle = kernel32.CreateFileW(
                        handle_or_port,
                        GENERIC_READ | GENERIC_WRITE,
                        0,    # exclusive access
                        None, # default security
                        OPEN_EXISTING,
                        0,
                        None)
        if handle == INVALID_HANDLE_VALUE:
            raise ctypes.WinError(ctypes.get_last_error())
        close_handle = True
    else:
        handle = handle_or_port
        close_handle = False
    try:
        prop = COMMPROP()
        if not kernel32.GetCommProperties(handle, ctypes.byref(prop)):
            raise ctypes.WinError(ctypes.get_last_error())
    finally:
        if close_handle:
            kernel32.CloseHandle(handle)
    return prop

例:

if __name__ == '__main__':
    for i in range(1, 10):
        port = r'\\.\COM%d' % i
        try:
            prop = get_comm_properties(port)
        except WindowsError as e:
            if e.winerror == ERROR_FILE_NOT_FOUND:
                continue
        print('%s properties' % port)
        x = prop.dwMaxTxQueue if prop.dwMaxTxQueue else 'no limit'
        print('\tMax output buffer size: %s' % x)
        x = prop.dwMaxRxQueue if prop.dwMaxRxQueue else 'no limit'
        print('\tMax input buffer size: %s' % x)
        x = prop.dwCurrentTxQueue if prop.dwCurrentTxQueue else 'unavailable'
        print('\tCurrent output buffer size: %s' % x)
        x = prop.dwCurrentRxQueue if prop.dwCurrentRxQueue else 'unavailable'
        print('\tCurrent input buffer size: %s' % x)
        x = prop.max_baud if prop.max_baud else 'user programmable'
        print('\tMax baud rate: %s' % x)
        print('\tProvider subtypes:\n\t\t%s' %
                    '\n\t\t'.join(prop.prov_subtype))
        print('\tProvider capabilities:\n\t\t%s' %
                    '\n\t\t'.join(prop.prov_capabilities))
        print('\tSettable parameters:\n\t\t%s' %
                    '\n\t\t'.join(prop.settable_params))
        print('\tSettable baud rates:\n\t\t%s' %
                    '\n\t\t'.join([str(x) for x in prop.settable_baud]))
        print('\tSettable user baud rates: %s' %
                    prop.user_settable_baud)
        print('\tSettable data bits:\n\t\t%s' %
                    '\n\t\t'.join([str(x) for x in prop.settable_data]))
        print('\tSettable wide data bits: %s' %
                    prop.wide_settable_data)
        print('\tSettable stop bits:\n\t\t%s' %
                    '\n\t\t'.join([str(x) for x in prop.settable_stop]))
        print('\tSettable parity:\n\t\t%s' %
                    '\n\t\t'.join(prop.settable_parity))

输出:

\\.\COM1 properties
        Max output buffer size: no limit
        Max input buffer size: no limit
        Current output buffer size: unavailable
        Current input buffer size: 4096
        Max baud rate: user programmable
        Provider subtypes:
                RS232
                RS422
                RS449
                FAX
                LAT
                X25
        Provider capabilities:
                DTRDSR
                RTSCTS
                RLSD
                PARITY_CHECK
                XONXOFF
                SETXCHAR
                TOTALTIMEOUTS
                INTTIMEOUTS
        Settable parameters:
                PARITY
                BAUD
                DATABITS
                STOPBITS
                HANDSHAKING
                PARITY_CHECK
                RLSD
        Settable baud rates:
                75
                110
                134.5
                150
                300
                600
                1200
                1800
                2400
                4800
                7200
                9600
                14400
                19200
                38400
                56000
                57600
                115200
        Settable user baud rates: True
        Settable data bits:
                5
                6
                7
                8
        Settable wide data bits: False
        Settable stop bits:
                1
                1.5
                2
        Settable parity:
                NONE
                ODD
                EVEN
                MARK
                SPACE

在Windows 7中,将波特率<100视为配置错误。因此,以50,75波特率启动循环都会产生错误。 110波特不返回错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM