2025 如何用 C++ 檢測 COM Ports | 完整 VSCode 開發教學


在物聯網(IoT)領域,COM Port(串行端口)仍然是許多設備之間進行數據傳輸的重要方式。儘管現代設備普遍使用 USB 等更先進的接口,但 COM 埠在嵌入式系統、工業自動化及舊式硬體中依然占有重要地位。在這篇文章中,我們將展示如何使用 C++ 來開發一個跨平台的 COM Port 列表工具,並且進一步擴展到 IoT 應用中,讓你能夠更高效地管理和監控你的設備。

COM Ports

為什麼選擇 C++ 開發?

高效能: C++ 是一種編譯型語言,能夠生成高效的機器碼,適合需要高效能和即時反應的應用程式。相比 Python 等解釋型語言,C++ 更加快速,尤其在處理大量數據、遊戲開發或嵌入式系統時,性能優勢明顯。

資源控制: C++ 允許開發者對記憶體進行精確控制,這對於需要低層次系統調優或硬體交互的應用程式(如驅動程式、嵌入式系統)非常重要。相比之下,Java 和 C# 依賴於垃圾回收,對記憶體的控制較弱。

什麼是 COM Port ?

COM Port(通信端口)是一種硬體接口,用於計算機與外部設備之間進行串行通信。它通常用於傳輸數據的過程中,並且是舊式計算機中最常見的串行端口之一。COM 埠也被稱為串行端口RS-232端口

儘管如今 USB 端口取代了 COM 埠成為更常見的設備連接方式,但 COM 埠仍然在某些領域中有廣泛的應用,特別是在 嵌入式系統工業設備舊式硬體 和某些 調試 應用中。

環境搭建

開始之前,請確保已安裝以下軟體:

在 VSCode 建立 C++ 專案

建立一個資料夾 serial_port_lister 並開啟 VSCode 再建立如下的檔案結構 ,並在資料夾中建立以下檔案結構:

serial_port_lister/
├── CMakeLists.txt   # CMake build configuration
└── main.cpp         # Code

COM 埠列表程式碼

以下是根據不同操作系統列舉 COM 埠的 C++ 程式碼:

#include <iostream>
#include <vector>
#include <string>

#ifdef _WIN32
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#pragma comment(lib, "setupapi.lib")

#elif defined(__APPLE__)
#include <dirent.h>
#include <sys/stat.h>

#else // Linux
#include <dirent.h>
#include <sys/stat.h>
#endif

std::vector<std::string> listSerialPorts() {
    std::vector<std::string> ports;

#ifdef _WIN32
    // Windows implementation
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        return ports;
    }

    SP_DEVINFO_DATA deviceInfoData;
    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &deviceInfoData); i++) {
        char buffer[256];
        DWORD bufferSize = sizeof(buffer);

        if (SetupDiGetDeviceRegistryPropertyA(
            hDevInfo, &deviceInfoData, SPDRP_FRIENDLYNAME,
            NULL, (PBYTE)buffer, bufferSize, &bufferSize)) {
            ports.push_back(buffer);
        }
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);

#elif defined(__APPLE__)
    // macOS implementation
    DIR* dir = opendir("/dev");
    if (dir) {
        struct dirent* entry;
        while ((entry = readdir(dir)) != nullptr) {
            std::string name = entry->d_name;
            if (name.find("cu.") == 0 || name.find("tty.") == 0) {
                ports.push_back("/dev/" + name);
            }
        }
        closedir(dir);
    }

#else
    // Linux implementation
    DIR* dir = opendir("/dev");
    if (dir) {
        struct dirent* entry;
        while ((entry = readdir(dir)) != nullptr) {
            std::string name = entry->d_name;
            if (name.find("ttyS") == 0 || name.find("ttyUSB") == 0 || 
                name.find("ttyACM") == 0 || name.find("ttyAMA") == 0) {
                ports.push_back("/dev/" + name);
            }
        }
        closedir(dir);
    }
#endif

    return ports;
}

int main() {
    std::cout << "Available COM Ports:" << std::endl;
    
    auto ports = listSerialPorts();
    
    if (ports.empty()) {
        std::cout << "No COM ports found." << std::endl;
    } else {
        for (const auto& port : ports) {
            std::cout << " - " << port << std::endl;
        }
    }
    
    return 0;
}

配置 CMakeLists.txt

當使用 CMake 來構建專案時,你需要提供一個 CMakeLists.txt 檔案,該檔案描述了專案如何被編譯和鏈接。

cmake_minimum_required(VERSION 3.10)
project(SerialPortLister VERSION 1.0.0)

# Basic settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Platform-specific settings
if(WIN32)
    add_definitions(-DWIN32_LEAN_AND_MEAN)
    find_library(SETUPAPI_LIB setupapi)
    message(STATUS "Found Windows setupapi.lib")
elseif(APPLE)
    message(STATUS "Configuring for macOS")
else()
    message(STATUS "Configuring for Linux")
endif()

# Main program
add_executable(${PROJECT_NAME} 
    main.cpp
)

# Link libraries
if(WIN32)
    target_link_libraries(${PROJECT_NAME} PRIVATE ${SETUPAPI_LIB})
endif()

# Installation settings (optional)
install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION bin
)

# Packaging settings (optional)
include(InstallRequiredSystemLibraries)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

編譯與執行

在 VSCode 中,按下 Ctrl (Cmd)+Shift+P,然後輸入 CMake: Build 來編譯專案。完成後,執行程式 ( 以 macOS 為例 ):

./SerialPortLister

結果 :

Available COM Ports:
 - /dev/cu.usbserial-1234
 - /dev/tty.usbserial-5678

結論

這個簡單的跨平臺應用程式展示了如何在不同操作系統上列舉串行通訊埠。通過使用條件編譯,我們可以為每個平臺提供特定的實現,同時保持統一的接口。你可以進一步擴展這個程式,例如:添加圖形用戶界面、添加埠詳細信息(如製造商、設備ID)、實現埠監控功能。