
你可以帮我写一个程序吗使用qt5.12.8,在银河麒麟下运行你有什么思路吗可以知道它是什么QSerialPortInfo 枚举推荐Qt 原生Qt5 自带QSerialPortInfo 可以列出所有串口的详细信息for (const QSerialPortInfo info : QSerialPortInfo::availablePorts()) { qDebug() info.portName(); // 如 ttyUSB0 qDebug() info.manufacturer(); // 厂商如 FTDI qDebug() info.description(); // 描述如 FT232R USB UART qDebug() info.vendorIdentifier(); // VID十六进制 qDebug() info.productIdentifier(); // PID十六进制 qDebug() info.serialNumber(); // 序列号 }只要你的设备芯片是常见型号description manufacturer 基本就能认出来。admin123admin123-pc:~/桌面$ ls /dev/ttyS* /dev/ttyS0 /dev/ttyS14 /dev/ttyS2 /dev/ttyS25 /dev/ttyS30 /dev/ttyS8 /dev/ttyS1 /dev/ttyS15 /dev/ttyS20 /dev/ttyS26 /dev/ttyS31 /dev/ttyS9 /dev/ttyS10 /dev/ttyS16 /dev/ttyS21 /dev/ttyS27 /dev/ttyS4 /dev/ttyS11 /dev/ttyS17 /dev/ttyS22 /dev/ttyS28 /dev/ttyS5 /dev/ttyS12 /dev/ttyS18 /dev/ttyS23 /dev/ttyS29 /dev/ttyS6 /dev/ttyS13 /dev/ttyS19 /dev/ttyS24 /dev/ttyS3 /dev/ttyS7你看到的这些/dev/ttyS*是 Linux 下的串口设备节点传统8250/16550兼容串口。你的系统里出现了ttyS0~ttyS31说明内核最多枚举了32 个串口。传统 8250/16550 兼容串口这是什么这是PC 串口通信硬件的两个经典芯片型号后来成了标准串口的代名词。名字的来源82501980 年代 IBM PC 上使用的第一代UART 芯片National Semiconductor 出品165501987 年推出的改进版增加了16 字节 FIFO 缓冲区是后来所有PC 串口的标准UART Universal Asynchronous Receiver/Transmitter通用异步收发器负责把并行的 CPU 数据转成串行信号发出去反之亦然。为什么叫兼容后来几十年的串口芯片无论哪家厂商生产寄存器布局、编程接口都向后兼容 8250/16550。所以Linux 驱动只要认这个接口就能驱动几乎所有传统串口。应用层 → /dev/ttyS0 ↓ Linux 8250 驱动 (serial8250) ↓ 硬件 UART 芯片16550 兼容 ↓ RS-232 电平 → DB9 接口 → 外部设备典型特征特征说明接口形式DB9 / DB25针脚或主板 9 针排针电平标准RS-232±12V或 TTL3.3V/5V地址传统固定 I/O 地址如COM10x3F8, COM20x2F8中断IRQ 4、IRQ 3 等波特率通常到 115200部分到 921600FIFO16550 有 16 字节8250 没有和你/dev/ttyS*的关系Linux 的8250驱动代码在drivers/tty/serial/8250/负责管理这些设备。它为每个可能的 I/O 地址/端口都建了一个/dev/ttyS*节点所以你看到 ttyS0~ttyS31 一大串但真正插了硬件的 →驱动能读到芯片显示16550A没插硬件的 → 显示unknown纯粹是占位节点这就是为什么你ls /dev/ttyS*看到 32 个但实际能用的可能只有 1~2 个。如何判断哪些是实际能用的.....................................待写....................................讲讲/dev/ttyUSB*/dev/ttyUSB*是USB 转串口设备在 Linux 下的设备节点。它和/dev/ttyS*最大的区别是硬件不是主板上的而是通过USB 接口热插拔接入的。为什么会有 ttyUSB*很多设备单片机、PLC、传感器、路由器、Arduino等本身只有 UART 串口但现代电脑没有物理串口了于是用一根USB 转串口线把UART 信号转换成 USB 信号接入电脑。Linux 内核里的usbserial驱动负责识别这些转换芯片并为每个转换出来的串口创建/dev/ttyUSB0、/dev/ttyUSB1……的节点。设备 UART → USB 转串口芯片 → USB 总线 → usbserial 驱动 → /dev/ttyUSB0常见的 USB 转串口芯片芯片常见设备驱动模块特点CH340 / CH341廉价Arduino、ESP开发板ch341便宜最常见CP2102 / CP2104ESP32、NodeMCUcp210x稳定Silicon LabsFT232 / FT2232工业设备、调试板ftdi_sio老牌质量好PL2303老式转接线pl2303早期常用兼容性有坑CDC ACM非 ttyUSBSTM32、Arduino原生 USBcdc_acm节点是/dev/ttyACM*注意CDC 类设备不会出现在ttyUSB*而是/dev/ttyACM*。查看有哪些 ttyUSBls /dev/ttyUSB*admin123admin123-pc:~/桌面$ ls /dev/ttyUSB* ls: 无法访问/dev/ttyUSB*: 没有那个文件或目录admin123admin123-pc:~/桌面$ ls /dev/ttyACM* ls: 无法访问/dev/ttyACM*: 没有那个文件或目录使用上面的代码我可以识别到ttyAMA0---ttyAMA3还有ttyUSB0你识别到的端口是什么端口类型说明ttyAMA0~ttyAMA3ARM SoC的 PL011 UART板载串口常见于树莓派、瑞芯微、全志等 ARM 平台。固定编号不随插拔变化ttyUSB0USB 转串口你插的外接设备通常是FTDI/CH340/CP2102等芯片。编号会变ttyAMA*是ARM 平台特有的命名。AMA来自 ARM 的AMBAAdvanced Microcontroller Bus Architecture总线PL011 是这个总线上的 UART 控制器。它们对应开发板/工控板上的物理串口排针或板载接口。打开前的检查Qt 提供了几个有用的检查方法QSerialPortInfo info /* 你选中的端口 */; // 1. 是否被占用 if (info.isBusy()) { qDebug() 端口已被其他程序占用; } // 2. 是否有效有真实硬件 if (!info.isValid()) { qDebug() 无效端口; }ttyAMA0 常被系统占用在很多ARM 开发板上ttyAMA0默认是串口控制台内核打印、登录 shell 都走它。程序直接打开会失败或干扰系统输出。# 看是否被 getty 占用 systemctl status serial-gettyttyAMA0.service # 检查内核命令行是否把 console 指向了它 cat /proc/cmdline | grep console如果确实被占用建议改用ttyAMA1/2/3或停掉 getty。我看我的设备上有两个串口相关的物理接口一个写着RS232一个写着RS422,但我Qt程序识别出来的是ttyAMA0---ttyAMA3感觉有点怪怪的你看到的“奇怪”其实是两个不同层面的东西被混淆了。你设备上物理接口写的RS232和RS422指的是电气标准物理层而 Qt 识别出的ttyAMA0~3是内核给UART 控制器分配的软件设备名。它们不是同一层面的对应关系。为什么会有“两个物理接口四个 ttyAMA”你的设备大概率是ARM 架构的开发板或工控机。ttyAMA是ARM PL011 UART 控制器的标准命名关键在于物理接口RS232/RS422和 UART 控制器ttyAMA之间通常隔着一层电平转换芯片或跳线配置。一个物理接口背后可能对应一个或多个 UARTRS232 和 RS422 都是电气标准。RS422 需要4 根信号线来实现全双工差分传输而 RS232 只需要2 根信号线。有些设备的 RS422 接口会占用两个 UART 控制器一个负责发送一个负责接收或者通过硬件跳线将某个 UART 配置为RS422 模式。你识别到的 4 个 ttyAMA只有部分真正连接到了物理接口你的设备虽然有 RS232 和 RS422 两个物理接口但板载的ARM SoC通常有多个UART 控制器如 4 个。这些ttyAMA0~3可能对应 SoC 内部的4 个 UART 外设但只有 1~2 个被引出到了物理接口上。典型的树莓派就是/dev/ttyAMA0引出到GPIO 针脚。对于工控板厂商可能会把ttyAMA1和ttyAMA2通过板载的RS422 收发器引出。“RS232”和“RS422”标签是给使用者看的接线指引设备厂商在物理接口旁印上 RS232/RS422是告诉你“这个 DB9 或端子排电气特性符合 RS232/RS422 标准请按对应方式接线”。它不会直接出现在 Linux 的设备节点命名里。内核只认 UART 控制器不关心你外面接的是MAX232 芯片还是MAX490 芯片。怎么确定哪个 ttyAMA 对应哪个物理接口最可靠的方法是查设备手册因为UART到物理接口的映射是硬件设计决定的没有通用规律。那我应该问厂商要一下设备手册或者直接问设备上的RS422对应着ttyAMA中的哪一个亦或者我该从/dev目录中访问谁才能读取到另一个设备通过RS422接口发过来的串口信息最优先直接问厂商问厂商是最快、最可靠的路径。你可以直接这样问“我设备上有RS232 和 RS422 两个物理串口接口请问它们分别对应 Linux 下的哪个/dev/ttyAMA*设备节点自己动手验证从/dev里试确认哪些 ttyAMA 是真实的# 看每个 ttyAMA 是否有效 for i in 0 1 2 3; do echo ttyAMA$i stty -F /dev/ttyAMA$i -a 21 | head -3 done能正常输出参数的就是真实可用的 UART报No such device或Invalid argument的可能未启用。stty -F /dev/ttyAMA$i -a 21 | head -3这行是核心拆成几部分部分含义sttyset tty查看/设置终端串口参数的命令-F /dev/ttyAMA$i指定要操作的设备文件$i替换后如/dev/ttyAMA0-aall显示该串口的全部当前配置21把标准错误重定向到标准输出这样错误信息也能被管道处理| head -3只显示输出的前 3 行避免刷屏今天联合调试的时候就遇到了这种问题我跟搞硬件的人中间差了一些东西让我们的沟通很艰难我眼里只有4个串口名称:ttyAMA0---ttyAMA3,他们眼里是我已经把线接到RS422口上了你能不能收到数据。有点烦。。。这种“鸡同鸭讲”的场面在软硬件联调里太常见了你烦是完全正常的。根本原因是你们各自站在不同的抽象层说话中间缺了一张“翻译表”。下面帮你把这个问题彻底理清。你们各自在说什么角色眼里的世界关心的东西你软件/dev/ttyAMA0~3打开哪个设备节点、波特率、能不能读到字节硬件同事RS422 接口、TX/TX-、A/B 线线接对了没、电平对不对、收发器工作没你们说的都对但不在同一个层面。他说“我接到 RS422 口了” → 这是物理层你说“我只有 ttyAMA0~3” → 这是软件设备层中间缺的是RS422 物理接口 ↔ 哪个 ttyAMA的映射关系为什么沟通这么难因为这个映射关系是硬件设计决定的软件无法自动知道。硬件同事知道他把线接到了 RS422 端子你知道系统里有 4 个 ttyAMA你们都不知道或没对齐RS422 端子背后连的是ttyAMA 这个信息只存在于硬件原理图或厂商手册里软件侧dmesg、/sys、lsusb都查不出来因为电平转换芯片对软件是透明的。可以尝试的方法现场最快的方法你写一个最简单的测试程序逐个 ttyAMA 监听让硬件同事从 RS422 发数据。用 Qt 写个最小 demofor (const QString name : {ttyAMA0, ttyAMA1, ttyAMA2, ttyAMA3}) { QSerialPort port; port.setPortName(name); port.setBaudRate(QSerialPort::Baud115200); if (port.open(QIODevice::ReadOnly)) { qDebug() name 打开成功等待数据...; // 连 readyRead 信号收到数据就打印 } }四个都打开哪个收到数据哪个就是 RS422。但要注意ttyAMA0很可能被内核控制台占用打开会失败或读到内核日志先从ttyAMA1~3试。