
一、系统总架构plaintextPC USB 主机 │ ▼ ┌─────────────────────┐ │ 板1 │ │ 上行USB ◄── PC │ │ 下行USB ──► 板2 │ │ 本地USB ──► 4口USB转串口芯片 CH348 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板2 │ │ 上行USB ◄── 板1 │ │ 下行USB ──► 板3 │ │ 本地USB ──► 4口USB转串口芯片 CH348 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板3 │ │ 上行USB ◄── 板2 │ │ 下行USB ──► 板4 │ │ 本地USB ──► 4口USB转串口芯片 CH348 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板4 │ │ 上行USB ◄── 板3 │ │ 下行USB ──► 空(末端)│ │ 本地USB ──► 4口USB转串口芯片 CH348 └─────────────────────┘说明共 4 块硬件板板间 USB 级联连接每块板含上行 USB、下行 USB、本地 USB 共 3 口本地 USB 接板载 CH3484 端口 USB 转串口芯片PC 仅需 1 根 USB 连接首块板整套系统共 16 路串口目标上位机识别每一路串口对应的物理板号 板内串口序号二、方案一CH348 烧录唯一序列号 SN 方案1. 结构示意图plaintextPC USB 主机 │ ▼ ┌─────────────────────┐ │ 板1 │ │ 上行USB ◄── PC │ │ 下行USB ──► 板2 │ │ 本地USB ──► CH348(SNBOARD01) └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板2 │ │ 上行USB ◄── 板1 │ │ 下行USB ──► 板3 │ │ 本地USB ──► CH348(SNBOARD02) └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板3 │ │ 上行USB ◄── 板2 │ │ 下行USB ──► 板4 │ │ 本地USB ──► CH348(SNBOARD03) └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板4 │ │ 上行USB ◄── 板3 │ │ 下行USB ──► 空(末端)│ │ 本地USB ──► CH348(SNBOARD04) └─────────────────────┘2. 逻辑关系每块板 CH348 单独烧录唯一序列号板 1-BOARD01、板 2-BOARD02、板 3-BOARD03、板 4-BOARD04烧录要求必须单块板单独接 PC 烧录不可级联烧录同一块 CH348 的 4 个串口SN 相同Interface 号不同 (0/1/2/3)映射规则Interface0→串口 1、1→串口 2、2→串口 3、3→串口 4上位机流程枚举 COM 口→读取 SNInterface→映射板号与串口3. C 核心实现代码cpp运行#include Windows.h #include SetupAPI.h #include string #include vector using namespace std; struct ComInfo { wstring comName; wstring sn; int interfaceId; int boardId; int uartId; }; vectorComInfo comList; int SnToBoardId(const wstring sn) { if (sn LBOARD01) return 1; if (sn LBOARD02) return 2; if (sn LBOARD03) return 3; if (sn LBOARD04) return 4; return 0; } void EnumAllCH348Com() { comList.clear(); HDEVINFO hDevInfo SetupDiGetClassDevs(GUID_DEVINTERFACE_COMPORT, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo INVALID_HANDLE_VALUE) return; SP_DEVICE_INTERFACE_DATA ifData { 0 }; ifData.cbSize sizeof(ifData); for (DWORD i 0; SetupDiEnumDeviceInterfaces(hDevInfo, nullptr, GUID_DEVINTERFACE_COMPORT, i, ifData); i) { DWORD reqSize 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, nullptr, 0, reqSize, nullptr); vectorBYTE detailBuf(reqSize); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail (PSP_DEVICE_INTERFACE_DETAIL_DATA)detailBuf.data(); pDetail-cbSize sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA devData { 0 }; devData.cbSize sizeof(devData); if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, pDetail, reqSize, nullptr, devData)) continue; wstring devicePath pDetail-DevicePath; int infNum -1; if (devicePath.find(L0) ! wstring::npos) infNum 0; else if (devicePath.find(L1) ! wstring::npos) infNum 1; else if (devicePath.find(L2) ! wstring::npos) infNum 2; else if (devicePath.find(L3) ! wstring::npos) infNum 3; if (infNum 0) continue; wstring sn; size_t snPos devicePath.find(LSN_); if (snPos ! wstring::npos) sn devicePath.substr(snPos 3, 8); wchar_t* pCom wcsstr(devicePath.c_str(), LCOM); if (!pCom) continue; ComInfo info; info.comName pCom; info.sn sn; info.interfaceId infNum; info.boardId SnToBoardId(sn); info.uartId infNum 1; comList.push_back(info); } SetupDiDestroyDeviceInfoList(hDevInfo); }三、方案二4bit GPIO 硬件地址方案不烧 SN、不加 MCU1. 结构示意图plaintextPC USB 主机 │ ▼ ┌─────────────────────┐ │ 板1 │ │ 上行USB ◄── PC │ │ 下行USB ──► 板2 │ │ 本地USB ──► CH348(GPIO硬件地址0001) └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板2 │ │ 上行USB ◄── 板1 │ │ 下行USB ──► 板3 │ │ 本地USB ──► CH348(GPIO硬件地址0010) └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板3 │ │ 上行USB ◄── 板2 │ │ 下行USB ──► 板4 │ │ 本地USB ──► CH348(GPIO硬件地址0011) └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ 板4 │ │ 上行USB ◄── 板3 │ │ 下行USB ──► 空(末端)│ │ 本地USB ──► CH348(GPIO硬件地址0100) └─────────────────────┘2. 逻辑关系每块板使用 4 个上下拉电阻接 CH348 的 4 个 GPIO设置 4bit 硬件地址地址定义板 1-0001、板 2-0010、板 3-0011、板 4-0100PC USB 枚举识别每一颗 CH348 设备上位机通过 CH348 官方 API 读取 GPIO 电平得到板号每颗 CH348 对应 4 个端口0/1/2/3→板内串口 1/2/3/4支持级联整体识别无需单块烧录无需额外 MCU3. C 核心实现代码cpp运行#include Windows.h #include CH348DLL.H #pragma comment(lib,CH348DLL.LIB) #include vector #include string using namespace std; struct BoardPort { int boardAddr; int uartId; wstring comName; }; vectorBoardPort boardList; int GpioToBoard(BYTE gpioData) { int addr gpioData 0x0F; if (addr 1) return 1; if (addr 2) return 2; if (addr 3) return 3; if (addr 4) return 4; return 0; } void ScanAllCH348Board() { boardList.clear(); DWORD devCount 0; CH348GetDevices(devCount); if (devCount 0) return; for (DWORD i 0; i devCount; i) { HANDLE hDev CH348Open(i); if (hDev INVALID_HANDLE_VALUE) continue; BYTE gpio 0; CH348GetGPIO(hDev, gpio); int board GpioToBoard(gpio); wchar_t comName[32]; for (int p 0; p 4; p) { CH348GetComName(hDev, p, comName); BoardPort bp; bp.boardAddr board; bp.uartId p 1; bp.comName comName; boardList.push_back(bp); } CH348Close(hDev); } }四、两套方案对比总结方案一烧录 SN 方案优点无需改动硬件 GPIO 电路缺点必须单块单独烧录 SN不可级联烧录识别方式USB 枚举→读 SNInterface 号完成映射方案二4bit GPIO 硬件地址方案优点不烧 SN、硬件统一、支持级联识别、无需额外 MCU缺点需硬件设计 4bit GPIO 上下拉电路识别方式USB 枚举 CH348→读 GPIO 地址→匹配 4 路串口