106

我正在寻找一种简单的方法来列出 PC 上所有可用的 com 端口。

我找到了这种方法,但它是特定于 Windows 的:Listing serial (COM) ports on Windows?

我在 Windows 7 PC 上使用 Python 3 和 pySerial。

我在 pySerial API(http://pyserial.sourceforge.net/pyserial_api.html)中找到了一个serial.tools.list_ports.comports()列出 com 端口(正是我想要的)的函数。

import serial.tools.list_ports
print(list(serial.tools.list_ports.comports()))

但它似乎不起作用。当我的 USB 到 COM 网关连接到 PC 时(我在设备管理器中看到 COM5),此 COM 端口不包含在list_ports.comports(). 相反,我只得到似乎连接到调制解调器的 COM4(我在设备管理器的 COM&LPT 部分中看不到它)!

你知道为什么它不起作用吗?您是否有其他非系统特定的解决方案?

4

13 回答 13

167

这是我使用的代码。

使用 Python 2 和 Python 3 在 Windows 8.1 x64、Windows 10 x64、Mac OS X 10.9.x / 10.10.x / 10.11.x 和 Ubuntu 14.04 / 14.10 / 15.04 / 15.10 上成功测试。

import sys
import glob
import serial


def serial_ports():
    """ Lists serial port names

        :raises EnvironmentError:
            On unsupported or unknown platforms
        :returns:
            A list of the serial ports available on the system
    """
    if sys.platform.startswith('win'):
        ports = ['COM%s' % (i + 1) for i in range(256)]
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        # this excludes your current terminal "/dev/tty"
        ports = glob.glob('/dev/tty[A-Za-z]*')
    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')
    else:
        raise EnvironmentError('Unsupported platform')

    result = []
    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            result.append(port)
        except (OSError, serial.SerialException):
            pass
    return result


if __name__ == '__main__':
    print(serial_ports())
于 2013-01-08T21:38:10.027 回答
39

在pyserial文档中基本上提到了这一点 https://pyserial.readthedocs.io/en/latest/tools.html#module-serial.tools.list_ports

import serial.tools.list_ports
ports = serial.tools.list_ports.comports()

for port, desc, hwid in sorted(ports):
        print("{}: {} [{}]".format(port, desc, hwid))

结果 :

COM1:通讯端口 (COM1) [ACPI\PNP0501\1]

COM7:联发科 USB 端口 (COM7) [USB VID:PID=0E8D:0003 SER=6 LOCATION=1-2.1]

于 2018-10-15T02:58:38.880 回答
29

您可以使用:

python -c "import serial.tools.list_ports;print serial.tools.list_ports.comports()"

按已知端口过滤: python -c "import serial.tools.list_ports;print [port for port in serial.tools.list_ports.comports() if port[2] != 'n/a']"

在此处查看更多信息: https ://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.list_ports

于 2015-11-12T03:44:16.627 回答
11

Thomas 出色答案的一个可能改进是让 Linux 和可能的 OSX 也尝试打开端口并仅返回那些可以打开的端口。这是因为 Linux 至少将大量端口列为 /dev/ 中的文件,这些文件没有连接到任何东西。如果您在终端中运行,/dev/tty 是您正在工作的终端,打开和关闭它可能会弄乱您的命令行,因此 glob 旨在不这样做。代码:

    # ... Windows code unchanged ...

    elif sys.platform.startswith ('linux'):
        temp_list = glob.glob ('/dev/tty[A-Za-z]*')

    result = []
    for a_port in temp_list:

        try:
            s = serial.Serial(a_port)
            s.close()
            result.append(a_port)
        except serial.SerialException:
            pass

    return result

此对 Thomas 代码的修改仅在 Ubuntu 14.04 上进行了测试。

于 2014-07-13T06:21:25.470 回答
10

带有 pySerial 包的一条线解决方案。

python -m serial.tools.list_ports
于 2018-11-05T17:03:02.263 回答
10

改进moylop260的答案:

import serial.tools.list_ports
comlist = serial.tools.list_ports.comports()
connected = []
for element in comlist:
    connected.append(element.device)
print("Connected COM ports: " + str(connected))

这列出了硬件中存在的端口,包括正在使用的端口。根据pyserial 工具文档,列表中存在更多信息

于 2017-08-01T18:20:09.953 回答
5

可能晚了,但可能会帮助有需要的人。

import serial.tools.list_ports


class COMPorts:

    def __init__(self, data: list):
        self.data = data

    @classmethod
    def get_com_ports(cls):
        data = []
        ports = list(serial.tools.list_ports.comports())

        for port_ in ports:
            obj = Object(data=dict({"device": port_.device, "description": port_.description.split("(")[0].strip()}))
            data.append(obj)

        return cls(data=data)

    @staticmethod
    def get_description_by_device(device: str):
        for port_ in COMPorts.get_com_ports().data:
            if port_.device == device:
                return port_.description

    @staticmethod
    def get_device_by_description(description: str):
        for port_ in COMPorts.get_com_ports().data:
            if port_.description == description:
                return port_.device


class Object:
    def __init__(self, data: dict):
        self.data = data
        self.device = data.get("device")
        self.description = data.get("description")


if __name__ == "__main__":
    for port in COMPorts.get_com_ports().data:
        print(port.device)
        print(port.description)

    print(COMPorts.get_device_by_description(description="Arduino Leonardo"))
    print(COMPorts.get_description_by_device(device="COM3"))
于 2021-02-18T19:11:46.537 回答
3

请尝试以下代码:

import serial
ports = serial.tools.list_ports.comports(include_links=False)
for port in ports :
    print(port.device)

首先需要导入包进行串口通信,所以:

import serial

然后创建当前可用的所有串行端口的列表:

ports = serial.tools.list_ports.comports(include_links=False)

然后,沿着整个列表走,您可以例如打印端口名称:

for port in ports :
    print(port.device)

这只是一个如何获取端口列表并打印其名称的示例,但您可以使用此数据执行其他一些选项。之后尝试打印不同的变体

港口。

于 2018-09-24T20:27:27.683 回答
1

试试这个代码

import serial.tools.list_ports
for i in serial.tools.list_ports.comports():
    print(i) 

它返回

COM1 - Port de communication (COM1)
COM5 - USB-SERIAL CH340 (COM5)

如果您只是不知道端口的名称,例如 COM1

import serial.tools.list_ports
for i in serial.tools.list_ports.comports():
    print(str(i).split(" ")[0])

它返回

COM1
COM5

就我而言,py 3.7 64bits

于 2020-08-19T20:23:27.137 回答
0

有几个选项可用:

使用 NULL lpDeviceName调用QueryDosDevice以列出所有 DOS 设备。然后对每个设备名依次使用 CreateFile 和GetCommConfig判断是否为串口。

使用 GUID_DEVINTERFACE_COMPORT 的 ClassGuid调用SetupDiGetClassDevs

WMI 也可用于 C/C++ 程序

在win32 新闻组和 CodeProject,呃,project上有一些对话。

于 2012-08-23T11:29:38.760 回答
0

一些简单的东西,但我经常使用它。

import serial.tools.list_ports as ports

com_ports = list(ports.comports()) # create a list of com ['COM1','COM2'] 
    for i in com_ports:            
        print(i.device) # returns 'COMx'        
于 2021-05-13T13:13:24.830 回答
0

需要注意的一件事,像这样的代码:

for i in serial.tools.list_ports.comports():
print(i) 

返回以下内容:

COM7 - Standard Serial over Bluetooth link (COM7) COM1 - Communications Port (COM1) COM8 - Standard Serial over Bluetooth link (COM8) COM4 - USB-SERIAL CH340 (COM4)

如果您希望按顺序列出端口,并且只列出您可用的端口,请尝试:(感谢 tfeldmann)

   def serial_ports():
    """ Lists serial port names

        :raises EnvironmentError:
            On unsupported or unknown platforms
        :returns:
            A list of the serial ports available on the system
    """
    if sys.platform.startswith('win'):
        ports = ['COM%s' % (i + 1) for i in range(256)]
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        # this excludes your current terminal "/dev/tty"
        ports = glob.glob('/dev/tty[A-Za-z]*')
    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')
    else:
        raise EnvironmentError('Unsupported platform')

    result = []
    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            result.append(port)
        except (OSError, serial.SerialException):
            pass
    return result

这将返回以下内容:

['COM1', 'COM4', 'COM8']

因此,与第一个示例不同,结果是 ['COM7', 'COM1', 'COM8', 'COM4'],这次我按顺序获取了所有的 COM 端口,并且只有可用的端口。如果您按顺序需要它们并进行测试以查看它们是否可用,则非常方便。

于 2021-12-29T00:33:30.410 回答
0

仅适用于 Windows:

import winreg
import itertools

def serial_ports() -> list:
    path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
    key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)

    ports = []
    for i in itertools.count():
        try:
            ports.append(winreg.EnumValue(key, i)[1])
        except EnvironmentError:
            break

    return ports

if __name__ == "__main__":
    ports = serial_ports()
于 2020-10-29T18:36:56.003 回答