串口 HOWTO

David S.Lawyer dave@lafn.org Greg Hankins 原创

v2.27 2011 年 2 月
本文档适用于 UART 串口。这种端口在台式机和笔记本电脑上已基本消失,但在其他地方(例如嵌入式系统)仍然使用。本文档涵盖的信息不应包含在 Modem-HOWTO、PPP-HOWTO、Serial-Programming-HOWTO 或 Text-Terminal-HOWTO 中。它列出了关于多串口卡的信息。它包含比上述 HOWTO 更详细的关于串口本身的技术信息,最适合用于排除串口本身的问题。如果您正在处理调制解调器、PPP(用于电话线上的 Internet 访问)或文本终端,应首先查阅这些 HOWTO。

1. 简介

2. 快速帮助

3. 硬件如何传输字节

4. 串口基础知识

5. 多串口板/卡/适配器

6. 串口服务器

7. 配置概述

8. 定位串口:IO 地址、IRQ

9. 配置串口驱动程序(高级)"stty"

10. 串口设备 /dev/ttyS2 等

11. 您应该了解的有趣程序

12. 速度(流速)

13. 阻止他人访问

14. 串口通信程序和实用工具

15. 串口技巧和杂项

16. 故障排除

17. 中断问题详情

18. 什么是 UART?它们如何影响性能?

19. 引脚排列和信号

20. 电压波形

21. 其他串口设备(非异步 RS-232)

22. 其他信息来源

23. 附录 A:非常过时的硬件/软件


1. 简介

本 HOWTO 涵盖了关于串口的基本信息,这种串口在新式个人电脑上已不常见,但在最新的嵌入式系统以及路由器、销售点设备等中仍在使用。它包括多串口卡。本文档是在串口还是连接 PC 与调制解调器和打印机等的主要端口时编写的,本文的风格也反映了这一点。如果您在串口方面遇到问题,想要了解其工作原理,或者在学习串口编程之前需要对其进行详细的介绍,那么这里是您可以找到相关信息的地方之一。

本 HOWTO 介绍的是最初的串口,它使用 UART 芯片,有时也称为 “UART 串口”,以区别于较新型的串行设备:通用串行总线或火线。与较新型的串行设备相比,它速度较慢,但发送文本的速度仍然比您阅读的速度快几倍。关于使用串口的设备的特定信息:模拟调制解调器、文本终端、红外设备和一些打印机,可以在 Modem-HOWTO、Text-Terminal-HOWTO、Infrared-HOWTO 和 Printing-HOWTO 中找到。关于 getty(运行登录过程或类似程序的程序)的信息也已移至其他相关的 HOWTO,因为 mgetty 和 uugetty 最适合调制解调器,而 agetty 最适合文本终端。如果您正在处理调制解调器、文本终端、红外设备或打印机,则可能不需要查阅本 HOWTO。但是,如果您将串口用于其他设备、使用多串口卡、排除串口本身的故障,或者想了解更多关于串口的技术细节,那么您可能需要使用本 HOWTO 以及其他一些 HOWTO。(请参阅相关 HOWTO)本 HOWTO 列出了关于各种多串口卡的信息。本 HOWTO 讨论的是在 PC(ISA 和/或 PCI 总线)上运行的 Linux,尽管它可能也适用于其他架构。

1.1 版权、免责声明和鸣谢

版权

版权所有 (c) 1993-1997 Greg Hankins,(c) 1998-2005 David S. Lawyer mailto:dave@lafn.org

请随意复制和分发(出售或赠送)本文档的任何格式。请将任何更正和意见发送给文档维护者。您可以创建衍生作品并分发,前提是您

  1. 如果不是翻译作品:通过电子邮件将您的衍生作品副本(LDP 接受的格式)发送给作者和维护者(可能是同一个人)。如果您没有收到回复,请通过电子邮件发送给 LDP(Linux 文档项目):submit@en.tldp.org。
  2. 以本许可证的精神许可衍生作品,或使用 GPL。包含版权声明,并至少指向所用许可证的链接。
  3. 对之前的作者和主要贡献者给予应有的感谢。

如果您正在考虑创建翻译以外的衍生作品,我们请求您与当前的维护者讨论您的计划。

免责声明

虽然我没有故意误导您,但本文档中可能存在许多错误。请告知我这些错误。由于这是免费文档,因此应该很明显,我对任何错误不承担任何法律责任。

商标。

任何品牌名称(以大写字母开头,例如 MS Windows)都应假定为商标)。此类商标属于其各自的所有者。

鸣谢

最初的 Serial-HOWTO 大部分由 Greg Hankins 编写。mailto:gregh@twoguys.org 他还重写了许多其他人的贡献,以保持写作风格和流程的连贯性。他写道:“感谢所有做出贡献或评论的人,人员名单已经太长,无法一一列出(超过一百人)。特别感谢 Ted Ts'o 回答关于串口驱动程序的问题。” 大约一半的 v2.00 来自 Greg Hankins HOWTO,另一半是 David Lawyer 的补充。Ted Ts'o 一直乐于助人。2006 年 1 月,“Charles Brockman” 检查了其中的错别字,并修复了许多错别字。

1.2 本 Serial-HOWTO 的新版本

新版本可能会每隔一两年发布一次。它们将在 LDP 镜像站点上提供浏览和/或下载,请参阅:http://www.tldp.org/mirrors.html。提供各种格式。如果您只想快速查看最新版本的日期,请查看http://www.tldp.org/HOWTO/Serial-HOWTO.html 并将其与此版本进行比较:v2.27 2011 年 2 月。

1.3 近期版本更新

要查看追溯到我开始维护本 HOWTO 时的完整修订历史,请参阅源文件(linuxdoc 格式):(cvs) Serial-HOWTO.sgml

1.4 关于串口的相关 HOWTO 等

调制解调器、文本终端、一些打印机和其他外围设备经常使用串口。从最近的镜像站点获取这些 HOWTO,如上所述。

1.5 反馈

请向我发送任何建议、更正或补充材料。告诉我您不理解的内容,或者哪些地方可以更清楚。您可以通过电子邮件与我联系,邮箱地址为 mailto:dave@lafn.org

1.6 什么是串口?

传统的串口(不是较新的 USB 端口或火线端口)是一种非常古老的 I/O(输入/输出)端口。直到 2006 年左右,大多数新型台式 PC 都配备了一个串口,而 1990 年代的旧 PC 有时配备了两个串口。大多数笔记本电脑在台式电脑之前就放弃了串口。1998 年中期之后的 Mac(苹果电脑)只有 USB 端口。但是,可以将传统的串口设备放在所有现代 PC 上的 USB 总线上。

每个串口在 /dev 目录中都有一个与之关联的 “文件”。它实际上不是文件,但看起来像文件。例如,/dev/ttyS0。其他串口是 /dev/ttyS1、/dev/ttyS2 等。但是 USB 总线、多串口卡等上的端口具有不同的名称。

传统串口的通用规范是 RS-232(或 RS-232)。因此,它通常被称为 “RS-232 串口”。串口的连接器通常在 PC 背面看到一个或两个 9 针连接器(在某些情况下为 25 针)。但串口不仅仅是连接器。它还包括相关的电子设备,这些电子设备必须产生符合 RS-232 规范的信号。请参阅 电压波形。一个引脚用于发送数据字节,另一个引脚用于接收数据字节。另一个引脚是公共信号地。其他 “有用” 的引脚主要用于信号目的,稳定的负电压表示 “关”,稳定的正电压表示 “开”。

UART(通用异步接收器-发送器)芯片完成大部分工作。如今,该芯片的功能通常内置于另一个芯片中。请参阅 什么是 UART? 这些芯片随着时间的推移而得到改进,旧型号(例如 1994 年之前)通常非常过时。

串口最初设计用于将外部调制解调器连接到 PC,但它也用于连接许多其他设备,例如鼠标、文本终端、一些打印机等。您只需使用正确的电缆将这些设备插入串口即可。许多内置调制解调器卡都内置了串口,因此当您在 PC 内部安装一个调制解调器卡时,就好像您在 PC 中安装了另一个串口一样。


2. 快速帮助

这里重复了在其他地方可以找到的更详细的信息。如果您的计算机似乎找不到您的串口,并且您已经了解一些关于硬件资源(如 3F8 地址和 5 IRQ)的知识,请尝试以下操作:首先,在计算机开机时进入 BIOS(通常称为 “setup”),方法是按某些键。要了解要按哪些键,请在 PC 启动时观看屏幕。如果屏幕上闪烁的文字太快而无法阅读,请同时按住 “pause” 和 “shift” 键来冻结屏幕。阅读完后,按任意键恢复(停止暂停),并按住进入 BIOS 设置所需的键。您可能需要再次尝试,因为可能有多个屏幕可以使用 “pause” 键冻结。此外,请在这些冻结的屏幕上查找关于串口的消息。

进入 BIOS 菜单后,尝试查找处理串口的菜单。它们可能显示在处理资源、即插即用、外围设备、端口等的菜单中。一些旧的 BIOS 设置(1995 年之前?)不处理串口。确保您需要的端口未被禁用,并注意它们的配置方式(如 3F8 IRQ 4)。您可能需要更改配置以防止冲突。如果 BIOS 保留了一些不需要保留的 IRQ,则可能存在 IRQ 短缺的情况。

为了找到串口,内核必须已编译了串口支持,或者串口支持必须由模块提供。要检查这一点,请查看文件 /boot/config-2.6... 并搜索 SERIAL。=m 表示它是一个模块,您可以检查正在使用的模块,方法是键入:lsmod。


3. 硬件如何传输字节

下面是关于该主题的介绍,但要了解更高级的处理方法,请参阅 FIFO

3.1 发送

发送是将字节从串口发送出去,远离计算机(输出)。一旦您理解了发送,接收(输入)就很容易理解了,因为它与发送类似。这里给出的第一个解释将过于简化。然后在后面的解释中将添加更多细节。当计算机想要通过串口(到外部电缆)发送一个字节时,CPU 会将该字节通过计算机内部的总线发送到串口的 I/O(输入输出)地址。I/O 通常简写为 IO。串口接收字节,并将其一次一位(串行位流)地发送到串口电缆连接器的发送引脚上。有关位的电气外观(和字节)的信息,请参阅 电压波形

以下是对上述内容的更详细的重述(但仍然非常不完整)。串口的大部分工作由 UART 芯片(或类似芯片)完成。要发送一个字节,串口设备驱动程序(在 CPU 上运行)会将一个字节发送到串口的 I/O 地址。该字节进入串口中的 1 字节 “发送移位寄存器”。从该移位寄存器中,字节中的位被逐位取出,并在串行线上逐位发送出去。然后,当最后一个位被发送,并且移位寄存器需要另一个字节来发送时,它可以直接要求 CPU 向其发送另一个字节。这样很简单,但可能会引入延迟,因为 CPU 可能无法立即获取字节。毕竟,CPU 通常除了处理串口之外还要做其他事情。

消除此类延迟的一种方法是进行安排,使 CPU 在移位寄存器需要字节之前获取字节,并将其存储在串口缓冲区(在硬件中)。然后,当移位寄存器发送完其字节并立即需要新字节时,串口硬件只需将其自身缓冲区中的下一个字节传输到移位寄存器。无需调用 CPU 来获取新字节。

此串口缓冲区的大小最初只有一个字节,但今天通常为 16 字节(在价格更高的串口中更多)。现在仍然存在一个问题,即如何使此缓冲区充分供应字节,以便当移位寄存器需要字节来发送时,它始终可以在那里找到一个字节(除非没有更多字节要发送)。这是通过使用中断联系 CPU 来完成的。

首先,我们将解释旧式单字节缓冲区的情况,因为 16 字节缓冲区的工作方式类似(但更复杂)。当移位寄存器从缓冲区中抓取字节并且缓冲区需要另一个字节时,它会通过在计算机总线上的专用导线上施加电压来向 CPU 发送中断。除非 CPU 正在执行非常重要的操作,否则中断会强制它停止正在执行的操作,并开始运行一个程序,该程序将向端口的缓冲区提供另一个字节。此缓冲区的目的是在硬件中保存一个额外的字节(等待发送),以便在外发串口电缆的字节传输中不会出现间隙。

一旦 CPU 收到中断,它将知道是谁发送了中断,因为每个串口都有一根专用的中断线(除非中断是共享的)。然后,CPU 将开始运行串口设备驱动程序,该驱动程序检查 I/0 地址处的寄存器,以找出发生了什么。它发现串口的发送缓冲区为空,正在等待另一个字节。因此,如果有更多字节要发送,它会将下一个字节发送到串口的 I/0 地址。下一个字节应该在前一个字节仍在发送移位寄存器中并且仍在逐位发送时到达。

回顾一下,当一个字节已完全通过串口的发送线发送出去,并且移位寄存器现在为空时,以下 3 件事会快速连续发生

  1. 下一个字节从发送缓冲区移动到发送移位寄存器
  2. 开始传输这个新字节(逐位)
  3. 再次发出中断,告诉设备驱动程序向现在为空的发送缓冲区发送另一个字节

因此,我们说串口是中断驱动的。每次串口发出中断时,CPU 都会向其发送另一个字节。一旦 CPU 将一个字节发送到发送缓冲区,CPU 就可以自由地进行其他活动,直到它收到下一个中断。串口以用户(或应用程序)选择的固定速率传输比特。这有时被称为波特率。串口还向每个字节添加额外的比特(起始位、停止位,可能还有奇偶校验位),因此通常每个字节发送 10 个比特。在 19,200 比特每秒 (bps) 的速率(也称为速度)下,因此有 1,920 字节/秒(以及 1,920 个中断/秒)。

对于 CPU 来说,完成所有这些工作量很大。这在很多方面都是如此。首先,一次通过 32 位数据总线(甚至 64 位)仅发送一个 8 位字节并不是非常有效地利用总线宽度。此外,处理每个中断也有很多开销。当接收到中断时,设备驱动程序只知道串口上的某些东西引起了中断,但不知道是因为发送了一个字符。设备驱动程序必须进行各种检查以找出发生了什么。同一个中断可能意味着收到了一个字符,某个控制线改变了状态等等。

一个重大的改进是将串口的缓冲区大小从 1 字节扩大到 16 字节。这意味着当 CPU 收到中断时,它会给串口最多 16 个新字节进行传输。这减少了需要处理的中断次数,但数据仍然必须一次一个字节地通过宽总线传输。16 字节缓冲区实际上是一个 FIFO(先进先出)队列,通常称为 FIFO。有关 FIFO 的详细信息以及上述某些信息的重复,请参阅 FIFO(先进先出)

3.2 接收

串口接收字节类似于发送字节,只是方向相反。它也是中断驱动的。对于具有 1 字节缓冲区的过时类型的串口,当从外部电缆完全接收到一个字节时,它会进入 1 字节的接收缓冲区。然后,端口给 CPU 一个中断,告诉它拾取该字节,以便串口有空间存储当前正在接收的下一个字节。对于具有 16 字节缓冲区的新型串口,此中断(用于获取字节)可能会在接收缓冲区中有 14 个字节后发送。然后,CPU 停止正在做的事情,运行中断服务例程,并从端口拾取 14 到 16 个字节。对于在接收到第 14 个字节时发送的中断,如果自中断以来又到达了 2 个字节,则可能需要获取 16 个字节。但是,如果应该到达 3 个字节(而不是 2 个),则 16 字节缓冲区将溢出。它也可能通过以这种方式设置或由于超时而拾取少于 14 个字节。有关更多详细信息,请参阅 FIFO(先进先出)

3.3 大型串口缓冲区

我们已经讨论了小型 16 字节串口硬件缓冲区,但在主内存中也有更大的缓冲区。当 CPU 从硬件的接收缓冲区中取出一些字节时,它会将它们放入主内存中更大的(例如 8k 字节)接收缓冲区中。然后,一个从串口获取字节的程序会从该大型缓冲区中取出它正在接收的字节(在程序中使用“read”语句)。

对于要传输的字节,情况也类似。当 CPU 需要获取一些要传输的字节时,它会从主内存中的大型(8k 字节)发送缓冲区中取出它们,并将它们放入硬件中的小型 16 字节发送缓冲区中。当程序想要通过串口发送字节时,它会将它们写入这个大型发送缓冲区。

这两个缓冲区都由串口驱动程序管理。但是驱动程序不仅仅处理这些缓冲区。它还对通过这些缓冲区的数据进行有限的过滤(少量修改),并侦听某些控制字符。所有这些都可以使用 Stty 程序进行配置。


4. 串口基础知识

您不必了解基础知识即可使用串口,但了解它可能有助于确定在遇到问题时哪里出了问题。本节不仅介绍了新主题,还更详细地重复了前一节 硬件如何传输字节 中所说的一些内容。

4.1 什么是串口?

串口简介

UART 串口(或简称“串口”)是一种 I/O(输入/输出)设备。

I/O 设备只是将数据输入和输出计算机的一种方式。有许多类型的 I/O 设备,例如较旧的串口和并口、网卡、通用串行总线 (USB) 和火线等。2007 年之前的大多数 PC 都有一到两个串口(在较旧的 PC 上)。每个串口在计算机背面都有一个 9 针连接器(有时是 25 针)。计算机程序可以将数据(字节)发送到发送引脚(输出),并从接收引脚(输入)接收字节。其他引脚用于控制目的和接地。

串口不仅仅是一个连接器。它将数据从并行转换为串行,并更改数据的电气表示。在计算机内部,数据位并行流动(同时使用多根导线)。串行流是单根导线上的比特流(例如在串口连接器的发送或接收引脚上)。为了使串口创建这样的流,它必须将数据从并行(在计算机内部)转换为发送引脚上的串行(反之亦然)。

串口的大部分电子设备都可以在一个称为 UART 的计算机芯片(或芯片的一部分)中找到。有关 UART 的更多详细信息,请参阅 什么是 UART? 部分。但您可能想先完成本节,以便您希望了解 UART 如何融入事物的整体方案中。

引脚和导线

旧 PC 使用 25 针连接器,但实际上只使用了大约 9 个引脚,因此后来大多数连接器只有 9 针。9 个引脚中的每个引脚通常连接到一根导线。除了用于传输和接收数据的两根导线外,另一个引脚(导线)是信号地。任何导线上的电压都是相对于这个地测量的。因此,用于双向数据传输的导线的最少数量是 3 根。除非已知在没有信号地线的情况下也能工作,但性能会降低,有时会出现错误。

还有更多的导线仅用于控制目的(信号),而不用于发送字节。所有这些信号都可以共享在一根导线上,但实际上,每种类型的信号都有一根单独的专用导线。其中一些(或全部)控制导线称为“调制解调器控制线”。调制解调器控制线要么处于 +5 伏特的 asserted(激活)状态,要么处于 -5 伏特的 negated(关闭)状态。其中一根导线用于向计算机发出信号,使其停止通过串口电缆发送字节。相反,另一根导线向连接到串口的设备发出信号,使其停止向计算机发送字节。如果连接的设备是调制解调器,则其他导线可能会告诉调制解调器挂断电话线,或者告诉计算机已建立连接或电话线正在响铃(有人试图呼入)。有关更多详细信息,请参阅 引脚排列和信号 部分。

RS-232 (EIA-232 等)

串口(不是 USB)通常是 RS-232-C、EIA-232-D 或 EIA-232-E。这三者几乎是同一回事。最初的 RS(推荐标准)前缀正式成为 EIA(电子工业协会),后来在 EIA 与 TIA(电信工业协会)合并后成为 EIA/TIA。EIA-232 规范还提供了同步(sync)通信,但支持同步的硬件几乎总是 PC 上缺少的。RS 命名旨在变得过时,但仍然被广泛使用,并且将在本教程中用于 RS-232。其他文档可能会使用完整的 EIA/TIA 命名,或者仅使用 EIA 或 TIA。有关其他(非 RS-232)串口的信息,请参阅 其他串行设备(非异步 RS-232) 部分

4.2 I/O 地址 & IRQ

由于计算机需要与每个串口通信,因此操作系统必须知道每个串口的存在及其位置(其 I/O 地址)。它还需要知道串口必须使用哪根导线(IRQ 编号)来请求计算机 CPU 的服务。它通过在这根导线上发送中断电压来请求服务。因此,每个串口设备都必须在其非易失性存储器中存储其 I/O 地址和中断请求编号:IRQ。请参阅 中断。PCI 总线有自己的中断系统。但由于支持 PCI 的 BIOS 将这些 PCI 中断设置为映射到 IRQ,因此它看起来就像上面描述的那样工作。不同之处在于允许共享 PCI 中断(两个或多个设备可以使用相同的 IRQ 编号)。

I/O 地址与内存地址不同。当 I/O 地址被放到计算机的地址总线上时,另一根导线会被激活。这既告诉主内存忽略该地址,又告诉所有具有 I/O 地址的设备(例如串口)监听总线上发送的地址,以查看它是否与设备的地址匹配。如果地址匹配,则 I/O 设备读取数据总线上的数据。

某个设备(例如 ttyS2)的 I/O 地址实际上是一系列地址。此范围中的较低地址是基地址。“地址”通常仅指“基地址”。

4.3 名称:ttyS0、ttyS1 等

串口被命名为 ttyS0、ttyS1 等(通常分别对应于 DOS/Windows 中的 COM1、COM2 等)。/dev 目录为每个端口都有一个特殊文件。键入“ls /dev/ttyS*”即可查看它们。仅仅因为可能存在(例如)ttyS3 文件,并不一定意味着那里存在物理串口。

这些名称(ttyS0、ttyS1 等)中的哪一个指的是哪个物理串口,其确定方式如下。串口驱动程序(软件)维护一个表,显示哪个 I/O 地址对应于哪个 ttyS。名称(例如 ttyS1)到 I/O 地址(和 IRQ)的这种映射可以通过“setserial”命令设置和查看。请参阅 什么是 Setserial。这 `不` 会设置硬件本身中的 I/O 地址和 IRQ(硬件中的 I/O 地址和 IRQ 由跳线或即插即用软件设置)。因此,哪个物理端口对应于 ttyS1 取决于串口驱动程序的想法(通过 setserial)以及硬件中设置的内容。如果出现错误,物理端口可能不对应于任何名称(例如 ttyS2),因此无法使用它。有关更多详细信息,请参阅 串口设备 /dev/ttyS2 等

4.4 中断

当串口接收到一定数量的字节(可以设置为 1、4、8 或 14)到其 FIFO 缓冲区中时,它会通过在通常仅由该端口使用的特定导线上发送称为中断的电信号来通知 CPU 获取它们。因此,FIFO 等待直到它接收到一定数量的字节,然后发出中断。

但是,如果在等待下一个字节到达时出现意外延迟(称为超时),也会发送此中断。因此,如果字节接收速度很慢(例如来自某人在终端键盘上键入),则可能为每个接收到的字节发出一个中断。对于某些 UART 芯片,规则是这样的:如果在一段时间间隔内可能接收到连续 4 个字节,但这些 4 个字节都没有出现,则端口放弃等待更多字节,并发出中断以获取当前 FIFO 中的字节。当然,如果 FIFO 为空,则不会发出中断。

每个中断导体(在计算机内部)都有一个编号 (IRQ),串口必须知道使用哪个导体来发出信号。例如,ttyS0 通常使用 IRQ 编号 4,称为 IRQ4(或 IRQ 4)。有关它们的列表以及更多信息,请在 “man setserial” 中找到(搜索 “Configuring Serial Ports”)。每当串口需要引起 CPU 的注意时,就会发出中断。及时执行此操作非常重要,因为串口内部的缓冲区只能容纳 16 个传入字节。如果 CPU 未能及时删除此类接收到的字节,则将没有空间容纳更多传入字节,并且小缓冲区可能会溢出(超限),从而导致数据字节丢失。

没有 流量控制 来防止这种情况发生。

当串口刚刚从其小型发送 FIFO 缓冲区中通过外部电缆发送出所有字节时,也会发出中断。然后它有空间容纳 16 个更多的传出字节。中断是为了通知 CPU 这一事实,以便 CPU 可以将更多字节放入小型发送缓冲区中进行传输。此外,当调制解调器控制线改变状态时,也会发出中断。

上面提到的缓冲区都是硬件缓冲区。串口在主内存中也有大型缓冲区。这将在后面解释

中断传递大量信息,但只是间接地传递。中断本身只是告诉一个称为中断控制器的芯片,某个串口需要注意。然后,中断控制器向 CPU 发出信号。然后,CPU 运行一个特殊程序来为串口服务。该程序称为中断服务例程(串口驱动程序软件的一部分)。它尝试找出串口上发生了什么,然后处理问题,例如从串口的硬件缓冲区传输字节(或传输到硬件缓冲区)。该程序可以轻松找出发生了什么,因为串口在串口驱动程序软件已知的 IO 地址处具有寄存器。这些寄存器包含有关串口的状态信息。软件读取这些寄存器,并通过检查内容,找出发生了什么并采取适当的措施。

4.5 数据流(速度)

数据(表示字母、图片等的字节)流入和流出您的串口。流速(例如 56k (56000) 比特/秒)被(不正确地)称为“速度”。但几乎每个人都说“速度”而不是“流速”。

重要的是要理解,平均速度通常低于指定速度。等待(或空闲时间)会导致平均速度降低。这些等待可能包括由于 流量控制 导致的可能长达一秒的漫长等待。在另一个极端,字节之间可能存在几微秒的非常短的等待(空闲时间)。如果串口上的设备(例如调制解调器)无法接受完整的串口速度,则必须降低平均速度。

4.6 流量控制

流量控制是指减慢导线中字节流的能力。对于串口,这意味着在不丢失任何字节的情况下停止然后重新启动流的能力。调制解调器和其他硬件需要流量控制,以允许瞬时流速的跳跃。

流量控制示例

例如,考虑您通过短电缆将 33.6k 外部调制解调器连接到串口的情况。调制解调器通过电话线以 33.6k 比特每秒 (bps) 的速度发送和接收字节。假设它没有进行任何数据压缩或纠错。您已将串口速度设置为 115,200 比特/秒 (bps),并且您正在从计算机向电话线发送数据。那么,从您的计算机到调制解调器通过短电缆的流量为 115.2k bps。但是,从您的调制解调器到电话线的流量仅为 33.6k bps。由于进入您的调制解调器的流量 (115.2k) 比从调制解调器流出的流量快,因此调制解调器会将多余的流量 (115.2k - 33.6k = 81.6k bps) 存储在其缓冲区之一中。除非停止 115.2k 的高流量,否则此缓冲区很快就会溢出(耗尽可用存储空间)。

但现在流量控制来解救了。当调制解调器的缓冲区几乎满时,调制解调器会向串口发送停止信号。串口将停止信号传递给设备驱动程序,并且 115.2k bps 的流量停止。然后,调制解调器继续以 33.6k bps 的速度发送数据,利用先前累积在其缓冲区中的数据。由于没有任何数据进入此缓冲区,因此其中的字节数开始下降。当缓冲区中几乎没有字节剩余时,调制解调器会向串口发送启动信号,并且从计算机到调制解调器的 115.2k 流量恢复。实际上,流量控制在短电缆中创建了一个平均流速(在本例中为 33.6k),该流速明显低于 115.2k bps 的“开启”流速。这就是“启动-停止”流量控制。

在上面的简单示例中,假设调制解调器没有进行数据压缩。当调制解调器发送一个已经压缩并且无法进一步压缩的文件时,可能会发生这种情况。现在让我们考虑相反的极端情况,即调制解调器以高压缩比压缩数据。在这种情况下,调制解调器可能需要 115.2k bps 的输入流速才能提供 33.6k bps(压缩数据)的输出(到电话线)。此压缩比为 3.43 (115.2/33.6)。在这种情况下,调制解调器能够压缩 115.2 bps 的 PC 到调制解调器的流量,并以 33.6bps 的速度通过电话线发送相同的数据(以压缩形式)。只要压缩比保持高于 3.43,就不需要流量控制。但是压缩比每秒都在变化,如果它应该降到 3.43 以下,则将需要流量控制

在上面的示例中,调制解调器是外部调制解调器。但截至 2003 年初,大多数内部调制解调器也存在相同的情况。PC 到调制解调器速度仍然存在速度限制,即使此流量不是通过外部电缆进行的。这使得内部调制解调器与外部调制解调器兼容。

在上面的流量控制示例中,流量是从计算机到调制解调器。但也有用于相反方向流量的流量控制:从调制解调器(或其他设备)到计算机。每个流量方向都涉及 3 个缓冲区:1. 在调制解调器中 2. 在 UART 芯片中(称为 FIFO)和 3. 在由串口驱动程序管理的主内存中。流量控制保护所有缓冲区(FIFO 除外)免于溢出。

在 Linux 下,小型 UART FIFO 缓冲区不受流量控制保护,而是依赖于对其发出的中断的快速响应。某些 UART 芯片可以设置为进行硬件流量控制以保护其 FIFO,但 Linux(截至 2003 年初)似乎不支持它。FIFO 代表“先进先出”,这是它处理队列中字节的方式。所有 3 个缓冲区都使用 FIFO 规则,但只有 UART 中的缓冲区被命名为 “FIFO”。这是流量控制的本质,但还有一些更多细节。

没有流量控制的症状

理解流量控制理论可能具有实际用途。没有流量控制的症状是,在没有流量控制的情况下发送的文件中缺少数据块。当发生溢出时,通常会丢失数百甚至数千个字节,并且全部在连续的块中丢失。

硬件与软件流量控制

如果可行,最好使用“硬件”流量控制,该控制使用两条专用的“调制解调器控制”导线来发送“停止”和“启动”信号。串口上的硬件流量控制的工作方式如下:使用 RTS(请求发送)和 CTS(允许发送)这两个引脚。当计算机准备好接收数据时,它通过在 RTS 引脚上施加正电压来断言 RTS(表示“请求发送给我”)。当计算机无法接收更多字节时,它通过在引脚上施加负电压来否定 RTS,表示:“停止发送给我”。RTS 引脚通过串口电缆连接到调制解调器、打印机、终端等上的另一个引脚。此另一个引脚的唯一功能是接收此信号。

对于调制解调器的情况,此“另一个”引脚将是调制解调器的 RTS 引脚。但对于打印机、另一台 PC 或非调制解调器设备,它通常是 CTS 引脚,因此需要“交叉”或“零调制解调器”电缆。此电缆将一端的 CTS 引脚与另一端的 RTS 引脚连接(两条导线,因为电缆的每一端都有一个 CTS 引脚)。对于调制解调器,使用直通电缆。

对于相反的流量方向,也使用了类似的方案。对于调制解调器,CTS 引脚用于向 PC 上的 CTS 引脚发送流量控制信号。对于非调制解调器,RTS 引脚发送信号。因此,调制解调器和非调制解调器互换了其 RTS 和 CTS 引脚的角色。一些非调制解调器(如哑终端)可能会使用其他引脚进行流量控制,例如 DTR 引脚而不是 RTS。

软件流量控制使用主接收和发送数据导线来发送启动和停止信号。它为此目的使用 ASCII 控制字符 DC1(启动)和 DC3(停止)。它们只是插入到常规数据流中。软件流量控制不仅反应较慢,而且不允许发送二进制数据,除非采取特殊预防措施。由于二进制数据很可能包含 DC1 和 DC3 字符,因此必须采取特殊方法来区分表示流量控制停止的 DC3 和作为二进制代码一部分的 DC3。DC1 也是如此。

4.7 数据流路径;缓冲区

已经提到,每个流量方向都有 3 个缓冲区(总共 3 对):16 字节 FIFO 缓冲区(在 UART 中)、一对连接到串口的设备(例如调制解调器)内更大的缓冲区,以及一对主内存中的缓冲区(例如 8k)。当应用程序向串口发送字节时,它们首先被存储在主内存中的发送串口缓冲区中。此对的另一个成员包括用于字节流相反方向的接收缓冲区。以下是使用浏览器浏览 Internet 的情况的示例图。发送数据流从左到右,而接收流从右到左。每个流量方向都有一个单独的缓冲区。

application     8k-byte         16-byte        1k-byte        tele-     
BROWSER ------- MEMORY -------- FIFO --------- MODEM -------- phone
program         buffer          buffer         buffer         line

对于发送情况,串口设备驱动程序一次从这个发送缓冲区(在主内存中)取出例如 15 个字节,并将它们放入串口 UART 中的 16 字节发送缓冲区中进行传输。一旦进入该发送缓冲区,就无法阻止它们被传输。然后,它们被传输到调制解调器或(连接到串口的其他设备),调制解调器或(连接到串口的其他设备)也有一个相当大的(例如 1k)缓冲区。当设备驱动程序(根据从调制解调器发送的流量控制命令)停止从计算机流出的字节流时,它实际停止的是从主内存中的大型发送缓冲区流出的字节流。即使发生这种情况并且到调制解调器的流量已停止,应用程序也可能会继续向 8k 发送缓冲区发送字节,直到它变满。与此同时,存储在 FIFO 中的字节继续被发送出去。除非调制解调器从电话线另一端的调制解调器获得调制解调器到调制解调器的流量控制停止,否则存储在调制解调器中的字节将继续通过电话线发送出去。

当内存缓冲区变满时,应用程序无法向其发送更多字节(C 程序中的 “write” 语句会阻塞),并且应用程序暂时停止运行并等待直到某些缓冲区空间可用。因此,流量控制“停止”最终能够停止发送字节的程序。即使该程序停止,计算机也不一定会停止计算,因为它可能会在等待流量控制停止时切换到运行其他进程。

以上内容在三个方面被稍微简化了。首先,某些 UART 可以进行自动硬件流量控制,如果需要,可以停止从 FIFO 缓冲区传输(Linux 尚不支持)。其次,当应用程序进程正在等待写入发送缓冲区时,它可能会执行其他任务。第三,串口驱动程序(位于内存缓冲区和 FIFO 之间)有其自己的小型缓冲区(在主内存中),用于处理字符。

4.8 复杂的流量控制示例

在许多情况下,存在一个涉及多个链路的发送路径,每个链路都有自己的流量控制。例如,我在连接到 PC 的文本终端上键入内容,并且 PC(在我的控制下)使用调制解调器拨号到另一台计算机。如今,“文本终端”很可能只是另一台模拟文本终端的 PC。主(服务器)PC 除了为我的文本终端提供服务外,还可能有人坐在那里做其他事情。请注意,将此 PC 称为“服务器”在技术上是不正确的,但它确实为终端提供服务。

文本终端使用没有图形显示器的命令行界面。我在文本终端上键入的每个字母都通过串口电缆传输到我的主 PC,然后通过电话线传输到我拨号连接的计算机。为了拨号连接,我使用了通信软件:“minicom”,它在我的 PC 上运行。

这听起来像一个简单的数据路径。我按下一个键,该键生成的字节仅通过两条电缆(键盘电缆除外)流动:1. 从我的文本终端到我的 PC 的电缆,以及 2. 到另一台计算机的电话线电缆。当然,电话电缆实际上是许多电话系统电缆,包括交换机和电子设备,因此单根物理电缆可以传输多个电话呼叫。但我可以将其视为一根电缆(或一个链路)。

现在,让我们计算一下每个击键字节必须通过的电子设备的数量和类型。终端到 PC 电缆的两端都有一个串口。电话电缆的两端都有一个串口和一个调制解调器。这加起来是 4 个串口和 2 个调制解调器。由于每个串口有 2 个缓冲区,每个调制解调器有 1 个缓冲区,因此加起来是 10 个缓冲区。这只是一个流量方向。每个字节还必须通过 minicom 软件。

虽然在上述场景中只有 2 根电缆,但如果使用外部调制解调器,则每个调制解调器及其串口之间将有一根额外的电缆。这总共是 4 根电缆。即使使用内部调制解调器,调制解调器及其串口之间也好像存在“虚拟电缆”。在所有这 4 个链路(或电缆)上,都发生了流量控制。

现在让我们考虑一个流量控制操作的示例。考虑从电话线另一端的远程计算机到我所坐的文本终端屏幕的字节流。真正的文本终端对其屏幕上可以显示字节的速度有限制,并且会不时发出流量控制“停止”来减慢流量。此“停止”以与其控制的字节流相反的方向传播。当发出这样的“停止”时会发生什么?让我们考虑这样一种情况,即“停止”等待足够长的时间才通过“启动”取消它,以便它到达电话线另一端的远程计算机。当它到达那里时,它将停止远程计算机上正在发送字节的程序。

让我们追踪一下此 “停止” 的流程(在某些链路上可能是 “硬件” 流量控制,而在另一些链路上可能是 “软件” 流量控制)。首先,假设我正在“捕获”来自远程计算机的长文件,该文件同时发送到我的文本终端和我硬盘上的文件。字节的传入速度快于终端可以处理的速度,因此它通过其串口向我的 PC 上的串口发送 “停止” 信号。设备驱动程序检测到它并停止从 8k PC 串口缓冲区(在主内存中)向终端发送字节。但 minicom 仍然不断地将终端的字节发送到这个 8k 缓冲区中。

当这个 8k 发送缓冲区(在第一个串口上)满时,minicom 必须停止向其写入数据。 Minicom 停止并等待。但这也会导致 minicom 停止从连接到调制解调器的第二个串口上的 8k 接收缓冲区读取数据。来自调制解调器的数据流继续,直到这个 8k 缓冲区也满了,并向调制解调器发送不同的“停止”信号。现在,调制解调器的缓冲区停止向串口发送数据,并且也满了。调制解调器(假设启用了纠错)向远程计算机上的另一个调制解调器发送“停止信号”。这个调制解调器停止从其缓冲区发送字节,当其缓冲区满时,又向远程计算机的串口发送另一个停止信号。在远程计算机上,8-k(或其他大小)缓冲区满了,远程计算机上的程序无法再向其写入数据,因此暂时停止。

因此,来自文本终端的停止信号已经停止了远程计算机上的程序。多么漫长的一连串事件!请注意,停止信号通过了 4 个串口、2 个调制解调器和一个应用程序(minicom)。每个串口都有 2 个缓冲区(在一个数据流方向上):一个是 8k 的,一个是硬件 16 字节的。应用程序可能在其 C 代码中有一个缓冲区。这加起来数据要通过 11 个不同的缓冲区。请注意,小的串口硬件缓冲区不直接参与流量控制。另请注意,与文本终端串口关联的两个缓冲区将在流量控制暂停期间将其内容转储到屏幕上。这还剩下 9 个其他缓冲区,它们可能在流量控制暂停期间被填满。

如果终端速度限制是从远程计算机到终端的数据流的瓶颈,那么它的流量控制“停止”实际上正在停止从远程计算机发送数据的程序,如上所述。但你可能会问:一个“停止”怎么会持续如此之久,以至于 9 个缓冲区(其中一些很大)都被填满了?这种情况很少发生,但如果所有缓冲区在终端发出“停止”信号时都接近其上限,那么实际上可能会发生这种情况。

但是,如果你对此运行一个模拟,你就会发现它通常比这更复杂。在某个时间点,某些链路正在流动,而另一些链路则因流量控制而停止。来自终端的“停止”信号很少像上面描述的那样整齐地传播回远程计算机。可能需要来自终端的几个“停止”信号才能在远程计算机上产生一个“停止”信号,等等。要了解正在发生什么,你真的需要观察一个模拟,对于简单的情况,可以用桌子上的硬币来完成。只使用几个缓冲区,并将每个缓冲区的上限设置为几个硬币。

真的需要理解所有这些吗?嗯,理解这些解释了为什么从远程计算机捕获文本会丢失文本。情况与上述示例完全相同,但调制解调器到调制解调器的流量控制被禁用。本应也到达我的硬盘的捕获文本块从未到达那里,因为我的调制解调器缓冲区由于来自终端的流量控制“停止”而溢出。即使远程计算机有一个通往硬盘的没有瓶颈的路径,但相同的数据流也流向了终端,终端发出了流量控制“停止”信号,这对流向硬盘上的文件的分支造成了灾难性的后果。流向硬盘的数据流通过了我的调制解调器,并且由于溢出发生在调制解调器上,因此原本要发送到硬盘的字节丢失了。

4.9 串行驱动模块

串口的设备驱动程序是操作串口的软件。它现在以串行模块的形式提供。从内核 2.2 开始,如果需要,此模块通常会自动加载。在早期的内核中,你必须运行 kerneld 才能按需自动加载模块。否则,串行模块需要显式列在 /etc/modules 中。在模块在 Linux 中流行之前,串行驱动程序通常构建到内核中(有时仍然如此)。如果是内置的,请不要让串行模块加载,否则你将同时运行两个串行驱动程序。使用 2 个驱动程序会出现各种错误,包括尝试打开串口时可能出现的“I/O 错误”。使用 "lsmod" 查看模块是否已加载。

当串行模块加载时,它会在屏幕上显示有关现有串口的消息(通常显示错误的 IRQ)。但是一旦模块被 setserial 使用来告诉设备驱动程序(希望是)正确的 IRQ,你应该会看到第二个显示,类似于第一个,但具有正确的 IRQ 等。请参阅 串行模块 请参阅 什么是 Setserial 以获取有关 setserial 的更多信息。

4.10 PC 上的串口现在已过时

如今 (2011 年),串口在 PC 上有点过时(并且通常被称为“传统”设备),但它仍然在一些较旧的计算机上使用,并且用于嵌入式系统,用于与路由器和销售点设备通信等。串口是慢速的,大约在 2005 年之后,大多数新 PC 都不再配备串口。大多数笔记本电脑和 Mac 更早地停止使用它们。在一些新 PC 配备串口而另一些没有配备串口的时代,没有串口的 PC 被委婉地称为“无传统”。然而,虽然今天的 PC 不再配备串口,但有些 PC 将串口内置到“传统”调制解调器中(该调制解调器插入电话线)。这样的串口仅适用于调制解调器,不能用于任何其他设备。它们具有这种“内置”串口的原因是模拟调制解调器设计为仅通过串口工作。

PC 背面的物理串口(包括与其连接的 PC 内部芯片)必须在计算机和外部电缆之间传递数据。因此它有两个接口:串口到电缆和串口到计算机总线。这两个接口都很慢。首先,我们将考虑通过外部电缆到外部世界的接口。

4.11 RS-232 电缆速度慢且距离短

传统的 RS-232 串口本质上是低速的,并且在距离上受到严重限制。广告经常宣传“高速”,但它只能在非常短的距离内以“高速”工作,例如到位于计算机旁边的调制解调器。与网卡相比,即使这种“高速”实际上也是低速的。所有 RS-232 串行电缆线都使用公共接地回路线,因此在没有额外硬件的情况下无法使用双绞线技术(高速所需的技术)。存在更现代的串口接口,但它们不像 RS-232 那样是 PC 上的标准配置。请参阅 RS-232 的后继者。一些多端口串行卡支持它们。

RS-232 标准从 1969 年开始,没有使用可以快大约一百倍的双绞线技术,这有点悲剧。自 1800 年代后期以来,双绞线已用于电话电缆。1888 年(120 多年前),“电缆会议”报告称支持双绞线(用于电话系统),并指出了其优点。但在“电缆会议”批准 80 多年后,RS-232 未能利用它。由于 RS-232 最初是为将终端连接到附近的低速调制解调器而设计的,因此对高速和更长距离传输的需求显然没有被认识到。结果是,由于串口无法处理高速,因此设计了可以实现高速的新型串行接口:以太网、USB、火线等。最终的结果是串口的消亡,由于其古老的技术,串口在高速度应用中变得过时。

4.12 连接到计算机的低效 PCI 接口(在某些情况下)

串口通过 PCI 总线、LPC 总线、X 总线或 ISA 总线与计算机通信。PCI 总线现在是 32 位或 64 位宽,但串口一次只发送一个字节(8 位宽),这浪费了 PCI 总线带宽。LPC 总线则不然,它只有 4 位宽的总线,因此提供了高效的接口。ISA 总线通常是 16 位宽的,与高效的 LPC 和低效的 PCI 相比,效率介于两者之间。


5. 多端口串行板/卡/适配器

5.1 多端口串行简介

多端口串行卡安装在 PC 的 ISA 或 PCI 总线上的插槽中。它们也称为“...适配器”或“...板”。每张这样的卡都为你提供多个串口。如今,它们通常用于控制外部设备(包括工业和家庭自动化)。它们可以连接到计算机服务器,以便从远程位置监控/控制服务器。它们曾经主要用于将许多哑终端和/或调制解调器连接到串口。如今,哑终端的使用已经减少,并且现在可以将多个调制解调器(或数字调制解调器)内置到内部卡中。因此,多端口串行卡不如以前那么重要了。

每个多端口卡都有多个外部连接器(DB-25 或 RJ45),以便可以连接多个设备(调制解调器、终端等)。然后,每个这样的物理设备将连接到其自己的串口。由于卡的外向部分的空间有限,通常没有足够的空间容纳所有串口连接器。为了解决这个问题,连接器可以在从卡(章鱼电缆)外部伸出的电缆末端。或者它们可以在一个外部盒子(可能是机架式)上,该盒子通过电缆连接到多端口卡。

5.2 哑卡与智能卡

哑多端口卡与普通串口没有太大区别。它们是中断驱动的,计算机的 CPU 完成大部分服务它们的工作。它们通常具有为所有端口共享单个中断的系统。这不会减少 CPU 的负载,因为每次任何一个端口需要服务时,都会向 CPU 发送单个中断。此类设备通常需要特殊的驱动程序,你必须将其编译到内核中或用作模块。

智能板可能使用普通的 UART,但在板内部处理来自 UART 的大多数中断。这使 CPU 从处理所有这些中断的负担中解放出来。板可能会将其大型内部 FIFO 中的字节保存起来,并可能一次将 1k 字节传输到主内存中的串行缓冲区。它可以使用 32 位的完整总线宽度进行到主内存的数据传输(而不是像哑串行卡那样仅传输 8 位字节)。并非所有“智能”板都同样高效。如今,许多板都是即插即用型的。

5.3 获取/启用驱动程序

介绍

为了使多端口板工作,必须使用它的专用驱动程序。该驱动程序可以构建到内核源代码中,也可以作为模块提供。对于 2.6 及更高版本的内核,大多数驱动程序都以两种方式提供:作为模块或可以构建到内核中。注意不要同时将支持构建到内核中,并强制模块加载用于某个串行卡。对于较旧的内核,通常没有用于哑串行多端口板的模块,因此支持构建到内核中。

将(编译)支持构建到内核中?

预编译的内核可能没有为你内置多端口卡的驱动程序。因此,你必须自己编译内核并构建正确的驱动程序,或者确保模块可用并加载。当然,如果驱动程序不是以两种方式(作为编译时选项和作为模块)提供,你就别无选择。

如果你想查看现有工作内核中已编译的内容,请转到 /boot 目录(或编译内核所在的任何位置)并在 config... 文件中查找。

在 2.6 内核中,配置文件中有许多选项可供选择进行编译。添加对某些多端口卡的支持列在标题“字符设备”或“串行驱动程序”下。旧的多端口卡将支持作为串行驱动程序的一部分,并在“串行驱动程序”下找到。更高级的卡有自己的驱动程序,在“字符设备”下找到

对于编译内核 2.6,你应该选择“CONFIG_SERIAL_8250_EXTENDED”。(或者对于 2.4 只是“CONFIG_SERIAL_EXTENDED”)。然后,你将被问及更多关于你的串口的问题,并有更多选项可供选择。如果生成的配置不太正确,那么你可能需要手动编辑内核配置文件。

使用模块支持

预编译的内核可能附带了该板的预编译模块,因此你无需重新编译内核。必须加载此模块才能使用它,并且如果有驱动程序的安装软件,它还应该设置 Linux 以加载模块(可能在启动时)。一些在启动时加载的模块列在 /etc/modules 或 /etc/modules.conf 中。此外,可能需要通过这些文件中的条目或通过 lilo 的“append”命令或通过 grub 的“kernel”命令将某些参数传递给驱动程序。对于内核 2.6(和 2.4),(未加载的)模块应在 /lib/modules/.../kernel/drivers/char. 中找到。

获取有关多端口板的信息

板的制造商应该在其网站上提供信息。不幸的是,旧板的信息有时不在那里,但可能在互联网上的其他地方(包括讨论组)找到。你可能还想查看 /usr/share/doc/linux-doc... 中的内核文档(以前是 2.6 内核之前的 kernel-doc)。对于在编译之前配置内核或模块,请参阅:Configure.help 并搜索“serial”等。还有一些内核文档文件用于某些板,包括 computone、hayes-esp、moxa-smartio、riscom8、specialix、stallion 和 sx (specialix)。

5.4 /dev 目录中的多端口设备,

你的多端口板使用的串口取决于你拥有的板的类型。有些有自己的设备名称,如 /dev/ttyE27 (Stallion) 或 /dev/ttyD2 (Digiboard) 等。对于各种其他品牌,请参阅内核文档中的 devices.txt。有些使用标准名称,如 /dev/ttyS14,并且可以在用作 setserial 参数的配置文件中找到。此类文件可能包含在 setserial 或 serial 包中。

5.5 在 /dev 目录中创建旧式多端口设备

安装脚本可能会为你执行此操作。但如果没有,这里有一些关于如何在 /dev 目录中创建设备名称的示例。如果你使用 udev,MAKEDEV 将不会在设备目录中创建设备,因为此目录仅在内存中,并且在关闭计算机时会丢失。相反,它将在dev/.static/dev 目录中创建设备。

对于 ttyS.. 以外的其他类型的串口的名称和编号,请参阅内核文档中的 devices.txt。使用 mknod 命令或 MAKEDEV 脚本。键入 "man makedev" 可能会显示有关使用它的说明。

使用 MAKEDEV 脚本,你首先成为超级用户 (root) 并键入(例如)以下之一

linux# MAKEDEV ttyS17

或者,如果以上方法不起作用,请在给出上述命令之前 cd 到 /dev>。将你的端口替换为 ttyS17。

使用 mknod 是一种更复杂的方法,因为你需要知道主设备号和次设备号。这些数字在内核文档的“devices”文件中。对于 ttyS 串口,次设备号是:64 + 端口号(对于下面的示例 = 81)。请注意,对于 ttyS 设备,“主”设备号始终为 4(对于过时的 cua 设备为 5)。因此,如果你想使用 mknodttyS17 创建设备,你将键入

linux# mknod -m 666 /dev/ttyS17 c 4 81

5.6 标准 PC 串行卡

在过去,PC 出厂时安装了串行卡。后来,串行功能被放在硬盘接口卡上。在 1990 年代和 2000 年代初期,主板(板载)上通常内置一到两个串口。它们中的大多数(截至 2002 年)使用 16550,但有些使用 16650(32 字节 FIFO)。但是,如果他们需要更多串口,仍然可以购买单独的 PC 串行卡。它们可用于连接外部串行设备(调制解调器、串行鼠标等)。只有极少数零售计算机商店出售此类卡。但可以在互联网上购买它们。在购买用于 PCI 总线的卡之前,请确保 Linux 支持它。

以下是一些流行的品牌列表

注意:由于地址冲突,你可能无法同时使用 /dev/ttyS3 和 IBM8514 显卡(以及其他一些显卡)。请参阅 避免与某些显卡发生 IO 地址冲突

5.7 哑多端口串行板(带有标准 UART 芯片)

它们也称为“串行适配器”。每个端口都有自己的地址。它们通常具有共享中断的特殊方法,这要求你将对它们的支持编译到内核中。

* => 在 Debian 中运行 setserial 的文件显示了一些配置细节
# => 请参阅下面关于此板的注释

一般来说,Linux 将支持任何使用 8250、16450、16550、16550A、16650、16650V2、16654、16750、16850、16950 和 16954 UART 的串行板。有关更完整的列表,请参阅最新的 "setserial" 手册页。

注释

AST Fourport:你可能需要在 rc.serial 中指定 skip_test

BB-1004 和 BB-1008 不支持 DCD 和 RI 线,因此不能用于拨入调制解调器。它们可以很好地用于所有其他目的。

Digi PC/8 中断状态寄存器位于 0x140。

SIIG IO1812 手册中 COM5-COM8 的列表是错误的。它们应该是 COM5=0x250、COM6=0x258、COM7=0x260 和 COM8=0x268。

5.8 智能多端口串行板

确保 Linux 兼容的驱动程序可用,并阅读随附的信息。这些板使用特殊的设备(在 /dev 目录中),而不是标准的 ttyS 设备。此信息因你的硬件而异。如果你有应在此处显示的更新信息,请通过电子邮件发送给我。

Linux 驱动程序模块的名称是 *.ko(内核 2.6 之前是 *.o),但这些可能不适用于显示的所有型号。请参阅 模块(主要用于智能板) 所需的模块可能已随你的 Linux 发行版提供。此外,通常需要将参数(如 io 和 irq)提供给模块,因此你需要查找有关此方面的说明(可能在源代码树中)。

有许多不同的品牌,每个品牌通常提供许多不同的卡。目前没有尝试在此处列出所有卡(并且列出的许多卡都已过时,并且链接到它们的互联网链接不良,需要修复)。但所有主要品牌和网站都应在此处显示,因此如果缺少某些内容,请告诉我。转到显示的网页以获取更多信息。这些网站通常还提供有关相关硬件的信息(广告),例如调制解调器池、远程访问服务器 (RAS) 和终端服务器。如果没有网页,则这些卡可能已过时。如果你想整理一个更好的列表,请告诉我。

Linux Journal 1995 年 6 月刊登载了对 Comtrol、Cyclades、Digi 和 Stallion 产品的评论。该文章可在 评论:智能多端口串行板 中找到。除了本 HOWTO 中上面找到的各种多端口品牌列表之外,还有 Gary 的百科全书 - 串行卡。它不如前者完整,但可能有一些不同的链接。

5.9 不受支持的多端口板

截至 2000 年 1 月 1 日,以下以前制造具有 Linux 支持的板卡的品牌未提及任何 Linux 支持。如果发生变化,请告诉我。


6. 串口服务器

具有许多串行端口(连接了许多串行电缆)的计算机通常被称为服务器。当然,大多数服务器除了提供串行端口服务外,还提供其他功能,并且许多服务器根本不提供串行端口服务(尽管它们可能有一个串行端口)。例如,“串行服务器”可能具有串行电缆,每条电缆都连接到不同的(非串行)服务器。串行服务器(可能称为“控制台服务器”)通过控制台控制所有其他服务器。控制台可能在物理位置上远离串行服务器,通过网络与服务器通信。

串行服务器主要有两种基本类型。一种类型只是普通的计算机(可能是机架式),它在 PCI 总线(或类似总线)上使用多端口卡。另一种类型是专用服务器,它是为特殊目的而设的专用计算机。这两种类型的服务器都可以称为:串行服务器、控制台服务器、打印服务器或终端服务器。它们并不相同。

终端服务器最初被设计为提供许多串行端口,每个端口都连接到一个哑文本终端。如今,终端服务器通常通过快速网络连接到图形终端,并且不使用串行端口,因为串行端口速度太慢了。一根网线取代了许多串行电缆,并且每个图形终端使用的带宽远大于文本终端。但是,图形终端可以在文本模式下运行以减少所需的带宽。《文本终端 HOWTO》中对终端服务器(串行端口)进行了更详细的讨论。有关联网终端服务器(非串行端口),请参阅 Linux 终端服务器项目 (LTSP)

(待办事项:讨论其他类型的串行服务器,但作者对此知之甚少。)


7. 配置概述

在大多数情况下,配置是自动处理的,您无需执行任何操作。Linux 应该会检测到您的串行端口,并在需要时加载驱动程序模块。然后,驱动程序应确保已分配 IRQ 和地址空间资源。最后,使用串行端口的应用程序应设置端口速度等。

为了使这一切正常工作,串行支持必须编译到内核中(由您或编译内核的人员编译),或者由在您开始使用串行端口时加载到内核中的模块提供。在大多数情况下,如果它没有编译到内核中,模块将完成这项工作,并且 Linux 应该能够自动找到并加载正确的模块。

但是,如果您有超过 4 个(或可能 2 个)串行端口,则必须告知内核,因为它似乎不会自动执行此操作。请参阅支持的串行端口数量内核配置串行模块

一旦内核和模块中有了适当的支持,串行端口的其余配置应该会自动发生。这通常由串行驱动程序软件在您的应用程序软件的帮助下完成。但有时它配置不正确,那么您需要自己配置。或者,也许您需要以特殊方式配置它等等。本 HOWTO 仅涵盖串行端口本身的配置,而不涵盖连接到端口的任何设备(例如调制解调器或打印机)的配置。

资源分配(定位硬件或底层配置)是将每个端口分配一个 IO 地址、IRQ 和名称(例如 ttyS2)。这个 IO-IRQ 对必须在硬件中设置,并让串行驱动程序知道。我们可以将此简称为“io-irq”配置。“setserial”程序有时用于告知驱动程序管理员已放入配置文件或作为 setserial 命令参数提供的 io-irq 信息。PnP 方法、跳线器等用于在硬件中设置 IO 和 IRQ。详细信息将在稍后提供。如果您需要配置但不理解某些细节,很容易陷入困境。请参阅定位串行端口:IO 地址 IRQ 什么是 Setserial

第二部分(高级配置)是为其分配速度(例如 115.2k 位/秒)、选择流控制等。这通常由通信程序启动,例如 wvdial、PPP、minicom、picocom 或 getty(您可以在端口上运行 getty,以便其他人可以从连接到端口的旧式哑终端登录到您的计算机)。但是,您需要通过使用菜单或配置文件来告诉这些程序您想要的速度等。这种高级配置也可以使用 stty 程序手动完成。如果您遇到问题,stty 也可用于查看当前状态。请参阅Stty部分


8. 定位串行端口:IO 地址、IRQ

8.1 我的串行端口在哪个总线上?

如果您需要查找串行端口,了解它在哪个总线上通常很有帮助。如果串行端口在卡上,您可能知道卡插入哪个总线插槽,例如 PCI 插槽。但是,如果串行端口内置在主板中,则可能不清楚它在哪个总线上。对于具有 ISA 总线插槽的旧主板,它很可能在 ISA 总线上,甚至可能不是即插即用 (Plug-and-Play)。但即使您的所有插槽都是 PCI,串行端口也可能在 ISA 总线或 LPC 总线(也称为“LPC 接口”)上。LPC 在笔记本电脑上很常见。键入“lspci”以查看它是否显示“LPC”。不幸的是,LPC 总线没有用于低级配置其上设备的标准即插即用方法。但是,根据规范,BIOS 应该执行此类配置(使用 ACPI ??)。要查看您是否有 LPC 总线,请键入“lspci”并查找 LPC 桥接器或类似物。

8.2 IO 和 IRQ 概述

为了使串行端口正常工作,首先必须为其提供 IO 地址和 IRQ。对于旧硬件(1990 年代中期),卡上的跳线器或保存的 BIOS 设置可以完成这项工作。对于较新的硬件,BIOS 或 Linux 必须在启动时设置它们,并且新硬件在断电后不记得它是如何设置的。启用硬件(通过使用软件)为其提供 IRQ 和 IO 地址。没有 IO 地址,它就无法使用。没有 IRQ,它将需要使用效率低下的轮询方法,为此必须在串行驱动程序中将 IRQ 设置为 0。使用 BIOS 或 Linux 发送到硬件的数字信号,所有这些都应该自动配置(前提是 BIOS 之前没有设置为禁用它)。因此,只有在遇到问题或者想了解其工作原理时才需要阅读本文。

驱动程序当然必须知道 IO 地址和 IRQ,以便它可以与串行端口芯片通信。现代串行端口驱动程序(内核 2.4)尝试通过 PnP 方法确定这一点,因此通常不需要告诉驱动程序(通过使用“setserial”)。驱动程序也可以在硬件中设置 IO 地址或 IRQ。但不幸的是,有一些 PCI 串行端口硬件驱动程序无法识别,因此您可能需要自己启用端口。请参阅PCI:启用已禁用的端口

对于旧的 ISA 总线,驱动程序还会探测可能的串行端口地址,以查看那里是否有任何串行端口。这适用于跳线器的情况,有时适用于驱动程序不执行 ISA PnP 时的 ISA PnP 端口(内核 2.4 之前)。

通过为其提供 IRQ 和 IO 地址来定位串行端口是低级配置。它通常由串行驱动程序自动完成,但有时您必须自己完成。以下内容重复了上面所说的内容,但更详细。

低级配置包括分配 IO 地址、IRQ 和名称(例如 ttyS2)。这个 IO-IRQ 对必须在硬件中设置,并告知串行驱动程序。并且驱动程序需要将此对称为名称(例如 ttyS2)。我们可以将此简称为“io-irq”配置。现代方法是驱动程序使用 PnP 方法来检测/设置 IO/IRQ,然后记住它所做的事情。驱动程序执行此操作的一种简单方法是让驱动程序请求内核启用设备,然后内核告诉驱动程序它已使用的 IO/IRQ。旧方法是使用“setserial”程序告诉驱动程序。对于跳线器,没有 PnP,但如果跳线器设置为常用的 IO/IRQ,则驱动程序可能会检测到端口。如果您需要配置但不理解某些细节,很容易陷入困境。

当 Linux 启动时,会努力检测和配置(低级)串行端口。具体发生的情况取决于您的 BIOS、硬件、Linux 发行版、内核版本等。如果串行端口工作正常,则可能无需执行任何更低级别的配置。

如果您在串行端口方面遇到问题,那么您可能需要进行低级配置。如果您使用内核 2.2 或更低版本,那么如果您

从内核 2.2 开始,您可能能够通过共享中断来使用超过 2 个串行端口,而无需进行任何低级配置。所有 PCI 端口都应支持此功能,但对于 ISA,它仅适用于某些硬件。如果中断可用,为每个端口分配一个唯一的中断可能同样容易。请参阅中断共享和内核 2.2+

低级配置(设置 IRQ 和 IO 地址)似乎比高级配置给人们带来更多麻烦,尽管对于许多人来说,它是完全自动的,并且无需进行任何配置。在端口启用并且串行驱动程序知道正确的 IRQ 和 IO 地址之前,端口通常根本无法工作。

端口可能被禁用,可能是由 BIOS 禁用,也可能是 Linux 未能找到并启用端口。对于现代端口(前提是 BIOS 没有禁用它们),手动 PnP 工具(例如 lspci)应该能够找到它们。应用程序和实用程序(例如“setserial”和“scanport”(仅限 Debian ??))仅探测 IO 地址,不使用 PnP 工具,因此无法检测到禁用的端口。

即使串行驱动程序完成的探测可以找到 ISA 端口,如果 IRQ 错误,它也可能工作非常缓慢。请参阅极慢:文本在长时间延迟后才缓慢出现在屏幕上。PCI 端口不太可能出现 IRQ 错误。

IO 地址、IRQ 等被称为“资源”,因此我们正在配置某些资源。但是还有许多其他类型的“资源”,因此该术语还有许多其他含义。总而言之,低级配置包括启用设备、为其命名(例如 ttyS2)并将两个值(IRQ 号和 IO 地址)放入两个位置

  1. 设备驱动程序(由 PnP 或“setserial”完成)
  2. 串行端口硬件本身的配置寄存器,由 PnP 软件(或旧式硬件上的跳线器)完成。

您可以观看启动(= 启动时)消息。它们通常是正确的。但是,如果您遇到问题,您的串行端口可能根本不显示,或者如果您看到来自“setserial”的消息,它可能不会显示硬件的真实配置(并且不一定应该显示)。请参阅I/O 地址和 IRQ:启动时消息

8.3 PCI 总线支持

介绍

如果您有内核 2.4 或更高版本,则应该支持 PCI 和 ISA 总线的 PnP(内置或通过模块)。某些 PCI 串行端口可以由串行驱动程序自动检测和低级配置。其他端口可能无法自动检测和配置。

虽然内核 2.2 通常支持 PCI,但它不支持 PCI 串行端口(尽管有些人还是让它们工作了)。从内核 2.4 开始,串行驱动程序将读取数字存储在串行硬件中的 ID 号,以确定如何支持它(如果它知道如何支持)。它应该为其分配 I/O 地址,确定其 IRQ 等。因此您不需要为其使用“setserial”。

如果您不使用设备文件系统,可能会出现问题。驱动程序可能会根据启动时消息将端口分配给 tt/ttyS4(使用 dmesg 查看)。但是,如果您没有“文件” /dev/ttyS4,则端口将无法工作。因此,您需要使用以下命令创建它:
cd /dev; ./MAKEDEV ttyS4

有关 PCI 的更多信息

PCI 端口没有很好的标准化。有些使用主内存与 PC 通信。有些需要特殊启用 IRQ。 “lspci -vv”的输出可以帮助确定是否可以支持某个端口。如果您看到 4 位 IO 端口,则只需告诉“setserial”IO 端口和 IRQ,该端口就可以工作。例如,如果 lspci 显示 IRQ 10,I/O 地址为 0xecb8,并且您决定将其命名为 ttyS2,则命令为

setserial /dev/ttyS2 irq 10 port 0xecb8 autoconfig

请注意,启动时消息“Probing PCI hardware”表示读取 PCI 设备中的 PnP 配置寄存器,这会检测有关所有 PCI 卡和板载 PCI 设备的信息。这与串行驱动程序探测 IO 地址不同,串行驱动程序探测 IO 地址意味着读取某些 IO 地址以查看读取的内容是否看起来像该地址存在串行端口。

8.4 关于低级配置的常见错误

以下是人们常犯的一些错误

8.5 IRQ 和 IO 地址必须正确

对于“什么是我的 IO 和 IRQ?”这个问题,实际上有两个答案。 1. 设备驱动程序认为已设置的内容(这是 setserial 通常设置和显示的内容)。 2. 硬件中实际设置的内容。 以上 1. 和 2. 应该相同。 如果它们不相同,则会带来麻烦,因为驱动程序具有有关物理串行端口的不正确信息。 在某些情况下,硬件被禁用,因此它没有 IO 地址或 IRQ。

如果驱动程序的 IO 地址错误,它将尝试将数据发送到不存在的串行端口——甚至更糟的是,发送到其他设备。 如果它的 IRQ 错误,驱动程序将不会收到来自串行端口的中断服务请求,从而导致响应非常慢或没有响应。 请参阅极慢:文本在长时间延迟后才缓慢出现在屏幕上。 如果它的 UART 型号错误,也很容易出现问题。 要确定 IO-IRQ 对是否相同,您必须找出它们在驱动程序和硬件中是如何设置的。

8.6 驱动程序认为的 IO 地址和 IRQ 是什么?

介绍

驱动程序认为的内容不一定是硬件的实际设置方式。 如果一切工作正常,那么驱动程序认为的内容很可能是正确的(在硬件中设置),您无需进行调查(除非您好奇或想成为专家)。 确定驱动程序认为的内容的方法包括:启动时消息 I/O 地址和 IRQ:启动时消息、/proc 目录“文件” /proc 目录和 setserial 以及“setserial”命令。

I/O 地址和 IRQ:启动时消息

在许多情况下,您的端口将在启动时自动进行低级配置(但并非总是正确)。 要查看正在发生的事情,请查看屏幕上的启动消息。 不要忽略检查 Linux 加载之前的 BIOS 消息(此处未显示示例)。 这些 BIOS 消息可以通过按 Pause 键(同时按住 Shift 键)来冻结。 冻结它们通常很棘手,您可能需要在 Linux 启动时按 Ctrl-Alt-Del 以启动重新启动并重试。 这些消息显示的内容可能会随着启动的进行而更改,并且在完全正确的单词处冻结它通常很棘手。

使用 Shift-PageUp 向后滚动到消息,在消息闪过后。 Shift-PageDown 将在相反方向滚动。 dmesg 命令(或查看 /var/log 中的日志)将仅显示这两条消息中的第一条。 以下是启动消息的示例(截至 2004 年,与 1999 年几乎相同)。 请注意,在较旧的版本中,ttyS1 在这些消息中显示为 ttyS01 等。

首先,您会看到检测到的内容(但 irq 只是一个猜测)

Serial driver version 4.27 with no serial options enabled
ttyS0 at 0x03f8 (irq = 4) is a 16550A
ttyS1 at 0x02f8 (irq = 3) is a 16550A
ttyS2 at 0x03e8 (irq = 4) is a 16550A
ttyS4 at port 0xeff0 (irq = 10) is a 16550A

请注意,ttyS0-ttyS2 是通过探测标准地址检测到的,而 ttyS4 是通过探测 PCI 配置检测到的 PCI 端口。 稍后,setserial 会向您显示保存在配置文件中的内容(您可以编辑该文件),但这也不一定是正确的

Loading the saved-state of the serial devices...
/dev/ttyS1 at 0x02f8 (irq = 3) is a 16550A
/dev/ttyS2 at 0x03e8 (irq = 5) is a 16550A

请注意,配置文件中只有 ttyS1-2,因此 ttyS0 和 ttyS4 不受其影响。 还存在轻微的差异:第一条消息显示 ttyS2 的 irq=4,而第二条消息显示它的 irq=5。 在大多数情况下,第二条消息是正确的。 但是,如果您遇到问题,它可能会产生误导。 在阅读本节其余部分中对所有这些复杂性的解释之前,您可能只需尝试使用您的串行端口,看看它是否工作正常。 如果是这样,则可能不需要进一步阅读。

第二条消息来自在启动时从 /etc 目录树中的脚本运行的 setserial 程序。 它显示了设备驱动程序认为正确的配置。 但这也可能是错误的。 例如,irq 实际上可能在硬件中设置为 irq=8(两条消息都错误)。 irq=5 可能在那里是因为配置文件不正确。

对于旧的跳线器设置的串行端口,Linux 有时会获得错误的 IRQ,因为它默认情况下不探测 IRQ。 它只是假定“标准”IRQ(第一条消息)或接受配置文件中的内容(第二条消息)。 这些都不一定是正确的。 如果串行驱动程序的 IRQ 错误,则串行端口会非常慢,或者似乎根本无法工作。

第一条消息是 Linux 探测 ISA 串行端口地址的结果,但它不探测 IRQ。 如果此处显示某个端口,则该端口存在,但 IRQ 可能错误。 Linux 不检查 IRQ,因为这样做并非万无一失。 它只是假定 IRQ 与显示的内容相同,因为它们是“标准”值。 您可以使用 setserial 以及 autoconfigauto_irq 选项手动检查它们,但这也不能保证是正确的。

BIOS 消息(在 Linux 启动之前首先看到的)显示的数据是最初在硬件中设置的数据。 如果您的串行端口是即插即用 (PnP) 端口,则“isapnp”或“setpci”可能会运行并更改这些设置。 在 Linux 启动后查找有关此内容的消息。 上面示例中显示的最后一条串行端口消息应与 BIOS 消息(可能由 isapnp 或 setpci 修改)一致。 如果它们不一致,那么您需要更改端口硬件中的设置,或者使用 setserial 告诉驱动程序硬件中实际设置的内容。

此外,如果您有即插即用 (PnP) 串行端口,则除非 IRQ 和 IO 已通过即插即用软件在硬件内部设置,否则它们只能通过 PnP 软件找到。 在内核 2.4 之前,这是启动消息未显示物理存在的串行端口的常见原因。 PnP BIOS 可能会自动低级配置它们。 PnP 配置将在稍后解释。

/proc 目录和 setserial

键入“setserial -g /dev/ttyS*”。 还有其他一些方法可以通过查看 /proc 目录中的“文件”来查找此信息。 请注意,不能保证硬件中设置的内容相同。

/proc/ioports 将显示驱动程序正在使用的 IO 地址。 /proc/interrupts 显示当前运行进程(已打开设备)的驱动程序使用的 IRQ。 它显示了实际发出的中断次数。 /proc/tty/driver/serial 显示了上述大部分内容,以及已接收和发送的字节数(即使设备现在未打开)。

请注意,对于 IO 地址和 IRQ 分配,您仅看到驱动程序认为的内容,而不一定是硬件中实际设置的内容。 但是,有关实际发出的中断数和处理的字节数的数据是真实的。 如果您看到大量中断和/或字节,则可能意味着设备正在(或曾经)工作。 但是,中断可能来自另一个设备。 如果没有接收到字节 (rx:0),但已传输字节 (例如 tx:3749),则只有一个方向的流工作(或被利用)。

有时,仅显示少量中断并不意味着中断实际上是由任何串行端口物理生成的。 因此,如果您看到您正在尝试使用的端口几乎没有中断,则该中断可能未在硬件中设置。 要查看 /proc/interrupts 以检查您当前正在运行的程序(例如“minicom”),您需要在查看时保持程序运行。

8.7 我的串行端口硬件的 IO 地址和 IRQ 是什么?

介绍

如果是 PCI 或 ISA PnP,则硬件中设置的内容是通过 PnP 方法完成的。 即使没有设置任何内容或端口被禁用,仍然可以使用“lspci -v”或“isapnp --dumpregs”找到 PnP 端口。 通过跳线器(或硬件故障)禁用的端口将完全丢失。 请参阅ISA PnP 端口PCI:已设置的 IO 和 IRQ 是什么?PCI:启用已禁用的端口

当电源关闭时,PnP 端口不会将其配置存储在硬件中。 这与跳线器(非 PnP)形成对比,跳线器在电源关闭时保持不变。 这就是 PnP 端口比旧的非 PnP 端口更可能在禁用状态下找到的原因。

PCI:已设置的 IO 和 IRQ 是什么?

对于 PCI,BIOS 几乎总是设置 IRQ,并且也可能设置 IO 地址。 要查看它是如何设置的,请使用“lspci -vv”(最佳)或查看 /proc/bus/pci(或对于内核 <2.2 /proc/pci)。 调制解调器的串行端口通常称为“通信控制器”。 查找此名称。 如果 lspci 显示“I/O ports at ... [disabled]”,则串行端口已禁用,并且硬件没有 IO 地址,因此它已丢失且无法使用。 请参阅PCI:启用已禁用的端口,了解如何启用它。

如果显示了多个 IO 地址,则第一个地址更可能是它。 您无法更改 IRQ(至少不能使用“setpci”)。 这是因为如果写入 IRQ,则不会对其硬件寄存器采取任何操作。 BIOS 应该实际设置 IRQ,然后将正确的值写入此寄存器以供 lspci 查看。 如果必须更改,请使用“setpci”通过更改 BASE_ADDRESS_0 或类似地址来更改 IO 地址。

PCI:启用已禁用的端口

如果端口通过 IO 地址通信,则“lspci -vv”应显示“Control: I/O+ ...”,其中 + 表示 IO 地址已启用。 如果它显示“I/O-”(和“I/O ports at ... [disabled]”),则您可能需要使用 setpci 命令来启用它。 例如,“setpci -d 151f:000 command=101”。 151f 是供应商 ID,000 是设备 ID,两者都从“lspci -n -v”或 /proc/bus/pci 或“scanpci -v”获得。 “command=101”表示 101 被放入命令寄存器中,该寄存器与“lspci”显示的“Control”寄存器相同。 101h 设置了两个位:1 将 I/O 设置为 +,100 部分保持 SERR# 设置为 +。 在这种情况下,当运行 lspci 命令时,最初观察到 Control 寄存器的 SERR# 位为 +。 因此,我们通过将位 8(其中位 0 是 I/O)设置为 1(在 101 中的第一个 1)来保持其启用状态为 +。 某些串行卡不使用 SERR#,因此如果您看到 SERR#-,则无需启用它,因此请使用:command=1。 然后,您需要设置“setserial”以告知驱动程序 IO 和 IRQ。

位 8 实际上是第 9 位,因为我们从 0 开始计数位。 不要惊慌,lspci 显示了很多 - 符号,表明该卡没有很多可用(或启用)的功能。 串行端口相对较慢,不需要这些功能。

启用它的另一种方法是让 BIOS 执行此操作,方法是告诉 BIOS 您没有即插即用操作系统。 然后,BIOS 应在您启动 PC 时启用它。 如果您在同一台 PC 上安装了 MS Windows9x,则执行此操作可能会导致 Windows 出现问题(请参阅 Plug-and-Play-HOWTO)。

ISA PnP 端口

对于 ISA 即插即用 (PnP) 端口,可以尝试使用 pnpdump 程序(isapnptools 的一部分)。 如果您使用 --dumpregs 选项,则它应该告诉您端口中设置的实际 IO 地址和 IRQ。 它还应该找到已禁用的 ISA PnP 端口。 它“尝试”的地址不是设备的 IO 地址,而是用于与 PnP 卡通信的特殊地址。

查找未禁用的端口(ISA、PCI、PnP、非 PnP)

也许 BIOS 消息会在 Linux 开始启动之前告诉您一些信息。 使用 Shift-PageUp 键向后逐步浏览启动时消息,并查看最早的消息,这些消息来自 BIOS。 这是 Linux 启动之前的状态。 Setserial 无法更改它,但 isapnp 或 setpci 可以。 从内核 2.4 开始,串行驱动程序可以为许多(但并非全部)串行端口进行此类更改。

使用“scanport”(仅限 Debian ??)将探测所有 I/O 端口,并将指示它认为可能是串行端口的内容。 在此之后,您可以尝试使用“autoconfig”选项使用 setserial 进行探测。 您需要猜测要探测的地址(使用来自“scanport”的线索)。 请参阅什么是 Setserial

对于使用跳线器设置的端口,IO 端口和 IRQ 根据跳线器设置。 如果端口不是即插即用 (PnP),而是已使用 DOS 程序设置,则它设置为运行该程序的人员设置的任何值。

通过 MS Windows 探索(最后的手段)

对于 PnP 端口,检查它在 DOS/Windows 下的配置方式可能(或可能不)暗示它在 Linux 下的配置方式。 MS Windows 将其配置信息存储在其注册表中,Linux 不使用该注册表,因此它们的配置不一定相同。 如果您让 PnP BIOS 在启动 Linux 时自动执行配置(并且在启动 Linux 时已告知 BIOS 您没有 PnP 操作系统),则 Linux 应使用 BIOS 非易失性存储器中的任何配置。 Windows 也使用相同的非易失性存储器,但不一定以这种方式配置它。

8.8 选择串行 IRQ

如果您有即插即用端口,则 PnP BIOS 或串行驱动程序可能会为您配置所有设备,因此您可能不需要选择任何 IRQ。 PnP 软件确定它认为最佳的 IRQ 并分配它们(但并不总是最佳的)。 但是,如果您直接使用 isapnp(ISA 总线)或跳线器,则必须选择。 如果您已经知道要使用的 IRQ,则可以跳过本节,但您可能想知道 IRQ 0 具有特殊用途(请参阅以下段落)。

IRQ 0 不是 IRQ

虽然 IRQ 0 实际上是计时器(在硬件中),但它对于使用 setserial 设置串行端口具有特殊含义。 它告诉驱动程序端口没有中断,然后驱动程序将使用轮询方法。 这种轮询会给 CPU 带来更多负载,但如果存在中断冲突或错误设置的中断,则可以尝试使用。 分配 IRQ 0 的优点是您无需知道硬件中设置了什么中断。 它应该仅用作临时权宜之计,直到您能够找到要使用的真实中断为止。

中断共享,内核 2.2+

IRQ 共享是指两个设备使用相同的 IRQ。 作为一般规则,ISA 总线不允许这样做。 PCI 总线可以共享 IRQ,但不能在 ISA 总线和 PCI 总线之间共享相同的 IRQ。 大多数多端口板都可以共享 IRQ。 共享效率不高,因为每次给出共享中断时,都必须进行检查以确定它来自哪里。 因此,如果可行,为每个设备分配自己的中断会更好。

在内核 2.2 之前,除了大多数多端口板之外,串行 IRQ 不能相互共享。 从内核 2.2 开始,串行 IRQ 有时可以在串行端口之间共享。 为了使共享在 2.2 中工作,内核必须已使用 CONFIG_SERIAL_SHARE_IRQ 编译,并且串行端口硬件必须支持共享(以便如果两个串行卡在同一中断线上施加不同的电压,则只有表示“这是一个中断”的电压才会占主导地位)。 由于 PCI 总线规范允许共享,因此任何 PCI 卡都应允许共享。

选择哪些 IRQ?

串行硬件通常只有有限数量的 IRQ。 此外,您不希望出现 IRQ 冲突。 因此,可能没有太多选择。 您的 PC 通常可能带有 IRQ 4 上的 ttyS0ttyS2,以及 IRQ 3 上的 ttyS1ttyS3。 查看 /proc/interrupts 将显示当前运行的程序正在使用的 IRQ。 您可能不想使用其中之一。 在 IRQ 5 用于声卡之前,它通常用于串行端口。

以下是 Greg(Serial-HOWTO 的原始作者)在 /etc/rc.d/rc.serial 中设置他的方法。 rc.serial 是一个在启动时运行的文件(shell 脚本)(它可能具有不同的名称或位置)。 对于 2.15 之后的“setserial”版本,不再总是以这种方式完成,但此示例确实显示了 IRQ 的选择。

/sbin/setserial /dev/ttyS0 irq 3        # my serial mouse
/sbin/setserial /dev/ttyS1 irq 4        # my Wyse dumb terminal
/sbin/setserial /dev/ttyS2 irq 5        # my Zoom modem
/sbin/setserial /dev/ttyS3 irq 9        # my USR modem

标准 IRQ 分配

        IRQ  0    Timer channel 0 (May mean "no interrupt".  See below.)
        IRQ  1    Keyboard
        IRQ  2    Cascade for controller 2
        IRQ  3    Serial port 2
        IRQ  4    Serial port 1
        IRQ  5    Parallel port 2, Sound card
        IRQ  6    Floppy diskette
        IRQ  7    Parallel port 1
        IRQ  8    Real-time clock
        IRQ  9    Redirected to IRQ2
        IRQ 10    not assigned
        IRQ 11    not assigned
        IRQ 12    not assigned
        IRQ 13    Math co-processor
        IRQ 14    Hard disk controller 1
        IRQ 15    Hard disk controller 2

在选择中断时,实际上没有正确的方法。 尝试找到一个未被主板或任何其他板使用的中断。 2、3、4、5、7、10、11、12 或 15 都是可能的选择。 请注意,IRQ 2 与 IRQ 9 相同。 您可以将其称为 2 或 9,串行驱动程序非常理解。 如果您的串行板非常旧,则可能无法使用 IRQ 8 及以上的中断。

请确保您没有使用 IRQ 1、6、8、13 或 14!这些中断请求 (IRQ) 是主板使用的。占用主板的 IRQ 会让她非常不高兴。完成后,您可能需要在使用中断的程序运行时双重检查 /proc/interrupts,并确保没有冲突。

8.9 选择地址 -- 视频卡与 ttyS3 冲突

这是一个关于一些旧串行卡的问题。据称 IBM 8514 视频卡(以及类似的卡)的 IO 地址是 0x?2e8,其中 ? 可以是 2、4、8 或 9。这可能会与 ttyS3 在 0x02e8 的 IO 地址冲突。您可能会认为这不应该发生,因为地址的高位数字不同(02e8 中的前导 0)。您是对的,但是设计不良的串口可能会忽略高位数字,并响应任何以 2e8 结尾的地址。如果您尝试在此 IO 地址使用 ttyS3 (ISA 总线),那将是坏消息。

对于 ISA 总线,您应该尝试使用下面显示的默认地址。PCI 卡使用不同的地址,以免与 ISA 地址冲突。下面显示的地址代表 8 字节范围的起始地址。例如,3f8 实际上是 3f8-3ff 的范围。每个串行设备(以及其他类型的使用 IO 地址的设备)都需要其自己唯一的地址范围。不应有重叠(冲突)。以下是 ISA 总线上常用串口的默认地址

ttyS0 address 0x3f8
ttyS1 address 0x2f8
ttyS2 address 0x3e8
ttyS3 address 0x2e8

假设在真实串口和另一个物理上不存在的端口(并显示 UART:未知)之间存在地址冲突(如 setserial -g /dev/ttyS* 报告的那样)。这种冲突不应引起问题,但有时在旧内核中会引起问题。为了避免此问题,请不要允许此类地址冲突,或者如果 /dev/ttySx 物理上不存在,则删除它。

8.10 在硬件中设置 IO 地址和 IRQ(主要用于 PnP)

在硬件中设置完成后,不要忘记使用 setserial 确保驱动程序中也设置了它。对于非 PnP 串口,它们要么通过跳线在硬件中设置,要么通过运行 DOS 程序(“无跳线”)来设置它们(这可能会禁用 PnP)。本小节的其余部分仅适用于 PnP 串口。以下是配置 PnP 串口的可能方法列表

每次系统开机时,IO 地址和 IRQ 都必须(通过 PnP)在其寄存器中设置,因为 PnP 硬件不记得断电时的设置。一种简单的方法是让 PnP BIOS 知道您没有 PnP 操作系统,BIOS 将在每次启动时自动执行此操作。如果您启动 Windows 时 BIOS 认为 Windows 不是 PnP 操作系统,这可能会在 Windows(这是一个 PnP 操作系统)中引起问题。请参阅 Plug-and-Play-HOWTO。

即插即用 (PnP) 旨在自动化此 io-irq 配置,但对于 Linux 而言,最初使生活更加复杂。在现代 Linux(2.4 内核 -- 部分在 2.2 内核中)中,每个设备驱动程序都必须执行自己的 PnP(使用它可能利用的提供的软件)。不幸的是,与 MS Windows 中一样,没有用于分配 IO 地址和 IRQ 的集中规划。但这通常在 Linux 中也能正常工作。

使用 PnP BIOS 进行 IO-IRQ 配置

虽然关于如何使用 setpci 或 isapnp 进行 io-irq 配置的解释应该随软件一起提供,但如果您想让 PnP BIOS 执行此类配置,则情况并非如此。并非所有 PnP BIOS 都能做到这一点。BIOS 通常有一个 CMOS 菜单来设置前两个串口。此菜单可能很难找到。对于“Award”BIOS,它位于“芯片组功能设置”下。通常可供选择的很少。对于 ISA 串口,前两个端口通常设置为标准 IO 地址和 IRQ。请参阅 更多关于串口名称的信息

无论您是否喜欢,当您启动 PC 时,PnP BIOS 都会开始对硬件设备进行 PnP (io-irq) 配置。它可能会部分完成这项工作,并将其余部分交给 PnP 操作系统(Linux 在某种意义上是 PnP 操作系统),或者如果它认为您没有 PnP 操作系统,它可能会完全配置所有 PnP 设备,但不配置设备驱动程序。

如果您告诉 BIOS 您没有 PnP 操作系统,那么 PnP BIOS 应该配置所有 PnP 串口 -- 而不仅仅是前两个。控制 BIOS 操作的间接方法(如果您在同一台 PC 上安装了 Windows 9x)是在 Windows 下“强制”配置。请参阅 Plug-and-Play-HOWTO 并搜索“forced”。使用 CMOS BIOS 菜单更容易,它可能会覆盖您在 Windows 下“强制”的内容。可能有一个 BIOS 选项可以设置或禁用此“覆盖”功能。

如果您添加新的 PnP 设备,BIOS 应该对其进行 PnP 配置。如果需要避免任何冲突,它甚至可以更改现有设备的 io-irq。为此,它会保留非 PnP 设备列表,前提是您已告知 BIOS 这些非 PnP 设备是如何进行 io-irq 配置的。告诉 BIOS 的一种方法是在 DOS/Windows 下运行名为 ICU 的程序。

但是,您如何找出 BIOS 所做的事情,以便使用此信息设置设备驱动程序?BIOS 本身可能会提供一些信息,无论是通过其设置菜单还是在您打开计算机时屏幕上的消息。请参阅 我的串口硬件中设置了什么?。其他查找方法是使用 lspci 获取 PCI 总线的信息,或使用 isapnp --dumpregs 获取 ISA 总线的信息。它显示的神秘结果对于新手来说可能不清楚。

8.11 向 Setserial 提供 IRQ 和 IO 地址

一旦您在硬件中设置了 IRQ 和 IO 地址(或安排由 PnP 完成),您还需要确保每次启动 Linux 时都运行 "setserial" 命令。请参阅子节 启动时配置


9. 配置串行驱动程序(高级) "stty"

9.1 概述

请参阅 Stty 部分。"stty" 命令设置许多内容,例如流量控制、速度和奇偶校验。本节仅讨论流量控制。

9.2 流量控制

配置流量控制:硬件流量控制通常是最佳选择,请参阅 流量控制 以获得解释。通常最好使用硬件流量控制,而不是使用 Xon/Xoff 的软件流量控制。要使用完整的硬件流量控制,您通常必须在串口和设备之间的电缆中使用两条专用线。如果设备位于卡上或主板上,则始终可以使用硬件流量控制。

许多应用程序(和 getty 程序)为您提供了关于流量控制的选项,并将按照您的指定进行设置,或者如果您不设置,它可能会默认启用硬件流量控制。它必须同时在串行驱动程序和连接到串口的硬件中设置。它如何在硬件中设置取决于硬件。有时,您需要通过 PC 上的串口向硬件设备发送特定的“初始化字符串”。对于调制解调器,通信程序应在两个位置都设置它。

如果您使用的程序没有在串行驱动程序中设置流量控制,那么您可以使用 stty 命令自行设置。由于驱动程序在您停止 Linux 后不记得设置,您可以将 stty 命令放在启动时或您登录时运行的文件中(例如 bash shell 的 /etc/profile)。以下是为串口 ttyS2 添加硬件流量控制的内容

stty -F /dev/ttyS2 crtscts
或用于旧 stty 版本 < 1.17
stty crtscts < /dev/ttyS2

crtscts 代表使用串口的 RTS 和 CTS 引脚进行硬件流量控制的控制设置。请注意,RTS+CTS 几乎拼写为:crtscts,初始的“c”表示“控制”。


10. 串口设备 /dev/ttyS2 等

10.1 串口名称:ttyS4 等

常见的串口名称是 /dev/ttyS0、/dev/ttyS1 等。然后在 2000 年左右出现了 USB 总线,其名称类似于 /dev/ttyUSB0 和 /dev/ttyACM1(用于 USB 总线上的 ACM 调制解调器)。多端口串行卡使用稍微不同的名称(取决于品牌),例如 /dev/ttyE5。

10.2 PCI 总线

由于 DOS 为旧 ISA 总线上的 4 个串口提供了支持:COM1-COM4,或 Linux 中的 ttyS0-ttyS3,因此较新的 PCI 总线上的大多数串口都使用了更高的编号,例如 ttyS4 或 ttyS14(在内核 2.6.13 之前)。但是由于大多数 PC 仅配备一个或两个串口,ttyS0 和可能的 ttyS1(用于第二个端口),因此 PCI 总线现在可以使用 ttyS2(内核 2.6.15 及更高版本)。所有这些都允许在同一台 PC 上同时拥有 ISA 串口和 PCI 串口,而不会发生名称冲突。0-1(或 0-3)保留用于旧的 ISA 总线(或较新的 LPC 总线),2-向上(或 4-向上或 14-向上)用于 PCI,其中括号中显示了较旧的方案。不一定非得这样,但通常是这样。

如果您正在使用 udev(它仅将您计算机上的设备放入启动时的 /dev 目录中),那么有一种简单的方法可以通过编辑 /etc/udev/ 中的文件来更改设备名称。例如,要将内核检测为 ttyS3 的名称更改为您想要命名的名称:ttyS14,请将类似于以下的行添加到 /etc/udev/udev.rules
BUS=="pci" KERNEL=="ttyS3", NAME="ttyS14"

在同时具有 PCI 和 ISA 插槽的主板上的板载串口很可能仍然是 ISA 端口。即使对于全 PCI 插槽主板,串口通常也不是 PCI。相反,它们要么是 ISA,位于内部 ISA 总线上,要么位于 LPC 总线上,LPC 总线用于慢速传统 I/O 设备:串口/并口和软盘驱动器。

10.3 串口设备名称和编号

Linux 中的设备具有主设备号和次设备号。串口 ttySx (x=0,1,2, 等) 的主设备号为 4。您可以通过在 /dev 目录中键入:“ls -l ttyS*”来查看此信息(以及次设备号)。要查找各种设备的设备名称,请参阅内核文档中的“devices”文件。

以前每个串口都有一个“cua”名称,它的行为略有不同。例如,ttyS2 将对应于 cua2。它主要用于调制解调器。cua 主设备号为 5,次设备号从 64 开始。您的 /dev 目录中可能仍然有 cua 设备,但它们现在已弃用。有关详细信息,请参阅 Modem-HOWTO,章节:cua 设备已过时。

有关在设备目录中创建旧设备的信息,请参阅

在 /dev 目录中创建设备

10.4 更多关于串口名称的信息

Dos/Windows 使用 COM 名称,而来自串行驱动程序的消息使用 ttyS00、ttyS01 等。较旧的串行驱动程序 (2001 ?) 仅使用 tty00、tty01 等。

下表显示了一些串口设备名称的示例。IO 地址是旧 ISA 总线的默认地址(不是较新的 PCI 和 USB 总线的默认地址)。

dos     common                  IO       USB-BUS ( ACM => acm modem )
name     name     major minor address || common name      common name
COM1   /dev/ttyS0  4,  64;   3F8      || /dev/ttyUSB0  |  /dev/ttyACM0
COM2   /dev/ttyS1  4,  65;   2F8      || /dev/ttyUSB1  |  /dev/ttyACM1
COM3   /dev/ttyS2  4,  66;   3E8      || /dev/ttyUSB2  |  /dev/ttyACM2
COM4   /dev/ttyS3  4,  67;   2E8      || /dev/ttyUSB3  |  /dev/ttyACM3
 -     /dev/ttyS4  4,  68;   various

10.5 USB(通用串行总线)串口

有关更多信息,请参阅内核文档目录中的 usb 子目录中的文件:usb-serial、acm 等。

10.6 将 ttySN 链接到 /dev/modem

在某些安装中,将创建两个额外的设备,/dev/modem 用于您的调制解调器,/dev/mouse 用于鼠标。这两个都是指向 /dev 中相应设备的符号链接。

历史记录:以前(在 1990 年代),不鼓励使用 /dev/modem(作为指向调制解调器串口的链接),因为锁定文件可能无法意识到它实际上是 /dev/ttyS2。较新的锁定文件系统不会陷入此陷阱,因此现在可以使用此类链接。

10.7 我的 PC 背面的哪个连接器是 ttyS1 等?

检查连接器

检查连接器可能会提供一些线索,但通常不是决定性的。PC 背面的串口连接器通常是带有公针的 DB 连接器。9 针是最常见的,但有些是 25 针的(尤其是像 486 这样的旧 PC)。可能有一个 9 针(可能是 ttyS0 ??)和一个 25 针(可能是 ttyS1 ??)。对于两个 9 针连接器,顶部的那个可能是 ttyS0。

如果您在 PC 背面只有一个串口连接器,这可能很容易。如果您还有一个内置调制解调器,像 wvdial 这样的程序可能会告诉您它在哪个端口上(除非它是尚未启用的 PnP)。来自 setserial 的报告(在启动时或由您从命令行运行)应该可以帮助您识别非调制解调器端口。

如果您有两个串口,可能会更困难。您可能只有一个串口连接器,但实际上有两个端口,其中一个端口未使用(但它仍然在电子上存在)。首先检查计算机的手册(如果有)。查看连接器是否有意义的标签。您甚至可能想要取下 PC 的盖子,看看内部扁平串行电缆插入的卡上是否有任何有意义的标签。标签(如果有)可能会说“serial 1”、“serial 2”或 A、B。它实际上是哪个 com 端口将取决于跳线或 PnP 设置(有时在 BIOS 设置菜单中显示)。但 1 或 A 更可能是 ttyS0,而 2 或 B 是 ttyS1。

向端口发送字节

标签不太可能是决定性的,所以这里有另一种方法。如果串口已按照 setserial 正确配置,那么您可以向端口发送一些字节,并尝试检测它们从哪个连接器(如果有)输出。发送此类信号的一种方法是使用如下命令将长文本文件复制到端口:cp my_file_name /dev/ttyS1。当您发出复制命令后,连接到 DTR 引脚(有关引脚排列,请参阅 Serial-HOWTO)的电压表将显示正电压。

在您开始发送字节后,发送引脚应从几伏负电压变为在零电压附近波动的电压。如果不是这样(但 DTR 变为正电压),那么您已经找到了正确的端口,但它被阻止发送。这可能是由于错误的 IRQ、设置了 -clocal 等原因造成的。命令“stty -F /dev/ttyS1 -a”应显示 clocal(而不是 -clocal)。如果不是,请将其更改为 clocal。

另一个测试是将测试串口的发送和接收引脚(25 针或 9 针连接器的引脚 2 和 3)短接。然后向每个端口发送一些内容(从 PC 键盘),看看是否会发回。如果发回,则很可能是带有跳线的端口。然后移除跳线,并验证是否没有发回任何内容。请注意,如果(通过 stty)设置了“echo”,则跳线会创建一个无限循环。通过跳线的字节进入端口,然后立即从另一个引脚返回到跳线。然后它们又来回进出。您发送到端口的任何内容都会永远重复(直到您通过移除跳线等方式中断它)。这可能是测试它的好方法,因为当移除跳线时,重复的测试消息会停止。

作为跳线,您可以使用带有迷你鳄鱼夹的迷你(或微型)跳线电缆(在一些电子零件商店出售)。一小片纸可以用来防止迷你夹在不应该接触的地方进行电气接触。金属回形针有时可以弯曲用作跳线。无论您使用什么作为跳线,都要小心不要弯曲或过度刮伤引脚。要从端口接收内容,您可以转到虚拟终端(例如 Alt-F2 并登录),然后键入类似 “cp /dev/ttyS2 /dev/tty” 的内容。然后在另一个虚拟终端中,您可以通过 “echo test_message > /dev/ttyS2” 向 ttyS2(或任何设备)发送一些内容。然后返回到接收虚拟终端并查找 test_message。有关更多信息,请参阅 串口电气测试设备

将设备连接到连接器

尝试识别串口的另一种方法是将一些物理串口设备连接到它,看看它是否工作。但这里的一个问题是它可能无法工作,因为它配置不正确。如果连接了串口鼠标,则可能会在启动时检测到它。

您可以将设备(例如串口鼠标(使用 1200 波特率))放在端口上,然后使用 minicom 或 picocom 与该端口通信。然后通过单击鼠标或以其他方式使用设备发送字符,看看它们是否显示。如果没有显示,您可能告诉 picocom 错误的端口(例如 ttyS0 而不是 ttyS1),请重试。

缺少连接器

如果软件显示您拥有的串口比您拥有的连接器多(包括作为串口的内置调制解调器),那么您可能有一个没有连接器的串口。一些主板配备了没有电缆或外部串口 DB 连接器的串口。有人可能会用它组装一台 PC,并决定不使用此串口。主板上可能有一个“串口”连接器和标签,但没有扁平电缆连接到其引脚。要使用此端口,您必须获得扁平电缆和连接器。我见过此类扁平电缆的不同接线方式,因此请注意。

10.8 在 /dev 目录中创建设备

如果您不使用 devfs(它会自动创建此类设备)并且没有您需要的设备“文件”,则您必须创建它。使用 mknod 命令或 MAKEDEV shell 脚本。示例,假设您需要创建 ttyS0

linux# mknod -m 666 /dev/ttyS0 c 4 64
MAKEDEV 脚本更易于使用。请参阅其手册页。例如,如果您需要为 ttyS0 创建设备,您只需键入

linux# MAKEDEV ttyS0

如果以上命令不起作用(并且您是 root 用户),请在 /dev 目录中查找 MAKEDEV 脚本并运行它。

这会处理设备创建并应设置正确的权限。有关创建多端口设备的信息,请参阅 在 /dev 目录中创建多端口设备


11. 您应该了解的有趣程序

关于 getty 的大部分信息已移至 Modem-HOWTO,现在在 Text-Terminal-HOWTO 中可以找到一些关于将 getty 与直接连接的终端一起使用的信息。

11.1 串口监视/诊断程序

一些 Linux 程序(和一个“文件”)将监视各种调制解调器控制线,并指示它们是正电压(1 或绿色)还是负电压(0 或红色)。

截至 1998 年 6 月,我不知道 Linux 中有任何用于串口的诊断程序。

11.2 更改中断优先级

11.3 什么是 Setserial?

这部分内容在 3 个 HOWTO 中:Modem、Serial 和 Text-Terminal。根据它出现在哪个 HOWTO 中,存在一些细微的差异。

Setserial 在 linmodems、笔记本电脑上的问题

如果您有笔记本电脑 (PCMCIA),请在阅读 笔记本电脑:PCMCIA 之前不要使用 setserial

介绍

setserial 是用户用来与串行设备驱动程序通信的程序。通常,如果您仅使用 PC 标配的一个或两个串口,则永远不需要使用它。即使在其他情况下,大多数额外的串口也应该被现代内核自动检测到。除非您的内核(例如 2.2 或更旧版本)既不检测也不设置您的附加 PCI 串口,否则您需要使用 setserial,如果您有通过物理硬件上的跳线设置的旧 ISA 串口。

setserial 允许您(或 shell 脚本)与串行软件对话。但是还有另一个程序 tt/stty/,它也处理串口,用于设置端口速度等。

setserial 处理串口的较低级别配置,例如处理 IRQ(例如 5)、端口地址(例如 3f8)等。它的一个主要问题是它无法设置或配置串口硬件:它无法在硬件中设置 IRQ 或端口地址。此外,当它看似报告硬件配置时,有时是错误的,因为它实际上并没有探测硬件,除非您明确告知它这样做。即使那样,它也不会进行现代类型的总线探测,并且某些硬件可能永远不会被它找到。尽管如此,它显示的内容在大多数情况下都是正确的,但是如果您在使串口工作时遇到问题,那么很有可能是错误的。

在过去,当 IRQ 和端口地址通过串行卡上的跳线设置时,人们会使用 setserial 来告诉驱动程序这些跳线是如何设置的。如今,当即插即用方法检测到无跳线串口是如何设置的时,除非您遇到问题或使用旧硬件,否则实际上不再需要 setserial。此外,如果 setserial 使用的配置文件不正确,则会遇到麻烦。在这种情况下,如果您使用 setserial 尝试找出端口是如何配置的,它可能只会重复配置文件中的不正确信息。

setserial 有时可以帮助查找串口。但仅当您知道端口地址并使用正确的选项时才有用。对于现代端口,通常有更好的方法通过即插即用方法来查找它们。

因此,名称 setserial 有点用词不当,因为它不会在硬件中设置 I/O 地址或 IRQ,它只是在驱动程序软件中“设置”它们。驱动程序天真地相信 setserial 告诉它的内容,即使它与驱动程序使用即插即用方法找到的内容冲突。太糟糕了,它至少没有为这种冲突发出警告消息。由于设备驱动程序被认为是内核的一部分,因此在其他文档中经常使用“内核”一词,而没有提及任何“串行驱动程序”。

某些发行版(和版本)设置了某些内容,以便 setserial 在启动时由初始化 shell 脚本(在 /etc 目录树中)运行。但是此脚本使用的配置文件可能位于 /etc 树或 /var 树中。在某些情况下,如果您希望 setserial 在启动时运行,您可能需要采取一些操作。setserial 如果没有内置于内核或作为模块加载的串行支持,将无法工作。如果您(或脚本)尝试使用 setserial,则模块可能会自动加载。

虽然可以使 setserial 探测硬件 IO 端口地址以尝试确定 UART 类型和 IRQ,但这有严重的局限性。请参阅 探测。它无法在 PnP 或 PCI 串口的硬件中设置 IRQ 或端口地址(但串行驱动程序的即插即用功能可能会执行此操作)。它也不能直接读取存储在硬件配置寄存器中的 PnP 数据。但是由于设备驱动程序可以读取这些寄存器,并且 setserial 告诉您设备驱动程序的想法,因此它可能是正确的。或者它可能是在告诉您 setserial 先前(可能错误地)告诉驱动程序的内容。如果不进行其他检查,就无法确定。

串行驱动程序(对于 Linux Kernel 2.4+)查找一些“标准”传统串口、ISA 总线上的 PnP 端口以及 PCI 总线上的所有受支持端口硬件。如果它正确找到您的端口,则无需使用 setserial。驱动程序不会探测使用卡上跳线设置的旧 ISA 串口的 IRQ,并且可能会出错。

除了 setserial 的手册页之外,还可以查看 /usr/doc/setserial...//usr/share/doc/setserial 中的信息。这应该告诉您如何为您的 Linux 发行版处理 setserial。虽然 setserial 在所有发行版中的行为都相同,但用于运行它的脚本、如何配置此类脚本(包括自动配置)以及脚本文件的名称和位置等都取决于发行版。

串口模块卸载

如果卸载了串口模块,则驱动程序将忘记先前通过 setserial 所做的更改。但是,虽然驱动程序忘记了它,但发行版提供的脚本可能会将其保存在某个文件中,以便在重新加载模块时可以恢复它。

1200 或更低的慢速波特率

曾经存在慢速串行打印机(尤其是 1980 年代的旧打印机)的问题。打印程序会在打印“结束”时关闭串口,这时主内存中大型串行缓冲区中的所有字符尚未发送到打印机。结果是打印作业被截断,没有打印最后一个段落或最后一页等。

但是较新的 lprng 打印程序(以及可能的其他打印程序)会保持端口打开,直到打印完成,因此“问题已解决”,即使您使用的是旧式打印机。Setserial 可以修改端口在关闭后保持运行的时间(以便输出主 RAM 缓冲区中仍然存在的任何字符)。这是通过 setserial 手册页中的 "closing_wait" 选项完成的。对于过早关闭端口的“不良”软件,如果在 1200 以上的速度下存在大量“流量控制”等待,也可能需要它。

给出 setserial 命令

请记住,setserial 无法在硬件中设置任何 I/O 地址或 IRQ。这要么由(驱动程序运行的)即插即用软件完成,要么由传统串口的跳线完成。即使您通过 setserial 向驱动程序提供 I/O 地址或 IRQ,它也不会设置这些值,而是假定它们已经设置。如果您给它错误的值,串口将无法正常工作(如果可以工作)。

对于传统端口,如果您知道 I/O 地址但不知道 IRQ,您可以命令 setserial 尝试确定 IRQ。

您可以通过仅键入 setserial 而不带任何参数来查看可能的命令列表。这无法显示单字母选项,例如 -v(用于 verbose),您通常应该在进行故障排除时使用它。请注意,setserial 将 IO 地址称为“端口”。如果您键入

setserial -g /dev/ttyS*
您将看到一些关于设备驱动程序如何为您的端口配置的信息。在许多情况下,您会看到一些端口显示的信息乍一看似乎是错误的 IRQ 和地址。但是,如果您还看到:"UART: unknown",则只需忽略整行,因为该地址上不存在串口。

如果您在 -g 选项中添加 -a,您将看到更多信息,尽管很少有人需要处理(或理解)这些额外信息,因为您看到的默认设置通常工作良好。在正常情况下,硬件的设置方式与 “setserial” 报告的方式相同。但是,如果您遇到问题,则很有可能是 setserial 报告有误。实际上,您可以运行 “setserial” 并分配一个纯粹虚构的 I/O 端口地址、任何 IRQ 以及您想要的任何 uart 类型。然后,下次您键入 “setserial ...” 时,它将显示您提供给驱动程序的这些虚假值。它们也将被正式注册到内核中,如 “scanport” 命令(Debian)在屏幕顶部显示的那样。当然,如果您尝试使用这样的端口,串行端口驱动程序将无法正常工作(如果还能工作的话)。因此,在给 setserial 提供参数时,“一切皆有可能”。好吧,几乎是。如果您为一个端口分配一个已经分配的基地址(例如 3e8),它可能不会接受。但是如果您使用 3e9,它会接受。不幸的是,3e9 实际上已被分配,因为它在以基地址 3e8 开头的范围内。因此,这个故事的寓意是,在使用 setserial 分配资源之前,请确保您的数据是正确的。

配置文件

虽然通过 setserial 所做的分配在 PC 关机时会丢失,但配置文件可能会在 PC 重新启动时恢复它们。在较新版本中,您通过 setserial 更改的内容可能会自动保存到配置文件中。当 setserial 运行时,它会使用来自配置文件的信息。

此配置文件位于何处取决于您的发行版。查看 /etc/ 树中的某个位置(例如 /etc/init.d/ 或 /etc/rc.d/)的启动脚本,并阅读 “serial” 或 “setserial” 或类似的启动脚本。它应该显示配置文件所在的位置。在 Debian 中,有 4 个选项可用于此配置文件

  1. 完全不使用此文件。在每次启动时,仅串行驱动程序检测端口,而 setserial 永远不会运行。(“kernel” 选项)
  2. 保存系统首次关机时 setserial 报告的内容,并将其放入配置文件中。之后,即使有人通过在命令行上运行 setserial 命令进行更改,然后在系统关机,也永远不要对配置文件进行任何更改。(“autosave-once” 选项)
  3. 在每次关机时,将 setserial 检测到的任何内容保存到配置文件。(“autosave” 选项)
  4. 手动编辑配置文件以设置配置。永远不要对其进行任何自动保存。(“manual” 选项)

在过去(可能在 2000 年之前),没有任何配置文件,配置是手动设置(硬编码)在运行 setserial 的 shell 脚本中的。请参阅 编辑脚本(版本 2.15 之前)

探测

只有当您怀疑端口已被启用(通过 PnP 方法、BIOS、跳线等)时,才使用 setserial 探测端口。否则,setserial 探测永远不会找到它,因为它的地址不存在。问题在于软件在指定的 I/O 地址查找端口。在用 “setserial” 探测之前,可以运行 “scanport”(Debian)命令来一次扫描所有可能的端口。它可以粗略地猜测某些端口上是什么,但不能确定 IRQ。这是一个快速的初步开始。它可能会使您的 PC 挂起,但到目前为止,它对我来说工作正常。请注意,非 Debian 发行版似乎不提供 “scanport”。是否有其他扫描程序?

使用适当的选项,setserial 可以(在给定的 I/O 地址)探测串行端口,但您必须猜测 I/O 地址。例如,如果您要求它探测 /dev/ttyS2,它将仅在其认为 ttyS2 所在的地址(2F8)进行探测。如果您告诉 setserial ttyS2 位于不同的地址,那么它将在该地址进行探测,等等。请参阅 探测

这种探测的目的是查看那里是否有 uart,如果有,它的 IRQ 是什么。主要在最后手段时使用 setserial,因为有更快的方法来尝试,例如 wvdialconf 检测调制解调器、查看非常早期的启动时消息,或使用 pnpdump --dumpregs 或 lspci -vv。但是,如果您想使用 setserial 检测硬件,请使用例如
setserial /dev/ttyS2 -v autoconfig
如果结果消息显示 uart 类型,例如 16550A,那么您就没问题。如果相反,它显示 uart 类型为 “unknown”,那么据推测在该 I/O 地址根本没有串行端口。一些廉价的串行端口无法正确识别自己,因此如果您看到 “unknown”,那里仍然可能有一个串行端口。

除了自动探测 uart 类型外,setserial 还可以自动探测 IRQ,但这也不总是正常工作。在一种情况下,它首先给出了错误的 irq,但是当重复该命令时,它找到了正确的 irq。在 setserial >= 2.15 的版本中,您上次探测测试的结果可以自动保存并放入特定于发行版的配置文件中,例如 Debian 的 /etc/serial.conf/etc/sysconfig/serial/var/lib/setserial/autoserial.conf。这将在您下次启动 Linux 时使用。

可能两个串行端口在硬件中都设置了相同的 IO 地址。当然,对于 ISA 总线,这通常是不允许的,但有时仍然会发生。当实际上有两个串行端口时,探测只检测到一个串行端口。但是,如果它们具有不同的 IRQ,则 IRQ 探测可能会显示 IRQ = 0。对我来说,只有在我首先使用 setserial 给 IRQ 一个虚构值时才会发生这种情况。

启动时配置

虽然 setserial 可能会通过初始化脚本运行,但当串行模块加载时(或者当内核启动内置串行驱动程序(如果已编译到内核中)时),类似于 setserial 的东西也会更早运行。因此,当您在屏幕上观看启动时消息时,看起来它运行了两次,而实际上确实如此。

如果第一个消息是针对旧端口的,则显示的 IRQ 可能不正确,因为它没有探测 IRQ。如果存在第二个串行端口报告,则可能是 /etc/init.d/setserial 等脚本的结果。它通常不进行探测,因此可能对硬件的实际设置方式是错误的。它仅显示保存在配置文件中的配置数据。在 setserial 2.15 之前的旧方法是将此类数据直接手动写入脚本。

当内核加载串行模块时(或者如果“模块等效物”内置于内核中),则会检测到所有受支持的 PnP 端口。对于旧式(非 PnP)端口,仅自动检测 ttyS{0-3},并且驱动程序设置为仅使用 IRQ 4 和 3(无论硬件中实际设置了哪些 IRQ)。不进行 IRQ 探测,但可以手动执行此操作。您会在启动时消息中看到这一点,就像运行了 setserial 一样。

为了纠正 IRQ 中可能的错误(或出于其他原因),可能存在一个脚本文件运行 setserial。不幸的是,如果此文件中的某些 IRQ 错误,内核仍将具有有关 IRQ 的不正确信息。此文件通常是在启动时完成的初始化的一部分。它是否运行取决于您(和/或您的发行版)如何设置。它也可能取决于运行级别。

在修改配置文件之前,您可以通过在命令行上键入 “proposed” setserial 命令来测试它。在某些情况下,当您关机时,使用 setserial 的结果将自动保存到某个位置,例如 /etc/serial.conf(或 autoserial.conf 或 serial)。因此,如果它工作正常(并解决了您的问题),则无需修改任何配置文件。请参阅 使用 /etc/serial.conf 等的配置方法

编辑脚本(版本 2.15 之前需要)

这是在 setserial 2.15 (1999) 之前完成的方式。目标是修改(或创建)/etc 树中的一个脚本文件,该文件在启动时运行 setserial。大多数发行版都提供了这样的文件(但它最初可能不在 /etc 树中)。

因此,在版本 2.15 (1999) 之前,它更简单。您所做的只是编辑脚本。没有 /etc/serial.conf 文件(或类似文件)来配置 setserial。因此,您需要找到在启动时运行 “setserial” 的文件并对其进行编辑。如果它不存在,您需要创建一个(或将命令放在在启动时早期运行的文件中)。如果当前正在使用这样的文件,则很可能在 /etc 目录树中的某个位置。但是 Redhat <6.0 在 /usr/doc/setserial/ 中提供了它,但在使用它之前,您需要将其移动到 /etc 树。

脚本 /etc/rc.d/rc.serial 过去经常使用。Debian 发行版使用 /etc/rc.boot/0setserial。曾经使用过的另一个文件是 /etc/rc.d/rc.local,但它可能没有足够早地运行。据报告,其他进程可能会在 rc.local 运行之前尝试打开串行端口,从而导致串行通信失败。后来,它很可能在 /etc/init.d/ 中找到,但通常不打算对其进行编辑。

如果提供了这样的文件,它很可能包含许多注释掉的示例。通过取消注释其中一些和/或修改它们,您可以正确地设置事情。重要的是使用 setserial 的有效路径和有效的设备名称。您可以手动执行此文件(只需以超级用户身份键入其名称)来进行测试,以查看它是否工作正常。像这样的测试比重复重启以使其正确要快得多。

对于 >= 2.15 版本(前提是您的发行版实现了更改,Redhat 最初没有),可能更棘手,因为在启动时运行 setserial 的文件 /etc/init.d/setserial 或类似文件不打算由用户编辑。请参阅 使用 /etc/serial.conf 等的配置方法

此类脚本中的一个示例行是

/sbin/setserial /dev/ttyS3 irq 5 uart 16550A  skip_test

或者,如果您希望 setserial 自动确定 ttyS3 的 uart 和 IRQ,您将使用类似这样的内容

/sbin/setserial  /dev/ttyS3 auto_irq skip_test autoconfig

这是为每个您想要自动配置的串行端口完成的,使用在您的机器上真实存在的设备名称。在某些情况下,由于硬件原因,它无法正常工作。

使用 /etc/serial.conf 等的配置方法

在 setserial 版本 2.15 (1999) 之前,配置 setserial 的方法是手动编辑在启动时运行 setserial 的 shell 脚本。请参阅 编辑脚本(版本 2.15 之前)。这很简单,但是简单明了的方法已更改为不必要的复杂方法。如今,脚本和配置文件是两个不同的文件,而不是一个文件。这个 shell 脚本没有被编辑,而是从配置文件(例如 /etc/serial.conf(或 /var/lib/setserial/autoserial.conf))中获取其数据。

此外,您甚至可能不需要编辑 serial.conf(或类似文件),因为在命令行上使用 “setserial” 命令可能会自动导致 serial.conf 被适当地编辑。这样做是为了让您可能不需要编辑任何文件即可设置(或更改)setserial 每次在 Linux 启动时执行的操作。

经常发生的情况是:当您关闭 PC 时,在启动时运行 “setserial” 的脚本会再次运行,但这次它只执行 “stop” 情况的部分所说的操作:它使用 “setserial” 找出 “setserial” 的当前状态,并将该信息放入串行配置文件中,例如 serial.conf。因此,当您运行 “setserial” 来更改 serial.conf 文件时,它不会立即更改,而只会在您正常关机时才会更改。

现在您可能可以猜到可能出现什么问题。假设您没有正常关机(有人关闭电源等),并且更改未保存。假设您使用 “setserial” 进行实验,并且忘记最后一次运行它以恢复原始状态(或在恢复原始状态时犯了错误)。然后,您的 “实验性” 设置将被保存。最糟糕的是,除非您知道配置文件中设置了哪些选项,否则您不知道会发生什么。Debian(以及可能的其他发行版)中的一个选项称为 “AUTOSAVE-ONCE”,它仅在您首次使用 setserial 命令进行更改时保存更改。

如果设置了选项 “###AUTOSAVE###” 并且您手动编辑 serial.conf,那么您的编辑将在您关机时被破坏,因为它会被更改回关机时 setserial 的状态。有一种方法可以禁用在关机时更改 serial.conf,即从 serial.conf 的第一行删除 “###AUTOSAVE###” 或类似的行。在 Debian 发行版中,首次安装后首次关机后,从第一行删除 “###AUTOSAVE###” 曾经是自动完成的。为了保留这种效果,创建了 “AUTOSAVE-ONCE” 选项,该选项仅在系统首次关机时(就在您安装或更新 setserial 程序之后)执行保存。

现在最常用于在启动时(根据配置文件)运行 setserial 的文件是 /etc/init.d/setserial (Debian) 或 /etc/init.d/serial (Redhat),或其他,但通常不应编辑它。对于 2.15,Redhat 6.0 只有一个文件 /usr/doc/setserial-2.15/rc.serial,如果您希望 setserial 在启动时运行,则必须将其移动到 /etc/init.d/。

要禁用端口,请使用 setserial 将其设置为 “uart none”。这将不会被保存。/etc/serial.conf 的格式似乎与在命令行上的 “setserial” 之后放置的参数的格式相同,每个端口一行。如果您不使用 autosave,您可以手动编辑 /etc/serial.conf。

为了强制将 setserial 设置的当前设置保存到配置文件 (serial.conf) 而无需关机,请执行通常在您关机时发生的操作:运行 shell 脚本 /etc/init.d/{set}serial stop。“stop” 命令将保存当前配置,但串行端口仍保持正常工作。

在某些情况下,您可能会最终安装了旧的和新的配置方法,但希望只有其中一种方法在启动时运行。Debian 将过时的文件标记为 “...pre-2.15”。

IRQ

默认情况下,ttyS0 和 ttyS2 将共享 IRQ 4,而 ttyS1 和 ttyS3 共享 IRQ 3。但是,虽然共享串行中断(在运行程序中使用它们)对于 PCI 总线来说是可以的,但对于 ISA 总线来说是不允许的,除非您:1. 拥有内核 2.2 或更高版本,并且 2. 您已编译支持此功能,并且 3. 您的串行硬件支持它。请参阅

中断共享和内核 2.2+

如果您只有两个串行端口,ttyS0 和 ttyS1,您仍然没问题,因为非现有设备不存在 IRQ 共享冲突。

如果您添加旧式内部调制解调器(没有即插即用)并保留 ttyS0 和 ttyS1,那么您应该尝试找到一个未使用的 IRQ 并在您的串行端口(或调制解调器卡)中设置它,然后使用 setserial 将其分配给您的设备驱动程序。如果 IRQ 5 未用于声卡,则可以将其用于调制解调器。

笔记本电脑:PCMCIA

如果您有笔记本电脑,请阅读 PCMCIA-HOWTO 以获取有关串行配置的信息。对于主板上的串行端口,setserial 的使用方式与台式机相同。但是对于 PCMCIA 卡(例如调制解调器)来说,情况就不同了。PCMCIA 系统的配置应自动运行 setserial,因此您无需运行它。如果您运行它(通过脚本文件或 /etc/serial.conf),它可能会有所不同并导致问题。serial.conf 的自动保存功能不应保存 PCMCIA 卡的任何内容(但 Debian 在 2.15-7 之前是这样做的)。当然,始终可以使用 setserial 来了解驱动程序如何配置 PCMCIA 卡。

11.4 Stty

介绍

stty 完成了串行端口的大部分配置,但由于应用程序(和 getty 程序)通常会处理此问题,因此您可能不需要经常使用它。如果您遇到问题或想查看端口的设置方式,它会很方便。尝试在您的终端/控制台中键入 ``stty -a'' 以查看当前的设置方式。也尝试在不使用 -a(全部)的情况下键入它,以获得一个简短的列表,其中显示了它与 “normal” 设置方式的不同之处, “normal” 设置方式是使用命令 "stty sane" 设置的。不要尝试学习所有设置,除非您想成为串行历史学家,因为许多设置仅适用于 1970 年代的慢速老式哑终端。大多数默认设置应该工作正常。

stty 在手册页中有所记录,信息页中有更详细的说明。键入 "man stty""info stty"

许多 stty 选项以 “o”(输出)或 “i”(输入)开头。例如:onlcr。输出是字节从计算机流出的过程,而输入是字节流入计算机的过程。“视角”是计算机,而不是串行端口或连接到串行端口的设备。例如,接收到的输入数据通过电缆进入,并到达串行端口芯片。该芯片在将来自串行的位转换为并行表示后,然后将其(通过程序读取)发送到主计算机内存中的大型串行端口缓冲区。因此,该芯片既有输入又有输出,但由于它是计算机的输入数据,因此其输出被视为输入。输出流经此芯片的情况类似。“输入” 和 “输出” 是指相对于计算机而不是串行端口硬件(芯片)的流动方向。

setserial 仅处理实际的串行端口,而 stty 既用于串行端口,也用于虚拟终端,例如 PC 监视器上的标准 Linux 文本界面。对于 PC 监视器,许多 stty 设置都是没有意义的。更改波特率等似乎实际上没有任何作用。

以下是 stty 配置的一些项目:速度(位/秒)、奇偶校验、位/字节、停止位数、剥离第 8 位?、调制解调器控制信号、流控制、中断信号、行尾标记、更改大小写、填充、缓冲区溢出时发出蜂鸣声?、将您键入的内容回显到屏幕、允许后台任务写入终端?、定义特殊(控制)字符(例如按下哪个键进行中断)。请参阅 stty 手册页或信息页以获取更多详细信息。另请参阅手册页:termios,其中涵盖了 stty 设置的相同选项,但(截至 1999 年中期)涵盖了 stty 手册页未提及的功能。

在某些 getty 实现(getty_ps 包)中,通常会给 stty 的命令会键入到 getty 配置文件中:/etc/gettydefs。即使没有此配置文件,getty 命令行也可能足以进行设置,以便您不需要 stty。

可以编写 C 程序来更改 stty 配置等。查看其中一些文档可能有助于更好地理解 stty 命令(及其许多可能的参数)的用法。Serial-Programming-HOWTO 可能有用,但它已过时。手册页:termios 包含对 C 语言结构(类型为 termios)的描述,该结构将 stty 配置存储在计算机内存中。此 C 结构中的许多标志名称几乎与 stty 命令的参数相同(并且执行相同的操作)。

流控制选项

要设置硬件流控制,请使用 “crtscts”。对于软件流控制,有 3 个设置:ixon、ixoff 和 ixany。

ixany:主要用于终端。在流控制停止后,按任意键将重新启动流。如果您使用 “stop scroll” 键(或类似的键)停止滚动,则按任意键将恢复滚动。它很少需要,因为再次按下 “scroll lock” 键将执行相同的操作。

ixon:使端口能够监听 Xoff 并在其收到 Xoff 时停止传输。同样,如果它收到 Xon,它将恢复传输。

ixoff:使端口能够在主内存中的缓冲区几乎满时,向传输线发送 Xoff 信号。它可以保护端口所在的设备免受溢出。

对于连接到快速 PC 的慢速哑终端(或其他慢速设备),PC 的端口不太可能被溢出。因此,您很少真正需要启用 ixoff。但它通常启用 “以防万一”。

在 “外部” 终端使用 stty

如何使用 stty 查看或设置您当前正在使用的终端以外的终端?如果外部终端正在使用并且在其上运行 shell,则通常无法执行此操作。在其他情况下,例如在另一个终端(例如 tty1)键入时处理 ttyS2,请使用 stty -F /dev/ttyS2 ...(或 --file 而不是 F)。如果 ... 是 -a,它将显示所有 stty 设置(-a 表示全部)。

但是,如果外部终端(本例中为 ttyS2)在其上运行 shell,那么您看到的内容很可能是具有欺骗性的,并且尝试设置它将不起作用。虚拟终端也存在此问题,例如从 tty1 处理 tty3 等。请参阅 终端上的两个接口 以了解它。

终端上的两个接口

当使用启用命令行编辑的 shell(例如 bash)时,存在两个不同的终端接口(当您键入 stty -a 时看到的内容)。当您在现代 shell 中在命令行中键入内容时,您有一个临时的 “raw” 接口(或原始模式),其中每个字符在您键入时都会被命令行编辑器读取。一旦您按下 <return> 键,命令行编辑器就会退出,并且终端接口会更改为终端的标称 “cooked” 接口(熟模式)。此熟模式会持续到下一个提示符发送到终端(这只是很短的时间)。请注意,永远不会在这种熟模式下键入任何命令,但是在熟模式下,shell 会读取在命令行上的原始模式下键入的内容。

当提示符发送到终端时,终端从 “熟” 模式变为 “原始” 模式(就像您启动编辑器(例如 vim)时一样。提示符表示启动命令行编辑器。“原始” 模式的设置仅基于从 “熟” 模式获取的基本 stty 设置。“原始” 模式保留这些设置,但会更改其他几个设置,以便将模式更改为 “原始”。它根本不是基于先前 “原始” 模式中使用的设置。因此,如果有人使用 stty 来更改原始模式的设置,则一旦有人在据称已 “设置” 的终端上按下 <return> 键,此类设置将永久丢失。

现在,当有人键入 stty 以查看终端接口时,可能会获得熟模式或原始模式的视图。您需要弄清楚您正在查看哪一个。如果您从外部终端(而不是您当前正在键入的终端)使用 stty,那么您将看到原始模式设置。所做的任何更改都只会应用于原始模式,并且当有人在您尝试 “设置” 的外部终端上按下 <return> 时将丢失。但是,如果您键入 stty 命令来查看/更改您正在使用的终端的配置,然后按下 <return>,情况就不同了。<return> 将终端置于熟模式。您的更改已保存,并且当终端返回到原始模式时,它们仍然存在(当然,除非它是原始模式不允许的设置)。

这种情况可能会造成问题。例如,假设您损坏了您的终端接口。要恢复它,您可以转到另一个终端并 “stty -F dev/ttyS1 sane”(或类似的)。它将不起作用!当然,您可以尝试在已损坏的终端上键入 “stty sane ...”,但您看不到您键入的内容。以上所有内容不仅适用于哑终端,而且也适用于 PC 监视器上使用的虚拟终端以及 X 中的终端窗口。换句话说,它适用于几乎每个使用 Linux 的人。

幸运的是,当您启动 Linux 时,任何在启动时运行 stty 的文件都可能处理没有 shell 在其上运行的终端(或没有终端的串行端口),因此对于这种特殊情况没有问题。

将 stty 命令放在哪里?

如果您需要每次计算机启动时都让 stty 设置串行接口,那么您需要将 stty 命令放在每次计算机启动时都会执行的文件中(Linux 启动)。它应该在串行端口被使用之前运行(包括在端口上运行 getty)。有很多可能的地方可以放置它。如果它被放在多个位置,而您只知道(或记得)其中一个位置,那么很可能会发生冲突。因此,请务必记录您所做的事情。

一个放置它的位置是与系统启动时运行 setserial 的文件相同的文件。位置取决于发行版和版本。最好将其放在 setserial 命令之后,以便首先完成低级操作。如果您在 /etc 树中有目录,其中每个文件都在启动时执行(System V Init),那么您可以为此目的创建一个名为 “stty” 的文件。

过时的重定向方法

在 2000 年左右之前,如果您想在外部终端上使用 stty,则需要使用重定向运算符 “<”。例如,要在 tty1 上坐在 ttyS2 上使用 stty,您可以键入:stty .... < /dev/ttyS2。在 2000 年之后(前提是您的 setserial 版本 >= 1.17 且 stty >= 2.0),创建了一种更好的方法,即使用 -F 选项:stty -F /dev/ttyS2。当旧的重定向方法失败时,这将起作用。

上面的旧重定向示例使 ttyS2 成为 stty 的标准输入。这为 stty 程序提供了指向 “文件” ttyS2 的链接,以便它可以 “读取” 它。但是,它没有像人们可能期望的那样读取发送到 ttyS2 的字节,而是使用该链接来查找端口的配置设置,以便它可以读取或更改它们。在过去,有些人尝试使用 ``stty ... > /dev/ttyS2'' 来设置终端。这不起作用。相反,它获取 stty 命令为终端(例如 tty1)正常显示的消息,并将此消息发送到 ttyS2。但它不会更改 ttyS2 的任何设置。

这是旧重定向运算符的一个问题(如果您改用较新的 -F 选项,则不会发生这种情况)。有时,当尝试使用 stty 时,命令会挂起并且没有任何反应(即使在按下 <return> 后,您也不会获得下一个命令的提示符)。这很可能是由于端口卡住,因为它正在等待其中一个调制解调器控制线被置为有效。例如,除非您已设置 “clocal” 以忽略调制解调器控制线,否则如果没有断言 CD 信号,端口将不会打开,并且 stty 将无法用于它(除非您使用较新的 -F 选项)。硬件流控制似乎也存在类似的情况。如果端口的电缆甚至没有用于需要断言的引脚的导体,那么就没有简单的方法可以阻止挂起。

摆脱上述挂起的一种方法是使用较新的 -F 选项并根据需要设置 “clocal” 和/或 “crtscts”。如果您没有 -F 选项,那么您可以尝试在端口上运行一些程序(例如 minicom),这将强制其运行,即使控制线说不要运行。然后,希望该程序可能会设置端口,以便将来不需要控制信号即可打开:clocal 或 -crtscts。要使用 “minicom” 执行此操作,您可能必须重新配置 minicom,然后退出并重新启动它。与其如此麻烦,不如简单地重新启动 PC,或者通过使用虚拟终端杀死进程,使用 “top”(或 “ps” 获取进程号,然后使用 “kill” 杀死该进程)。

过时的重定向方法(在更高版本中仍然有效)是键入 ``stty ... < /dev/ttyS2''。如果使用 -F 的新方法有效,但过时的方法挂起,则意味着端口由于调制解调器控制线未被断言而挂起。因此,过时的重定向方法可能仍然对故障排除有用。

11.5 什么是 isapnp?

isapnp 是一个程序,用于在 ISA 总线上配置即插即用 (PnP) 设备,包括内置调制解调器。它包含在一个名为 "isapnptools" 的软件包中,并包含另一个程序 "pnpdump",该程序可以查找您所有的 ISA PnP 设备,并以一种可以添加到 PnP 配置文件 /etc/isapnp.conf 中的格式显示配置它们的选项。isapnp 命令可以放入启动文件中,以便在每次启动计算机时运行,从而配置 ISA PnP 设备。即使您的 BIOS 不支持 PnP,它也能够做到这一点。请参阅 Plug-and-Play-HOWTO。

11.6 通过串口连接两台 PC

这里您需要将一条串口线(交叉类型 = Null 调制解调器类型)连接到两台 PC 的串口之间。然后如何使用这条线路呢?一种方法是在一台 PC 上在串口线上运行登录程序,并在另一台 PC 上运行例如 minicom 或 picocom 来模拟终端。请参阅 Text-Terminal-HOWTO。在这种情况下,没有使用网络协议,也没有错误检测。

另一种方法是在线路运行网络协议。例如,要将 PPP 与 TCP/IP 结合使用,请参阅 Serial Laplink HOWTO。尽管该 HOWTO 没有提及旧程序 "slattach"(串行线路连接),但它可以将串行线路置于使用您选择的协议的网络模式。slattach 的协议包括 PPP 或 SLIP(一种比 PPP 更早广泛使用的协议)。

Debian 软件包 net-tools 包含了 slattach。SLIP 以内核模块的形式提供,也可以构建到内核中(2.2、2.4 或 2.6)。

11.7 将串口连接到快速网络:ser2net

ser2net 是一个 Linux 程序,它将网络连接到串口。例如,有人通过以太网端口或使用例如 telnet 的快速调制解调器连接到您的 PC。然后(没有 ser2net),他们可以远程登录到您的 PC,然后在您的 PC 上运行使用 PC 上串口的程序。但是,如果他们不需要登录和使用您的软件,而是可以立即连接到串口,这可能会更好。在您的 PC 上运行的 ser2net 可以实现这一点。

它可以像以太网电缆和串口电缆之间的桥梁。以太网电缆上会有 TCP/IP 协议,而串口只会取出 TCP/IP 数据包中的原始数据。可选地,您也可以在串口线上使用 TCP/IP 数据包。由于以太网端口具有高带宽,它可以同时与多个串口通信,并且也可以在其他地方进行数据流动。

要设置 ser2net,您必须指定哪些网络端口(在以太网上)将连接到哪些串口。然后,当网络数据包通过以太网到达您的 PC,并且这些数据包寻址到您已绑定到串口的网络端口时,这些数据包中的数据将流向串口。反之亦然。当然,网络不必是以太网。它可以是电缆调制解调器或 DSL 线路等。


12. 速度(流速)

我们所说的“速度”实际上是指“数据流速”,但几乎每个人都错误地称之为速度。速度以位/秒(或波特)为单位衡量。速度使用 "stty" 命令或使用串口的程序设置。请参阅 Stty

12.1 非常高的速度

超过 115.2kbps 的速度

自 1990 年代中期以来,115.2k 的最高速度一直是标准。但是到 2000 年,大多数新的串口都支持更高的速度,如 230.4k 和 460.8k。有些还支持 921.6k。不幸的是,由于缺少驱动程序,Linux 很少使用这些速度。因此,除非通过特殊软件启用更高的速度,否则这些端口的行为就像 115.2k 端口一样。要获得这些速度,您需要使用特殊补丁编译内核,或使用模块,直到支持内置到内核的串口驱动程序中。

不幸的是,串口制造商从未就支持高速的标准方式达成一致,因此串口驱动程序需要支持各种硬件。一旦启用高速,选择它的标准方法是将 baud_base 设置为最高速度(使用 setserial)(除非串口驱动程序为您执行此操作)。然后,软件将使用 1 的除数来设置最高速度。所有这些有望在 2003 年的某个时候得到 Linux 内核的支持。

w83627hf 芯片(用于许多主板,如 Tyan S2460)的驱动程序位于 https://www.muru.com/linux/w83627hf/

一些制造商实现高速的一种非标准方法是使用非常大的除数来获得高速。这个数字实际上根本不是除数,因为它不除以任何东西。它只是充当一个代码编号,告诉硬件要使用的速度。在这些情况下,您需要使用特殊补丁编译内核。

支持第二种类型高速硬件的一个补丁称为 shsmod(超高速模式)。该补丁有 Windows 和 Linux 版本。请参阅 http://www.devdrv.com/shsmod/。还有一个用于 VIA VT82C686 芯片的模块 http://www.kati.fi/viahss/。使用它可能会导致缓冲区溢出。

对于内置调制解调器,只有少数制造商宣传它们支持超过 115.2k 的速度用于其内置串口。shsmod 是否支持这些?

速度如何在硬件中设置:除数和 baud_base

速度的设置是通过改变串口时钟的频率来实现的。但是这种改变不是通过实际改变驱动时钟的振荡器的频率来实现的,而是通过“除以”时钟的频率来实现的。例如,要除以 2,只需忽略每隔一个时钟滴答。这将速度减半。除以 3 使时钟以 1/3 的频率运行,依此类推。因此,为了减慢时钟速度(意味着设置速度),我们只需向时钟发送一个除数。它由串口驱动程序发送到端口中的寄存器。因此,速度是由除数设置的。

如果时钟以 115,000 bps(常见)的最高速度运行,那么以下是各种速度的除数(假设最高速度为 115,200):1 (115.2k), 2 (57.6k), 3 (38.4k), 6 (19.2k), 12 (9.6k), 24 (4.8k), 48 (2.4k), 96 (1.2k) 等。串口驱动程序通过仅向硬件发送一个“除数”(一个正整数)来设置硬件中的速度。这个“除数”除以硬件的“最高速度”,从而产生较慢的速度(除了除数 1 显然告诉硬件以最高速度运行)。

以上情况存在例外,因为对于某些串口硬件,高于 115.2k 的速度是通过使用非常高的除数来设置的。在您阅读本节的其余部分时,请记住这个例外。通常,如果您指定 115.2k 的速度(在您的通信程序中或通过 stty),那么串口驱动程序会将端口硬件设置为除数 1,这将设置最高速度。

除了使用非常高的除数来设置高速外,传统的做法如下:如果您碰巧有硬件的最大速度为 230.4k(并且 230.4k 速度已在硬件中启用),那么指定 115.2k 将导致除数 1。对于某些硬件,这实际上会给您 230.4k。这是您设置速度的两倍。事实上,对于您设置的任何速度,实际速度都将是两倍。如果您有可以以 460.8k 运行的硬件,那么实际速度将是您设置速度的四倍。以上所有假设您不使用 “setserial” 来修改任何内容。

设置除数,速度计算

为了纠正这种计算(但并非总是解决问题),您可以使用 “setserial” 将 baud_base 更改为您端口的实际最大速度,例如 230.4k。然后,如果您将速度(通过您的应用程序或通过 stty)设置为 230.4k,将使用除数 1,您将获得与您设置的速度相同的速度。

如果您有非常旧的软件,不允许您告诉它如此高的速度(但您的硬件已启用),那么您可能需要考虑使用 “spd_cust” 参数。这允许您告诉应用程序速度为 38,400,但这种情况下的实际速度由 “divisor” 的值决定,该值也在 setserial 中设置。我认为最好尽量避免使用这种权宜之计。

有些品牌的 UART 使用非常高的除数来设置高速。没有任何令人满意的方法可以使用 “setserial”(例如设置 “divisor 32770”)来获得这样的速度,因为这样 setserial 会认为速度非常低,并禁用 UART 中的 FIFO。

晶振频率高于 baud_base

请注意,baud_base 设置通常远低于晶体振荡器的频率,因为例如 1.8432 MHz 的晶体频率在硬件中除以 16 以获得 115.2k 的实际最高速度。晶体频率需要更高的原因是,这种高晶体速度可以生成时钟滴答,以采集每个比特的多个样本,从而确定它是 1 还是 0。

实际上,1.8432 MHz 的 “晶体频率” 可以通过将 18.432 MHz 的晶体振荡器除以 10 获得,然后再馈送到 UART。其他方案也是可能的,只要 UART 运行正常即可。

12.2 更高的串口吞吐量

如果您在具有 (E)IDE 磁盘驱动器的系统上看到吞吐量缓慢和串口溢出,您可以获取 hdparm。这是一个实用程序,可以修改 (E)IDE 参数,包括在磁盘 IRQ 期间取消屏蔽其他 IRQ。这将提高响应速度,并有助于消除溢出。请务必仔细阅读手册页,因为某些驱动器/控制器组合不喜欢这样做,可能会损坏文件系统。

还可以看看一个名为 irqtune 的实用程序,它可以更改设备(例如您的调制解调器所在的串口)的 IRQ 优先级。这可能会提高您系统上的串口吞吐量。irqtune 的 FAQ 位于 http://www.best.com/~cae/irqtune


13. 锁定以防止他人使用

13.1 简介

当您使用串口时,您可能希望阻止其他人在同一时间使用它。但是,在某些情况下,您可能希望其他人使用它,例如,如果您正在使用文本终端,则向您发送重要消息。

有多种方法可以防止其他用户(或其他进程)在您使用串口时使用它(锁定)。这一切都应该自动发生,但如果它给您带来麻烦,了解这一点很重要。如果程序异常退出或 PC 突然关闭(通过拔掉插头等),您的串口可能会最终被锁定。即使锁仍然存在,当您想再次使用串口时,它通常也会自动移除。但在极少数情况下,情况并非如此。那时您需要了解发生了什么。

实现锁定的一种方法是设计内核来处理它,但到目前为止,Linux 一直避开这种解决方案(除了涉及 cua 设备的情况,该设备现在已过时)。Linux 使用的两种解决方案是:

  1. 创建锁文件
  2. 修改设备(如 /dev/ttyS2)的权限和/或所有者

13.2 锁文件

如果您使用新的设备文件系统 (devfs),请参阅下一节。锁文件只是一个创建的文件,表示特定设备正在使用中。它们保存在 /var/lock 中。以前它们在 /usr/spool/uucp 中。Linux 锁文件通常命名为 LCK..name,其中 name 可以是设备名称、进程 ID 号、设备的 major 和 minor 号,或 UUCP 站点名称。大多数进程(getty 是一个例外)创建这些锁,以便它们可以独占访问设备。例如,如果您使用调制解调器拨出,将出现一些锁文件,告诉其他进程其他人正在使用调制解调器。在较旧的版本(1990 年代)中,每个进程通常只有一个锁文件。锁文件包含已锁定设备的进程的 PID。请注意,如果进程坚持使用已锁定的设备,它可能会忽略锁文件并仍然使用该设备。这在向文本终端发送消息等情况下很有用。

当程序想要使用串口但发现它被锁文件锁定时,它应该检查锁文件的 PID 是否仍在被使用。如果不是,则表示锁已过时,可以继续使用该端口(在删除过时的锁文件之后)。不幸的是,可能有一些程序不这样做,并且会放弃,告诉您设备已被使用,但实际上并非如此。

如果锁文件仅使用设备名称,则可能会出现以下问题:如果同一设备有两个不同的名称,则两个不同的进程可以使用同一设备的不同名称。这会导致具有不同名称但实际上是同一设备的锁文件。以前,每个物理串口都以两个不同的设备名称而闻名:ttyS0 和 cua0。为了解决这个锁文件别名问题,已经使用了 3 种方法。这可能有点过头了,因为这些方法中的任何一种都足以解决问题。

  1. 锁检查软件被告知 ttyS 与 cua 的区别。
  2. 设备 cua 已被弃用
  3. 创建了额外的锁,这些锁使用唯一的设备号而不是名称。

如果一个程序打开 /dev/ttyS2,而另一个程序打开 /dev/modem,则使用备用名称(如 /dev/modem 代表 /dev/ttyS2)可能会导致问题。这个问题据称在 2000 年左右已修复,但在 2005 年仍然存在。对于哑终端,不使用锁文件,因为这将不允许其他人使用 write 或 talk 程序向您的终端发送消息。

13.3 更改设备文件的所有者、组和/或权限

为了使用设备,您(或者您运行的程序,如果您具有 “set user id”)需要具有读取和写入 /dev 目录中设备“文件”的权限。因此,阻止其他人使用设备的逻辑方法是将您自己设置为设备的临时所有者,并设置权限,以便其他任何人都不能使用它。程序可能会为您执行此操作。可以使用类似的方法处理设备文件的组。

虽然锁文件阻止其他进程使用设备,但更改设备文件所有者/权限会限制其他用户(或组)使用它。一种情况是允许组写入端口,但不允许从端口读取。写入端口可能仅仅意味着发送到文本终端的消息,而读取意味着破坏性读取。如果另一个进程已经读取了数据,则需要读取数据的原始进程可能会发现数据丢失。因此,读取可能比写入造成更大的危害,因为读取会导致数据丢失,而写入只会添加额外的数据。这是允许写入但不允许读取的原因。这与普通文件的情况正好相反,在普通文件中,您允许其他人读取文件,但不允许写入(修改)文件。端口的使用通常需要读取和写入权限。

更改设备文件属性的程序应该在退出时撤消这些更改。但如果退出异常,则设备文件可能会处于这样一种状态,即当再次尝试使用它时,会给出错误 “permission denied”(权限被拒绝)。


14. 串口通信程序和实用程序

14.1 软件列表

以下是一些您可以选择的通信软件列表,如果您的 Linux 发行版没有附带这些软件,则可以通过 FTP 获取。

14.2 kermit 和 zmodem

有关将 kermit 与调制解调器一起使用,请参阅 Modem-HOWTO。可以在 kermit 程序中运行 zmodem。要执行此操作(对于 ttyS3),请将以下内容添加到您的 .kermrc 文件中

define rz !rz < /dev/ttyS3 > /dev/ttyS3
define sz !sz \%0 > /dev/ttyS3 < /dev/ttyS3
请务必输入您的调制解调器所在的正确端口。然后,要使用它,只需在 kermit 提示符下键入 rzsz <filename>


15. 串口技巧和杂项

15.1 串口模块

通常,串口驱动程序以模块的形式提供,例如 generic_serial.ko。USB 串口和多端口卡的驱动程序通常以模块的形式提供。Linux 应该自动加载任何需要的模块,因此在大多数情况下,您无需执行任何操作。

但有时您需要配置 Linux 以加载某些模块,或向模块或内核提供参数。

这些参数可以在内核的命令行上,或在 /etc/modules、/etc/modules.conf 或 /etc/modprobe.conf 中提供给某些模块。自内核 2.2 起,您无需编辑 modprobe.conf 文件,而是使用程序 update-modules 来更改它。用于更新 modules.conf 的信息放在 /etc/modutils/ 中。

Debian/GNU Linux 有一个名为 /etc/modutils/setserial 的文件,每次加载或卸载串口模块时,该文件都会运行 /etc/init.d/ 中的 serial 脚本。当卸载串口模块时,此脚本会将模块的状态保存在 /var/run/setserial.conf 中。然后,如果模块再次加载,则会恢复此保存的状态。当串口模块在启动时首次加载时,/var/run/setserial.conf 中没有任何内容,因此状态从 /etc/serial.conf 获取。因此,有两个文件保存状态。其他发行版可能会执行类似的操作。

串口模块位于 /lib/modules/.../kernel/drivers/ 的子目录中。对于多端口卡,请查看 serial 子目录和/或 char。对于 USB 串口,请查看 usb/serial 子目录。模块 parport_serial 用于包含串口和并口的 PCI 卡。

作为最后的手段,可以编辑源代码来修改串口驱动程序。大部分串口驱动程序都在文件 serial.c 中找到。有关为串口编写程序的信息,请参阅 Serial-Programming-HOWTO。Vern Hoxie 在 1999 年对其进行了修订,但该修订版本不在 LDP 上。

15.2 内核配置

15.3 支持的串口数量

如果您有超过 4 个(或可能 2 个)串口,则必须确保内核知道这一点。这可以通过在编译时配置内核,或在内核启动时(启动提示符或内核命令行)给内核一个参数来完成。

内核配置参数:CONFIG_SERIAL_8250_RUNTIME_UARTS=4 和 CONFIG_SERIAL_8250_NR_UARTS=4 将普通串口 (UART) 的最大数量设置为 4。如果您有超过 4 个普通串口,则需要将 4 更改为任何数量。但是您可以通过内核命令行覆盖此设置,例如:nr_uarts=16(如果串口支持内置到内核中)或 8250.nr_uarts=16(如果串口支持通过模块实现)。启动加载程序(如 lilo 或 grub)可以被告知执行此操作。

15.4 串口控制台(串口上的控制台)

请参阅内核文档:Documentation/serial-console.txt。内核 2.4+ 具有更好的文档。另请参阅 Text-Terminal-HOWTO 中的 “Serial Console”。

15.5 线路驱动器

对于文本终端,RS-232 速度足够快,但可用的电缆长度通常太短。平衡技术可以解决这个问题。获得与文本终端平衡通信的常用方法是在串行线路中安装 2 个线路驱动器,以将不平衡转换为平衡(反之亦然)。它们是专用物品,如果购买新的则很昂贵。

15.6 打印等操作时停止数据流

通常,流控制和/或应用程序会在需要时停止字节流。但有时它们不会这样做。问题是到串口的输出首先通过 PC 主内存中的大型串口缓冲区。因此,如果您想中止打印,则应删除此缓冲区中的任何内容。当您告诉应用程序停止打印时,它可能不会清空此缓冲区,因此打印会继续,直到缓冲区为空。此外,您的打印机也有自己的缓冲区,需要清除。因此,告诉 PC 停止打印可能不起作用,因为这两个缓冲区会继续为打印机提供字节。这是打印机软件不了解串口以及需要断开调制解调器控制线以停止打印机的问题。

确保打印停止的一种方法是直接关闭打印机。对于较新的串口驱动程序,这可以正常工作。缓冲区被清除,打印不会恢复。对于较旧的串口驱动程序,PC 的串口缓冲区不会清除,有时会在打印机重新打开时继续打印。为避免这种情况,您必须等待 setserial 的 closing_wait 指定的时间,然后再重新打开打印机。您可能还需要从打印队列中删除打印作业,这样它就不会尝试恢复。

15.7 已知的 IO 地址冲突

避免与某些显卡发生 IO 地址冲突

IBM 8514 显卡(和其他显卡)的 IO 地址据称是 0x?2e8,其中 ? 是 2、4、8 或 9。如果串口在解码地址时忽略前导 0 十六进制数字(许多串口都这样做),则这可能会与 ttyS3 在 0x02e8 的 IO 地址冲突(但不应该,如果串口设计良好)。如果您尝试在此 IO 地址使用 ttyS3,那将是坏消息。另一个说法是,Linux 将不会检测到您在 ttyS3 上的内置调制解调器,但是您可以使用 setserialttyS3 放在此地址,调制解调器将可以正常工作。

与 ide2 硬盘驱动器的 IO 地址冲突

ttyS2 的地址是 3e8-3ef,而硬盘驱动器 ide2 使用 3ee,它在此范围内。因此,当启动 Linux 时,您可能会看到有关此冲突的报告。大多数人不使用 ide2(第三个硬盘驱动器电缆),可以忽略此冲突消息。您可能在 ide0 上有 2 个硬盘驱动器,在 ide1 上还有两个,因此大多数人不需要 ide2。

15.8 已知的硬件缺陷

AMD Elan SC400 CPU(单芯片 PC)的问题

这在 UART 的中断和状态寄存器之间存在竞争条件。当 UART 发射器完成字节的传输并且 UART 发射缓冲区变空(等待下一个字节)时,会发出中断。但是 UART 的状态寄存器更新不够快,无法反映这一点。因此,中断服务例程快速检查并(错误地)确定没有任何事情发生。因此,没有字节发送到端口进行传输,并且 UART 发射器徒劳地等待永远不会到达的字节。如果中断服务例程在检查状态寄存器之前稍微等待一下,那么它将被更新以反映真实状态,一切都会正常。

有一个通过修补串口驱动程序来解决此问题的提议。但是 Linux 是否应该修补以适应有缺陷的硬件,特别是如果此补丁可能会损害良好硬件的性能?


16. 故障排除

有关与调制解调器或 getty for modems 相关的故障排除,请参阅 Modem-HOWTO。对于文本终端,此处的大部分信息以及 Text-Terminal-HOWTO 中的故障排除信息也将很有价值。

16.1 串口电气测试设备

分线盒等

虽然万用表(用作电压表)可能足以满足少数串口的需求,但已经制造出用于测试串口线的简单专用测试设备。有些被称为 “分线盒 ...”,其中分线意味着从电缆中分出导体。这些小工具有几个连接器,用于连接到串口连接器(在串口线的末端或 PC 的背面)。有些具有用于连接电压表的测试点。另一些具有 LED 灯,当某些调制解调器控制线被置位(打开)时会亮起。灯的颜色可能指示信号的极性(正电压或负电压)。还有一些具有跳线,因此您可以将任何导线连接到任何导线。有些具有开关。

Radio Shack(在 2002 年)销售 “RS-232 故障排除器”(以前称为 “RS-232 线路测试仪”)货号 #276-1401。它检查 TD、RD、CD、RTS、CTS、DTR 和 DSR。绿灯表示开启 (+12 v),红灯表示关闭 (-12 v)。他们还销售 “RS-232 串口跳线盒” 货号 #276-1403。这允许您以您选择的任何方式连接引脚。这两件物品都属于 “外围设备连接助手”。不幸的是,它们没有列在印刷目录的索引中。它们与 D 型连接器在同一页上,因此请在索引中查找 “Connectors, Computer, D-Sub”。名为 “Active Components” 的连锁店可能有售。

测量电压

任何电压表或万用表,即使是最便宜的售价约为 10 美元的,也应该可以正常工作。尝试使用其他方法检查电压是很棘手的。不要使用 LED,除非它具有串联电阻以降低 LED 上的电压。对于 20 ma LED 使用 470 欧姆电阻(但并非所有 LED 都是 20 ma)。LED 仅会为特定极性点亮,因此您可以测试 + 或 - 电压。是否有人制造出用于汽车电路测试的此类小工具?如果您尝试使用逻辑探头,则可能会损坏它们,因为它们设计的 TTL 电压仅为 5 伏。尝试使用 12 V 白炽灯泡不是一个好主意。它不会显示极性,并且由于 UART 的输出电流有限,它可能甚至不会亮起。

要测量母连接器上的电压,您可以将弯曲的回形针插入所需的开口中。回形针的直径应不大于引脚,以免损坏触点。将鳄鱼夹(或类似物)夹到回形针上以进行连接。注意不要用任何金属物体同时接触两个引脚。

品尝电压

作为最后的手段,如果您没有测试设备并且愿意冒险触电(甚至触电身亡),您始终可以品尝电压。在用舌头接触其中一个测试引线之前,请先测试它们以确保它们上没有高电压。同时用双手触摸两个引线,看看它们是否会电击您。如果没有电击,用舌头舔湿皮肤接触点并重复。如果此测试给您带来电击,您当然不想用舌头。

对于 12 V 的测试,舔一下手指并握住一个测试引线。将另一个测试引线放在您的舌头上。如果舌头上的引线是正极,则会有明显的味道。您可以先用手电筒电池尝试一下,这样您就会知道会是什么味道。

16.2 串口监控/诊断

一些 Linux 程序将监控调制解调器控制线,并指示它们是正极 (1) 还是负极 (0)。请参阅 串口监控/诊断 部分

16.3 (以下子章节在 Serial 和 Modem HOWTO 中都有)

16.4 找不到串口

有 3 种可能性

  1. 您的端口被禁用,因为 BIOS 和 Linux 都未能启用它。它没有 IO 地址。
  2. 您的端口已启用并具有 IO 地址,但它没有分配给该地址的 ttyS 设备号(如 ttyS14),因此无法使用该端口。作为最后的手段,您可能需要使用 “setserial” 为其分配一个 ttyS 号。
  3. 您的端口确实有一个分配给它的 ttyS 号(如 ttyS14),但您不知道它是哪个物理连接器(在您的 PC 背面)。请参阅 我的 PC 背面的哪个连接器是 ttyS1 等?

首先检查启动时的 BIOS 消息(以及可能的 BIOS 菜单中的串口)。然后对于 PCI 总线类型,键入 lspci -v。如果这显示类似 “LPC Bridge” 的内容,那么您的端口很可能在 LPC 总线上,Linux 尚不支持 LPC 总线(但 BIOS 可能会找到它)?如果是 ISA 总线 PnP 串口,请尝试 “pnpdump --dumpregs” 和/或参阅 Plug-and-Play-HOWTO。如果端口碰巧已启用,则以下两个段落可能有助于找到 IO 端口

扫描/探测传统端口

这主要适用于传统非 PCI 端口和非即插即用 ISA 端口。

使用 “scanport”(仅限 Debian ?)将扫描所有已启用的总线端口,并可能发现一个未知的端口,该端口可能是串口(但它不探测端口)。它可能会使您的 PC 挂起。如果您怀疑您的端口可能位于某个地址,您可以尝试使用 setserial 手动探测,但如果您有多个地址要探测,这将是一项缓慢而乏味的任务。请参阅 探测

16.5 Linux 创建中断冲突 (你的 PC 有 ISA 插槽)

如果你的 PC 有处理 ISA (以及可能的 PCI) 的 BIOS,那么如果你发现 IRQ 冲突,这可能是由于可用 IRQ 短缺造成的。BIOS 通常维护一个保留 IRQ 列表,用于传统的 ISA 卡。如果保留了太多 IRQ,BIOS 可能无法找到空闲的 IRQ,并会错误地将 IRQ 分配给串口,从而造成冲突。因此,请检查是否真的需要所有保留的 IRQ,如果不需要,则取消保留串口可以使用的 IRQ。更多详情,请参阅 Plug-and-Play-HOWTO。

16.6 极其缓慢:文本在长时间延迟后才缓慢出现在屏幕上

这很可能是中断设置错误/冲突。以下是一些症状,当你第一次尝试使用调制解调器、终端或串口打印机时会发生这些症状。在某些情况下,你键入了一些内容,但屏幕上没有任何显示,直到几秒钟之后。可能只显示最后键入的字符。它可能只是一个不可见的 <return> 字符,所以你只会注意到光标向下跳了一行。在另一些情况下,当应该在屏幕上显示大量数据时,只会出现大约 16 个字符的批次。然后会有很长时间的等待,几秒钟后才会出现下一批字符。你可能还会收到 “input overrun” 错误消息 (或者在日志中找到它们)。

有关症状以及发生原因的更多详细信息,请参阅 中断问题详情 和/或 中断冲突 和/或 中断设置错误。如果涉及到即插即用设备,另请参阅 Plug-and-Play-HOWTO。

作为一个快速检查,看看是否真的是中断问题,使用 "setserial" 将 IRQ 设置为 0。这将告诉驱动程序使用轮询而不是中断。如果这似乎解决了 “slow” 问题,那么你遇到了中断问题。你仍然应该尝试解决这个问题,因为轮询会过度使用计算机资源。

检查以找出中断冲突可能不容易,因为据推测 Linux 不允许任何中断冲突,并且如果你认为你正在尝试创建冲突,它会向你发送 /dev/ttyS?: 设备或资源忙 错误消息。但是,如果 “setserial” 告诉内核不正确的信息,则可能会创建真正的冲突。内核被欺骗了,因此不认为存在任何冲突。因此,使用 “setserial” 不会显示冲突 (查看 /proc/interrupts 也不会,它的信息基于 “setserial”)。你仍然需要知道 “setserial” 认为是什么,以便你可以查明它在哪里出错,并在你确定硬件中实际设置了什么时更改它。

你需要做的是检查硬件是如何设置的,通过检查跳线或使用 PnP 软件来检查硬件的实际设置方式。对于 PnP,运行 "pnpdump --dumpregs" (如果是 ISA 总线) 或运行 "lspci" (如果是 PCI 总线)。将此与 Linux (例如 “setserial”) 认为硬件是如何设置的进行比较。

16.7 有点慢:我期望它快几倍

一个明显的原因是波特率设置得太慢。据称,这种情况曾经发生在尝试将波特率设置为高于硬件支持的速度 (例如 230400) 时。

另一个原因可能是串口上的任何设备 (例如调制解调器、终端、打印机) 的工作速度不如你想象的那么快。

另一个可能的原因是你的串口已过时:UART 8250、16450 或早期的 16550 (或者串口驱动程序认为你是)。请参阅

什么是 UART? 使用 "setserial -g /dev/ttyS*"。如果它显示任何低于 16550A 的内容,这可能是你的问题。如果你认为 "setserial" 搞错了,请检查一下。请参阅 什么是 Setserial 以获取更多信息。如果你真的有一个过时的串口,向 setserial 撒谎只会让事情变得更糟。

16.8 启动屏幕显示串口的错误 IRQ

对于非 PnP 端口,Linux 在启动时不会进行任何 IRQ 检测。当串口模块加载时,它只进行串口设备检测。因此,忽略它关于 IRQ 的说法,因为它只是假设了标准的 IRQ。这样做是因为 IRQ 检测不可靠,并且可能被愚弄。但是,当且仅当 setserial 从启动脚本运行时,它才会更改 IRQ,并在启动屏幕上显示新的 (并且希望是正确的) 状态。如果错误的 IRQ 没有在屏幕上的后续显示中得到纠正,那么你就遇到了问题。

所以,即使我将我的 ttyS2 设置为 IRQ 5,我仍然看到

ttyS02 at 0x03e8 (irq = 4) is a 16550A
在 Linux 启动时第一次看到。(较旧的内核可能会将 "ttyS02" 显示为 "tty02",这与 ttyS2 相同)。你可能需要使用 setserial 来告诉 Linux 你正在使用的 IRQ。

16.9 “无法打开 /dev/ttyS?: 设备或资源忙”

请参阅 /dev/tty? 设备或资源忙

16.10 “无法打开 /dev/ttyS?: 权限被拒绝”

使用 "ls -l /dev/ttyS?" 检查此端口的文件权限。如果你拥有 ttyS?,那么你需要读写权限:crw,其中 c (字符设备) 在第 1 列。如果你不拥有它,那么如果它在第 8 和 9 列显示 rw-,它将对你有效,这意味着每个人都对其具有读写权限。使用 "chmod" 更改权限。还有更复杂 (和安全) 的方法来获得访问权限,例如属于具有组权限的 “组”。有些程序在运行时更改权限,但在程序正常退出时恢复它们。但是如果有人拔掉你的 PC 的插头,这是一个异常退出,正确的权限可能无法恢复。

16.11 “无法打开 /dev/ttyS?”

除非 stty 设置为 clocal,否则可能需要断言 CD 引脚才能打开串口。如果物理端口未连接到任何东西,或者如果它连接到未通电的东西 (例如外部调制解调器),那么来自该设备的 CD 上将没有电压。因此出现 “无法打开” 消息。要么设置 clocal,要么将串口连接器连接到某个东西并通电。

即使设备已通电并连接到端口,有时也可能阻止打开端口。这方面的一个例子是设备已否定 CD,而你的 PC 上的 CD 引脚也被否定 (负电压)。

16.12 “设备不支持的操作” 对于 ttyS?

这意味着 setserial、stty 等请求的操作无法完成,因为内核不支持这样做。以前这通常是由于没有加载 “serial” 模块。但是随着 PnP 的出现,这很可能意味着在驱动程序 (和 setserial) 认为存在的地址上没有调制解调器 (或其他串口设备)。如果那里没有调制解调器,那么发送到该地址的命令 (用于操作) 显然不会完成。请参阅 我的串口硬件中设置了什么?

如果 “serial” 模块没有加载,但 “lsmod” 显示它现在已加载,则可能是它现在已加载,但在你收到错误消息时未加载。在许多情况下,模块会在需要时自动加载 (如果可以找到)。要强制加载 “serial” 模块,它可以列在文件:/etc/modules.conf 或 /etc/modules 中。实际模块应位于:/lib/modules/.../misc/serial.o 中。

16.13 “无法创建锁文件。抱歉”

有时当无法创建锁文件时,你会收到错误消息:“... 设备或资源忙” 而不是上面的消息。当程序 “打开” 端口时,会在 /var/lock/ 中创建一个锁文件。锁目录的错误权限将不允许在那里创建锁文件。使用 "ls -ld /var/lock" 查看权限是否正常。为 root 所有者和组提供 rwx 权限应该可以工作,前提是需要拨号的用户属于该组。其他人应该具有 r-x 权限。即使使用此方案,也可能存在安全风险。使用 "chmod" 更改权限,使用 "chgrp" 更改组。当然,如果没有 “lock” 目录,则无法在那里创建锁文件。有关锁文件的更多信息,请参阅 什么是锁文件

16.14 “设备 /dev/ttyS? 已锁定。”

这意味着其他人 (或某些其他进程) 据称正在使用串口。有多种方法可以尝试找出哪个进程正在 “使用” 它。一种方法是查看锁文件 (/var/lock/LCK...) 的内容。它应该是进程 ID。如果进程 ID 例如是 100,则键入 "ps 100" 以找出它是什么。然后,如果不再需要该进程,可以通过 "kill 100" 优雅地杀死它。如果它拒绝被杀死,请使用 "kill -9 100" 强制杀死它,但这样锁文件将不会被删除,你需要手动删除它。当然,如果不存在进程 100,那么你可以直接删除锁文件,但在大多数情况下,如果锁文件包含过时的进程 ID (例如 100),则应自动删除锁文件。

16.15 “/dev/tty? 设备或资源忙”

这意味着你正在尝试访问 (或使用) 的设备据称正忙 (正在使用中),或者它需要的资源 (例如 IRQ) 据称正在被另一个设备使用且无法共享。如果它仅表示设备正忙 (正在使用中),则此消息很容易理解。但有时它意味着所需的资源已在使用中 (忙)。更令人困惑的是,在某些情况下,设备及其需要的资源实际上都不是 “忙”。

在过去,如果 PC 通过直接关闭电源而关机,则可能会留下一个伪造的锁文件,然后在稍后会收到此伪造消息,并且无法使用串口。今天的软件应该会自动删除此类伪造的锁文件,但截至 2006 年,与 “wvdial” 拨号程序相关的锁文件仍然存在问题。如果 wvdial 因为在 /var/lock/ 目录中没有写入权限而无法创建锁文件,你将看到此错误消息。请参阅 无法创建锁文件。抱歉

以下示例是无法共享中断的情况 (至少一个中断在 ISA 总线上)。“资源忙” 部分通常意味着 (例如 ttyS2) “你无法使用 ttyS2,因为另一个设备正在使用 ttyS2 的中断。” 潜在的中断冲突是从 “setserial” 认为的内容推断出来的。更准确的错误消息应该是 “无法使用 ttyS2,因为 setserial 数据 (和内核数据) 表明另一个设备正在使用 ttyS2 的中断”。如果两个设备使用相同的 IRQ,并且你只启动其中一个设备,则一切正常,因为尚未发生冲突。但是,当你接下来尝试启动第二个设备 (而不退出第一个设备) 时,你会收到 “... 忙” 错误消息。这是因为内核仅跟踪实际使用的 IRQ,并且实际冲突只有在设备正在使用 (打开) 时才会发生。I/O 地址 (例如 0x3f8) 冲突的情况类似。

此错误有时是由于有两个串口驱动程序引起的:一个是模块,另一个编译到内核中。两个驱动程序都尝试抢占相同的资源,并且一个驱动程序发现它们 “忙”。

当你看到此消息时,有两种可能的情况

  1. 可能存在正在避免的真正资源冲突。
  2. Setserial 搞错了,并且无法使用 ttyS2 的唯一原因是 setserial 错误地预测了冲突。

你需要做的是找到 setserial 认为 ttyS2 正在使用的中断。查看 /proc/tty/driver/serial。你也应该能够使用 ttyS2 的 "setserial" 命令找到它。

旧版本中的错误:在 2001 年之前,存在一个错误,该错误将阻止你使用 "setserial" 查看它。尝试查看它会给出相同的 “... 忙” 错误消息。

要尝试解决此问题,请重新启动或:退出或优雅地杀死所有可能冲突的进程。如果你重新启动:1. 观看启动时串口的消息。2. 希望在启动时运行 "setserial" 的文件不会 (本身) 再次创建相同的冲突。

如果你认为你知道 ttyS2 正在使用的 IRQ,那么你可以查看 /proc/interrupts 以查找当前还有什么 (除了另一个串口) 正在使用此 IRQ。你可能还想仔细检查此处 (和通过 "setserial") 显示的任何可疑 IRQ 是否正确 (与硬件中设置的相同)。测试是否是潜在中断冲突的一种方法是使用 "setserial" 将 IRQ 设置为 0 (轮询)。然后,如果忙消息消失,则很可能是潜在的中断冲突。永久将其设置为 0 不是一个好主意,因为它会给 CPU 带来更多负载。

16.16 来自 setserial、stty、pppd 等的 “输入/输出错误”

这意味着与串口的通信无法正常工作。这可能意味着在 setserial 认为你的端口所在的 IO 地址上没有任何串口。这也可能是中断冲突 (或 IO 地址冲突)。这也可能意味着串口正在使用中 (忙或已打开),因此 setserial 或 stty 获取/设置参数的尝试失败。如果你在串口名称中键入错误,例如键入 "ttys" 而不是 "ttyS",也会发生这种情况。

16.17 “LSR 安全检查已启动”

LSR 是硬件寄存器的名称。它通常意味着在驱动程序认为你的串口所在的地址上没有串口。你需要找到你的串口,并可能配置它。请参阅 定位串口:IO 地址 IRQ 和/或 什么是 Setserial

16.18 串口上的溢出错误

这是硬件 FIFO 缓冲区的溢出,你无法增加其大小。错误说明 (2002 年报告):由于某些内核 2.4 版本中的错误,端口号可能会丢失,你只会看到 "ttyS" (没有端口号)。但是,如果正在使用诸如 "tts/2" 之类的 devfs 表示法,则没有错误。请参阅 更高的串口吞吐量

16.19 端口仅零星地获取字符

可能有一些其他程序正在端口上运行。使用 "top" (前提是你已将其设置为显示端口号) 或键入 "ps -alxw"。查看结果以查看端口是否正在被另一个程序使用。注意经常在串口上运行的 gpm 鼠标程序。

16.20 故障排除工具

以下是一些你可能想在故障排除中使用的程序

16.21 几乎所有字符都错误;许多丢失或许多额外的字符

可能是波特率不匹配。如果一个端口以另一个端口设置为接收速度的两倍速度发送,那么每发送两个字符将被接收为一个字符。接收到的字符的每一位都将是发送内容的两位样本,并且将是错误的。此外,似乎只有一半发送的字符被接收到。对于反向方向的流,情况恰恰相反。接收到的字符是发送字符的两倍。更糟糕的不匹配会产生更糟糕的结果。

速度不匹配不太可能发生在调制解调器上,因为调制解调器会自动检测速度。速度不匹配的一个原因可能是由于串口硬件已设置为以非常快的速度运行。它实际上可能以你 (或应用程序) 通过软件设置的速度的 8 倍的速度运行。请参阅 极高速


17. 中断问题详情

虽然 故障排除 部分按症状列出了问题,但本节解释了如果中断设置不正确会发生什么。本节帮助你了解导致症状的原因、可能由同一问题引起的其他症状以及如何处理它。

17.1 中断问题类型

“setserial” 程序将向你显示串口驱动程序认为中断是如何设置的。如果串口驱动程序 (和 setserial) 是正确的,那么关于中断的一切都应该没问题。当然,/dev/ttyS 必须存在于设备中,并且即插即用 (或跳线) 必须在硬件中设置地址和 IRQ。Linux 不会故意允许中断冲突,如果你尝试执行会创建冲突的操作,你将收到 “设备或资源忙” 错误消息。

由于内核试图避免中断冲突,并且如果你尝试创建冲突,则会给出 “资源忙” 消息,那么中断冲突是如何发生的呢?很简单。“setserial” 可能搞错了,并且错误地预测不会发生冲突,但实际上会根据硬件中设置的内容发生真正的冲突。当这种情况发生时,不会出现 “... 忙” 消息,但会实际发生冲突。性能可能会非常慢。两个设备将在同一条线上发送相同的中断信号,并且 CPU 会错误地认为中断仅来自一个设备。这将在以下各节中详细解释。

Linux 不会在你为两个设备分配相同的 IRQ 时抱怨,前提是这两个设备都没有在使用。当每个设备启动 (初始化) 时,它都会向 Linux 请求允许使用其硬件中断。Linux 跟踪哪个中断分配给了谁,如果你的中断已被使用,你将看到 “... 忙” 错误消息。因此,如果两个设备使用相同的 IRQ,并且你只启动其中一个设备,则一切正常。但是,当你接下来尝试启动第二个设备 (而不退出第一个设备) 时,你会收到 “... 忙” 错误消息。

17.2 中断设置错误或冲突的症状

症状取决于你是否拥有带有 FIFO 缓冲区的现代串口,还是没有 FIFO 缓冲区的过时串口。理解过时串口的症状也很重要,因为有时现代串口似乎也会以这种方式运行。

对于过时的串口,每隔几秒钟才通过一个字符。这太慢了,以至于看起来几乎像什么都没有工作 (特别是如果通过的字符是不可见的 (例如空格或换行符))。对于带有 FIFO 缓冲区的现代端口,你可能会看到每隔几秒钟爆发最多 16 个字符。

如果你的端口上有调制解调器并拨打电话号码,则连接似乎可能不会成功,因为 CONNECT 消息可能无法通过。但是经过长时间的等待后,它最终可能会连接,你可能会看到登录消息的一部分 (或类似内容)。来自你连接方的响应可能会延迟到另一方放弃并断开你的连接,从而导致 NO CARRIER 消息。

如果你使用 minicom,一个常见的测试来看事情是否正常工作的方法是键入最简单的 "AT" 命令,看看调制解调器是否响应。正常情况下 (如果中断正常),键入 at<enter> 应该立即收到来自调制解调器的 "OK" 响应。如果中断不良,你键入 at<enter> 可能会看不到任何内容。但是大约 10 秒钟后,你会看到光标下降一行。正在发生的事情是 FIFO 的行为就像它只能容纳一个字节一样。你键入的 "at" 导致它溢出,并且两个字母都丢失了。但是,最终的 <enter> 最终通过了,你通过注意到光标向下跳了一行来 “看到” 这个不可见的字符。如果你要键入一个字母,然后等待大约 10 秒钟,你应该看到它回显到屏幕上。如果你的打字速度低于每分钟一个字,这很好 :-)

17.3 中断设置错误

如果你不理解中断的作用,请参阅 中断。如果串口在硬件中设置了一个 IRQ,但在设备驱动程序中设置了另一个 IRQ,则设备驱动程序将不会捕获串口发送的任何中断。由于串口使用中断来调用其驱动程序以服务端口 (从其 16 字节接收缓冲区中获取字节或将另 16 字节放入其发送缓冲区中),因此人们可能会期望串口根本无法工作。

但它仍然可能以某种方式工作 - 有点。为什么?好吧,除了服务端口的中断方法之外,还有一种未记录的慢速轮询方法,不需要中断。它的工作方式是,设备驱动程序会不时检查串口,看看它是否需要任何东西,例如它是否有任何需要从其接收缓冲区中获取的字节。如果中断不起作用,串口驱动程序会退回到这种轮询方法。但是,这种轮询方法并不打算用作中断的替代品。它太慢了,以至于不切实际,并且可能导致缓冲区溢出。它的目的可能是让事情在仅仅丢失一个中断或未能做正确的事情时再次开始运行。它还有助于向你显示中断已失败。不要将这种慢速轮询方法与在 IRQ 设置为 0 的端口上运行的快速轮询方法混淆。

对于 16 字节的发送缓冲区,将发送 16 个字节,然后它将等待下一次轮询发生 (几秒钟后),然后再发送下 16 个字节。因此,传输速度非常慢且以小块进行。接收速度也很慢,因为接收缓冲区接收到的字节很可能在那里停留几秒钟,直到被轮询。

这解释了为什么你键入的内容需要这么长时间才显示出来。当你向调制解调器键入例如 AT 时,AT 会通过串口发送到调制解调器。然后调制解调器将 AT 回显通过串口返回到屏幕。因此,AT 字符必须通过串口两次。通常,这种情况发生得如此之快,以至于 AT 似乎在你敲击键盘上的按键的同时出现在屏幕上。由于串口的慢速轮询延迟,你可能要等到 15 秒后才能看到你键入的内容。即使那样,你通常也看不到你键入的所有内容,而只能看到前几个字符。

关于 16 字节接收缓冲区的溢出呢?这将在外部调制解调器上发生,因为调制解调器只是以高速发送到串口,这很可能导致 16 字节缓冲区溢出。但是对于内部调制解调器,串口位于同一张卡上,并且很可能在将接收到的字节放入其中之前检查此 16 字节接收缓冲区是否有空间容纳更多字节。在这种情况下,不会发生此接收缓冲区的溢出,但文本只会以 16 字节的块出现在屏幕上,这些块间隔几秒钟。

即使使用外部调制解调器,你可能也不会发生溢出。如果只发送少量字符 (少于 16 个),你不会发生溢出,因为缓冲区很可能可以容纳它们。但是,尝试从你的调制解调器向屏幕发送大量字节可能会导致溢出。但是,如果时序正确,则可以无溢出地通过 16 个以上的字节 (没有间隙)。例如,假设从外部电缆突发 32 个字节进入端口。轮询可能恰好在最初 16 个字节进入后发生,因此它会正确地拾取这 16 个字节。然后将有空间容纳接下来的 16 个字节,以便整个 32 个字节都通过。虽然这种情况不太可能发生,但 17 到 31 个字节通过的类似情况更有可能发生。但更可能的是,只有偶尔的 16 字节块会通过,并且可能丢失数据。

如果你有一个只有 1 字节缓冲区的过时串口 (或者它被错误地设置为像 1 字节缓冲区一样工作),那么情况将比上面描述的更糟,并且只有偶尔一个字符会通过端口。接收到的每个字符都会导致溢出 (并丢失),除了接收到的最后一个字符。此字符很可能只是换行符,因为这通常是在发送到屏幕的字符突发中最后传输的字符。因此,你可能会向调制解调器键入 AT<return>,但永远不会在屏幕上看到 AT。你几秒钟后看到的只是光标下降一行 (换行符)。这种情况发生在我身上,一个 16 字节的 FIFO 缓冲区表现得像一个 1 字节的缓冲区。

当通信程序启动时,它期望中断工作正常。它不适合使用这种慢速轮询式操作模式。因此,可能会犯各种错误,例如错误地设置串口和/或调制解调器。它可能无法意识到何时已建立连接。如果脚本用于登录,则由于轮询延迟,它可能会失败 (由超时引起)。

17.4 中断冲突

当两个设备拥有相同的 IRQ 号时,这被称为共享中断。在某些情况下,这种共享可以正常工作。从内核版本 2.2 开始,ISA 串口可以(如果硬件为此设计)与其他串口共享中断。PCI 总线上的设备可以与其他 PCI 总线上的设备共享同一个 IRQ 中断(前提是软件支持此功能)。在其他可能发生冲突的情况下,如果任何两个具有相同 IRQ 的设备永远不同时“使用”,则应该没有问题。更准确地说,“使用”实际上意味着“打开”(用程序员的术语来说)。在上述例外情况之外的其他情况下(除非特殊的软件和硬件允许共享),不允许共享,如果尝试共享,则会发生冲突。

即使两个具有冲突 IRQ 的进程同时运行,其中一个设备的设备驱动程序也可能会捕获到其中断,并且可能工作正常。另一个设备的中断将不会被正确的驱动程序捕获,并且可能会表现得像一个具有错误设置中断的进程一样。有关更多详细信息,请参阅 错误设置中断

17.5 解决中断问题

如果您遇到如上所述的非常慢的响应,那么一个测试是将 IRQ 更改为 0(使用快速轮询而不是中断),看看问题是否消失。请注意,由于 IRQ=0 引起的轮询比由于错误中断引起的慢速“轮询”快几个数量级。如果 IRQ=0 似乎解决了问题,那么很可能中断存在问题。使用 IRQ=0 非常消耗资源,只是一种临时性的修复方法。您应该尝试找到中断问题的根源,而不是永久使用 IRQ=0。

检查 /proc/interrupts 以查看 IRQ 当前是否被另一个进程使用。如果它被另一个串口使用,您可以尝试 "top"(输入 f 然后启用 TTY 显示)或 "ps -e" 来找出哪些串口正在使用。如果您怀疑 setserial 具有错误的 IRQ,请参阅 我的串口的当前 IO 地址和 IRQ 是什么?


18. 什么是 UART?它们如何影响性能?

18.1 UART 简介

UART(Universal Asynchronous Receiver Transmitter,通用异步收发器)是您 PC 主板(或内部调制解调器卡)上的串行芯片。UART 功能也可以在执行其他功能的芯片上完成。在较旧的计算机(如许多 486)上,芯片位于磁盘 IO 控制器卡上。更老的计算机有专用的串行板。

当 PC 都具有并行总线架构时,UART 的目的是将来自 PC 并行总线的字节转换为串行比特流。从串口出来的电缆是串行的,并且每个流向只有一个导线。串口一次发送一个比特的比特流。相反,通过外部电缆进入串口的比特流被转换为计算机可以理解的并行字节。UART 处理字节大小的数据块,这也很方便地是 ASCII 字符的大小。

假设您有一个终端连接到您 PC 的串口。当您键入一个字符时,终端会将该字符提供给其发射器(也是一个 UART)。发射器以特定的速率将该字节一次一位地发送到串行线上。在 PC 端,接收 UART 接收所有比特并重建字节(在较旧的 PC 上是并行的),并将其放入缓冲区。对于可能具有 PCI-e 串口的新型 PC,UART 不需要进行并行到串行的转换,因为 PCI-e “总线”已经是串行线。但是 PCI-e 线承载着编码信号,必须对其进行解码,然后大大减速到 RS-232 串行线的速度。

除了在串行和并行之间进行转换之外,UART 还作为其主要任务的副产品(副作用)完成一些其他事情。用于表示比特的电压也被转换(改变)。在每个字节传输之前,会添加额外的比特(称为起始位和停止位)。有关详细信息,请参阅 Serial-HOWTO 部分 电压波形。此外,虽然计算机内部并行总线上的流速(以字节/秒为单位)非常高,但 UART 串行端口侧的流速要低得多。UART 具有一组固定的速率(速度),可以在其串行端口接口上使用。

18.2 两种类型的 UART

UART 主要有两种基本类型:哑 UART 和 FIFO UART。哑 UART 是 8250、16450、早期 16550 和早期 16650。它们已经过时了,但是如果您了解它们的工作原理,就很容易理解现代的 FIFO UART(晚期 16550、16550A 和更高编号)是如何工作的。请注意,所有这些 UART 的驱动程序在 Linux 中仍然标记为 “8250” 驱动程序,如果您编译自己的内核等,您可能会在编译选项中看到它。

关于 16550 存在一些混淆。早期的型号存在缺陷,只能作为 16450 工作(没有 FIFO)。后来修复了缺陷的型号被命名为 16550A,但许多制造商不接受名称更改,并继续称其为 16550。今天使用的大多数 16550 都像 16550A。Linux 会将其报告为 16550A,即使您的硬件手册(或标签注释)说它是 16550。16650 也存在类似的情况(只是情况更糟,因为据称制造商不承认有任何问题)。Linux 会将晚期的 16650 报告为 16650V2。如果它报告为 16650,那是个坏消息,它只能像有一个字节缓冲区一样使用。

18.3 FIFO

要理解哑 UART 和 FIFO(先进先出队列规则)之间的区别,首先让我们检查当 UART 发送或接收一个字节时会发生什么。UART 本身无法处理通过它的数据,它只是接收和发送数据。对于过时的哑 UART,CPU 每次发送或接收一个字节时都会从串行设备获得中断。然后 CPU 将接收到的字节从 UART 的缓冲区中移出并放入内存中的某个位置,或者给 UART 另一个要发送的字节。过时的 8250 和 16450 UART 只有一个字节的缓冲区。这意味着,每次发送或接收 1 个字节时,CPU 都会被中断。在低传输速率下,这还可以。但是,在高传输速率下,CPU 会变得非常忙于处理 UART,以至于它没有足够的时间来处理其他任务。在某些情况下,CPU 没有及时处理中断,并且字节被覆盖,因为它们传入的速度太快了。这被称为“溢出”。

FIFO UART 有助于解决这个问题。16550A(或 16550)FIFO 芯片配备了 16 字节的 FIFO 缓冲区。这意味着它可以接收多达 14 个字节(或发送 16 个字节)才需要中断 CPU。它不仅可以等待更多字节,而且 CPU 可以一次传输所有字节(14 到 16 个)。这相对于只有 1 字节缓冲区的过时 UART 来说是一个显着的优势。CPU 接收的中断更少,并且可以自由地执行其他操作。数据很少丢失。请注意,FIFO 缓冲区的中断阈值(触发级别)可以设置为小于 14。1、4 和 8 是其他可能的选择。截至 2000 年末,Linux 用户无法直接设置这些值(setserial 无法做到)。虽然许多 PC 只有具有 16 字节缓冲区的 16550,但更好的 UART 具有更大的缓冲区。

请注意,中断是在缓冲区即将满之前(例如,对于 16 字节的缓冲区,触发级别为 14 字节)发出的。这为在中断服务例程能够实际获取所有这些字节之前接收更多几个字节留出了空间。触发级别可以由内核软件设置为各种允许的值。触发级别为 1 将几乎像过时的 UART(除了它在发出中断后仍然有 15 个字节的空间)。

现在考虑您在 Internet 上的情况。它刚刚向您发送了一个简短的文本网页。所有这些都通过串口传入。如果您的串口上有一个 16 字节的缓冲区,它会保留字符直到它有 14 个字符,那么屏幕上最后几个字符中的一些可能会丢失,因为 FIFO 缓冲区正在等待获得第 14 个字符。但是第 14 个字符没有到达,因为您已经通过电话线收到了整个页面,并且没有更多字符要发送给您。这些最后的字符可能是 HTML 格式的一部分等等,并且不是要在屏幕上显示的字符,但您也不想丢失格式。

有一个“超时”来防止上述问题。“超时”对于接收 UART 缓冲区的工作方式如下:如果字符一个接一个地到达,那么只有当第 14 个字符到达缓冲区时才会发出中断。但是,如果一个字符到达,而下一个字符没有很快到达,那么无论如何都会发出中断。这导致提取 FIFO 缓冲区中的所有字符,即使只有几个(或只有一个)字符存在。发送缓冲区也有“超时”。

18.4 为什么 FIFO 缓冲区很小

您可能想知道为什么 FIFO 缓冲区不大。毕竟,内存很便宜,使用千字节范围的缓冲区也不会花费太多。原因是流量控制。流量控制在必要时停止串行线上的数据(字节)流。如果向串口发送停止信号,则停止请求由软件处理(即使流量控制是“硬件”)。串口硬件对流量控制一无所知。

如果串口缓冲区包含 64 个字节准备发送,当它收到流量控制信号以停止发送时,它仍然会发送出 64 个字节,违反了停止请求。由于它不知道流量控制,因此无法阻止它。如果缓冲区很大,那么将发送更多字节,违反流量控制的停止请求。

18.5 UART 型号

以下是一些 UART 的列表。TLTrigger Level(触发级别)

对于 V.90 56k 调制解调器,使用 16650 可能会快几个百分点(特别是当您下载大型未压缩文件时)。16650 的主要优势是其更大的缓冲区大小,除非调制解调器压缩比很高,否则不需要额外的速度。一些 56k 内部调制解调器可能配备 16650 ??

非 UART 和智能多端口板使用 DSP 芯片进行额外的缓冲和控制,从而进一步减轻 CPU 的负担。例如,Cyclades Cyclom 和 Stallion EasyIO 板使用 Cirrus Logic CD1400 RISC UART,许多板使用 80186 CPU 甚至特殊的 RISC CPU 来处理串行 IO。

许多 486 PC(旧)和所有奔腾(或类似的)应该至少具有带有 FIFO 的 16550A(通常简称为 16550)。今天(2000 年)一些更好的主板甚至具有 16650。对于在 1990 年之前的硬件中用更新的 UART 替换过时的 UART,请参阅附录:过时 ...


19. 引脚排列和信号

19.1 9 针和 25 针串行连接器的引脚排列

引脚编号通常刻在连接器的塑料上,但您可能需要放大镜才能读取它们。请注意,DCD 有时标记为 CD。母连接器上的引脚编号是从右到左读取的,从右上角的 1 开始(而不是像下面显示的公连接器那样从左上角的 1 开始)。--> 方向是从 PC 输出。

  ___________                    ________________________________________
  \1 2 3 4 5/  Looking at pins   \1  2  3  4  5  6  7  8  9  10 11 12 13/
   \6 7 8 9/  on male connector   \14 15 16 17 18 19 20 21 22 23 24 25/
    ------                         -----------------------------------
Pin #   Pin #   Acronym  Full-Name   Direction  What-it-May-Do/Mean
9-pin   25-pin
 3       2      TxD     Transmit Data     -->   Transmits bytes out of PC
 2       3      RxD     Receive Data      <--        Receives bytes into PC
 7       4      RTS     Request To Send   -->   RTS/CTS flow control
 8       5      CTS     Clear To Send     <--        RTS/CTS flow control
 6       6      DSR     Data Set Ready    <--        I'm ready to communicate
 4      20      DTR     Data Terminal Ready-->  I'm ready to communicate
 1       8      DCD     Data Carrier Detect<--       Modem connected to another
 9      22      RI      Ring Indicator    <--        Telephone line ringing
 5       7      SG      Signal Ground

  9-Pin DB9 Connector                    25-Pin DB-25 Connector
1     DCD   Carrier Detect             1           Chassis Ground             
2     RxD   Receive Data               2     TxD   Transmit Data
3     TxD   Transmit Data              3     RxD   Receive Data
4     DTR   Data Terminal Ready        4     RTS   Request To Send
5     SG    Signal Ground              5     CTS   Clear To Send
6     DSR   Data Set Ready             6     DSR   Data Set Ready
7     RTS   Request To Send            7     SG    Signal Ground
8     CTS   Clear To Send              8     DCD   Carrier Detect
9     RI    Ring Indicator            20     DTR   Data Terminal Ready
                                      22     RI    Ring Indicator

19.2 信号可能没有固定的含义

9 个引脚中只有 3 个具有固定的分配:发送、接收和信号地。这是由硬件固定的,您无法更改它。但是其他信号线由软件控制,并且几乎可以做(和意味着)任何事情。但是它们只能处于两种状态之一:置位(+12 伏)或复位(-12 伏)。置位是“开”,复位是“关”。例如,Linux 软件可以命令将 DTR 复位,硬件只执行此命令并在 DTR 引脚上施加 -12 伏电压。接收到此 DTR 信号的调制解调器(或其他设备)可能会执行各种操作。如果调制解调器已配置为某种方式,它将在 DTR 复位时挂断电话线。在其他情况下,它可能会忽略此信号或在 DTR 复位(关闭)时执行其他操作。

所有 6 条信号线都是如此。硬件只发送和接收信号,但它们执行什么动作(如果有),取决于 Linux 软件以及您连接到串口的设备的配置/设计。但是,大多数引脚都有它们通常执行的某些功能,但这可能会因操作系统和设备驱动程序配置而异。在 Linux 下,可以修改源代码以使这些信号线的行为有所不同(有些人这样做过)。

19.3 串行端口之间的布线

来自串行端口的电缆始终连接到另一个串行端口。连接到串行端口的外部调制解调器或其他设备内置了串行端口。对于调制解调器,电缆始终是直通的:引脚 2 连接到引脚 2,等等。调制解调器被称为 DCE(数据通信设备),计算机被称为 DTE(数据终端设备)。因此,对于连接 DTE 到 DCE,您使用直通电缆。对于连接 DTE 到 DTE,您必须使用零调制解调器电缆(也称为交叉电缆)。有很多方法可以连接这种电缆(请参阅 Text-Terminal-HOWTO 子节中的示例:“直接电缆连接”)

它以这种方式工作是有充分理由的。一个原因是信号是单向的。如果引脚 2 发送信号出去(但无法接收任何信号),那么显然您不能将其连接到同类型设备的引脚 2。如果您这样做,它们都将在同一根导线上相互发送信号,但两者都无法接收任何信号。有两种方法可以解决这种情况。一种方法是拥有两种不同类型的设备,其中第一种类型的引脚 2 将信号发送到第二种类型的引脚 2(接收信号)。这就是当您将 PC (DTE) 连接到调制解调器 (DCE) 时所做的方式。第二种方法是在没有两种不同类型设备的情况下执行此操作:将发送引脚 2 连接到同类型设备上的接收引脚 3。这就是当您将 2 台 PC 连接在一起或将 PC 连接到终端 (DTE-to-DTE) 时所做的方式。用于此目的的电缆称为零调制解调器电缆,因为它在不使用调制解调器的情况下连接两台 PC。零调制解调器电缆也可以称为交叉电缆,因为引脚 2 和 3 之间的导线相互交叉(如果您将它们绘制在纸上)。以上示例是针对 25 针连接器的,但对于 9 针连接器,引脚编号 2 和 3 只是相反的。

串行引脚指定最初旨在将哑终端连接到调制解调器。终端是 DTE(数据终端设备),调制解调器是 DCE(数据通信设备)。今天,PC 通常用作 DTE 而不是终端(但真正的终端仍然可以这样使用)。DTE 和 DCE 上的引脚名称相同。“接收”和“发送”这两个词是从 PC (DTE) 的“角度”出发的。来自 PC 的发送引脚发送到调制解调器的“发送”引脚(但实际上调制解调器正在从该引脚接收数据,因此从调制解调器的角度来看,它将是一个接收引脚)。

串行端口最初旨在用于连接 DTE 到 DCE,这使得布线很简单:只需使用直通电缆即可。因此,当连接调制解调器时,人们很少需要担心哪个引脚是哪个引脚。但是人们想要连接 DTE 到 DTE(例如计算机到终端),并且找到了各种方法通过制造各种类型的特殊零调制解调器电缆来做到这一点。在这种情况下,哪个引脚连接到哪个引脚变得很重要。

19.4 RTS/CTS 和 DTR/DSR 流量控制

这是“硬件”流量控制。流量控制先前在 流量控制 子节中进行了解释,但没有解释引脚和电压信号。Linux 目前仅支持 RTS/CTS 流量控制(但是可能存在用于特定应用程序的特殊驱动程序,该驱动程序支持 DTR/DSR 流量控制)。由于 DTR/DSR 流量控制的工作方式相同,因此仅讨论 RTS/CTS 流量控制。要获得 RTS/CTS 流量控制,需要在应用程序中选择硬件流量控制,或者使用命令
stty -F /dev/ttyS2 crtscts (或类似的命令)。这将在 Linux 设备驱动程序中启用 RTS/CTS 硬件流量控制。

然后,当 DTE(例如 PC)想要停止流入它的流量时,它会复位 RTS。复位的“请求发送”(-12 伏)意味着“请求不要向我发送”(停止发送)。当 PC 准备好接收更多字节时,它会置位 RTS (+12 伏),并且字节流向它的流量恢复。流量控制信号始终在与被控制的字节流相反的方向上发送。DCE 设备(调制解调器)的工作方式相同,但通过 CTS 引脚发送停止信号。因此,它是使用 2 条线的 RTS/CTS 流量控制。

此停止信号在哪些引脚上接收?这取决于我们是 DCE-DTE 连接还是 DTE-DTE 连接。对于 DCE-DTE,它是直通连接,因此显然信号是在与其发送引脚同名的引脚上接收的。它是 RTS-->RTS(PC 到调制解调器)和 CTS<--CTS(调制解调器到 PC)。对于 DTE 到 DTE,连接也很容易弄清楚。RTS 引脚始终发送,CTS 引脚始终接收。假设我们将两台 PC(PC1 和 PC2)通过其串口连接在一起。那么它是 RTS(PC1)-->CTS(PC2) 和 CTS(PC1)<--RTS(PC2)。换句话说,RTS 和 CTS 交叉。这种电缆(以及其他交叉的信号)称为“零调制解调器”电缆。请参阅 串行端口之间的布线

有时令人困惑的是 RTS 的原始用途,它意味着与上述解释相反。这种原始含义是:我请求向您发送。此请求旨在从终端(或计算机)发送到调制解调器,调制解调器如果决定批准该请求,将从其 CTS 引脚向计算机的 CTS 引脚发送回置位的 CTS:您被允许向我发送。请注意,与现代 RTS/CTS 双向流量控制相比,这仅保护一个方向的流量:从计算机(或终端)到调制解调器。这种原始用途在现代设备(包括调制解调器)上似乎很少使用。

DTR 和 DSR 引脚

就像 RTS 和 CTS 一样,这些引脚是成对的。对于 DTE 到 DTE 连接,它们很可能会交叉。有两种方法可以使用这些引脚。一种方法是将它们用作 RTS/CTS 流量控制的替代品。DTR 引脚就像 RTS 引脚,而 DSR 引脚的行为类似于 CTS 引脚。尽管 Linux 不支持 DTR/DSR 流量控制,但可以通过将 PC 上的 RTS/CTS 引脚连接到使用 DTR/DSR 流量控制的设备上的 DSR/DTR 引脚来获得它。DTR 流量控制与 DTR/DSR 流量控制相同,但它是单向的,并且仅使用设备上的 DTR 引脚。许多文本终端和一些打印机使用 DTR/DSR(或仅 DTR)流量控制。将来,Linux 可能会支持 DTR/DSR 流量控制。该软件已经编写完毕,但不清楚何时(或是否)将其纳入串行驱动程序中。

DTR 和 DSR 的正常用途(不是用于流量控制)如下:设备置位 DTR 表示其已通电并准备好运行。对于调制解调器,来自 PC 的 DTR 信号的含义取决于调制解调器的配置方式。复位 DTR 有时称为“挂断”,但它并不总是这样做。一种“挂断”(复位 DTR)的方法是使用命令 “stty 0” 将波特率设置为 0。尝试从“外部”终端执行此操作可能由于双接口问题而不起作用。请参阅 终端上的两个接口。对于内部调制解调器-串口,它在使用 minicom 的端口上工作正常,但如果端口使用 wvdial 则不起作用。为什么?

19.5 防止端口打开

如果 “stty -clocal”(或 getty 与复位的 “local” 标志一起使用),则串行端口在 DCD 获得置位 (+12 伏) 信号之前无法打开。


20. 电压波形

20.1 比特电压

在 RS-232 串行端口上,电压是双极性的(相对于地为正或负),幅度应约为 12 伏(有些是 5 或 10 伏)。对于发送和接收引脚,+12 伏是 0 位(有时称为“空格”),-12 伏是 1 位(有时称为“标记”)。这被称为反相逻辑,因为通常 0 位既是假又是负,而 1 位通常既是真又是正。尽管接收和发送引脚是反相逻辑,但其他引脚(调制解调器控制线)是正常逻辑,正电压为真(或“开”或“置位”),负电压为假(或“关”或“复位”)。零电压没有意义(除非它通常意味着设备已断电)。

允许一定的电压范围。规范规定,发送信号的幅度应在 5 到 15 伏之间,但绝不能超过 25 伏。任何低于 3 伏的接收电压都是未定义的(但某些设备会接受较低的电压作为有效电压)。有时会看到错误的说法,即电压通常为 5 伏(甚至 3 伏),但通常为 11-12 伏。如果您在 Mac 计算机上使用 EIA-422 (RS-422) 端口作为 RS-232(需要专用电缆)或 EIA-423 (RS-423),则电压实际上仅为 5 伏。此处的讨论假设为 12 伏。

请注意,正常的计算机逻辑通常只有几伏(5 伏曾经是标准),因此,如果您尝试在串行端口的 12 伏电压上使用为测试 3-5 伏计算机逻辑 (TTL) 而设计的测试设备,则可能会损坏测试设备。

20.2 字节的电压序列

当没有发送任何内容时,发送引脚 (TxD) 保持在 -12 V(标记)。要开始一个字节,它会跳到 +12 V(空格)作为起始位,并在起始位的持续时间(周期)内保持在 +12 V。接下来是数据字节的低位。如果是 0 位,则没有任何变化,线路在另一个位周期内保持在 +12 V。如果是 1 位,则电压从 +12 V 跳到 -12 V。之后是下一个位(如果是 1 则为 -12 V,如果是 0 则为 +12 V),等等。在最后一个数据位之后,可以发送一个奇偶校验位,然后是一个 -12 V(标记)停止位。然后,线路保持在 -12 V(空闲),直到下一个起始位。请注意,没有返回到 0 伏电压,因此,对于 2 个连续位具有相同极性(都为零或都为一)的情况,除了同步信号之外,没有简单的方法来判断一个位在哪里结束,下一个位在哪里开始。

第二个停止位也将是 -12 V,与第一个停止位相同。由于没有信号来标记这些位之间的边界,因此第二个停止位的唯一效果是线路必须保持在 -12 V 空闲状态的时间是原来的两倍。接收器无法检测到第二个停止位和字节之间更长的空闲时间之间的差异。因此,如果一端使用一个停止位,而另一端使用 2 个停止位,则通信工作正常,但仅使用一个停止位显然更快。在极少数情况下,使用 1 1/2 个停止位。这意味着线路保持在 -12 V 的时间为 1 1/2 个周期(就像停止位比正常宽度宽 50%)。

20.3 奇偶校验解释

字符通常以 7 或 8 位数据传输。可以将额外的奇偶校验位附加到此,从而产生 7、8 或 9 位的字节长度。一些终端仿真器和较旧的终端不允许 9 位。如果使用 2 个停止位,则有些禁止 9 位(因为这将使总位数太大:在添加起始位后总共 12 位)。

奇偶校验可以设置为奇校验、偶校验或无校验(标记和空格奇偶校验可能是某些终端或其他串行设备上的选项)。对于奇校验,选择奇偶校验位,使字节中 1 位的数量(包括奇偶校验位)为奇数。如果这样的字节因位被翻转而损坏,则结果将是奇偶校验为偶数的非法字节。将检测到此错误,如果是终端的传入字节,则错误字符符号将出现在屏幕上。偶校验的工作方式类似,所有合法字节(包括奇偶校验位)都具有偶数个 1 位。在设置期间,每个字符的位数通常仅表示每个字节的数据位数(对于真正的 ASCII 为 7,对于各种 ISO 字符集为 8)。

“标记”是 1 位(或逻辑 1),“空格”是 0 位(或逻辑 0)。对于标记奇偶校验,奇偶校验位始终为 1 位。对于空格奇偶校验,它始终为 0 位。标记或空格奇偶校验(也称为“粘性奇偶校验”)只会浪费带宽,如果可行,应避免使用。stty 命令无法设置粘性奇偶校验,但串行硬件支持它,并且可以通过 C 编程来处理。“无奇偶校验”意味着不添加奇偶校验位。对于不允许 9 位字节的终端,当使用 8 位字符集时,必须选择 “无奇偶校验”,因为没有奇偶校验位的空间。

20.4 形成字节(成帧)

在通过 RS-232 端口进行字节的串行传输中,始终首先发送低位(位顺序)。PC 上的串行端口使用异步通信,其中有一个起始位和一个停止位来标记字节的开始和结束。这称为成帧,成帧字节有时称为帧。因此,每个字节总共发送 9、10 或 11 位,其中 10 位是最常见的。8-N-1 表示 8 个数据位,无奇偶校验,1 个停止位。当计算起始位时,这总共加起来为 10 位。几乎普遍使用一个停止位。在 110 位/秒(有时在 300 位/秒)时,曾经使用过 2 个停止位,但今天,第二个停止位仅在非常不寻常的情况下使用(或因错误而使用,因为它仍然可以正常工作,但会浪费带宽)。

不要将这种类型的成帧与用于网络上字节包的成帧混淆。串行端口只对每个字节进行成帧。对于网络,许多字节被成帧到一个数据包(有时称为帧)中。对于网络帧,不是起始位,而是一系列称为标头的字节。在使用串行端口(带调制解调器)的网络上,帧错误的报告通常是指多字节帧,而不是单个字节的串行端口帧。

20.5 “异步”是如何同步的

在 PC 上实现的 RS-232 串行端口是异步的,这实际上意味着没有与 “滴答” 一起发送的 “时钟” 信号来标记何时发送每个比特。发送(或接收)线只有两种状态:标记(-12 V)或空格 (+12 V)。没有 0 V 状态。因此,1 位序列通过稳定的 -12 V 传输,比特之间没有任何类型的标记。为了使接收器检测到单个比特,它必须始终具有与发送器时钟同步的时钟信号。这样的时钟将生成与每个发送(或接收)的比特同步的“滴答”。

对于异步传输,同步是通过用起始位和停止位对每个字节进行成帧来实现的(由硬件完成)。接收器在负极线上监听正起始位,当它检测到一个起始位时,它开始其时钟滴答。它使用此时钟滴答来定时读取接下来的 7、8 或 9 位。(实际上,这比这稍微复杂一些,因为通常会采集一个比特的几个样本,这需要额外的定时滴答。)然后读取停止位,时钟停止,接收器等待下一个起始位。因此,异步实际上在单个字节的接收期间是同步的,但是一个字节和下一个字节之间没有同步。


21. 其他串行设备(非异步 RS-232)

21.1 RS-232 的后继者

已经为使用双绞线(平衡)技术的更高速度和更长距离建立了一些 EIA(或 RS)标准。平衡传输使更高的速度成为可能,并且可以比不平衡的 RS-232 快一千倍。对于给定的速度,使用双绞线时,距离(最大电缆长度)可能会长很多倍。但是,大约 2004 年之前的 PC?? 仍然使用准过时的 RS-232 制造,因为它与调制解调器和鼠标配合良好,因为电缆长度很短。

高速串行端口(超过 460.8 kbps)通常将支持 RS-232 和 EIA-485/EIA-422 (RS-485/RS-422) 模式。(请注意,对于非 RS-232,我使用了 “EIA” 名称,而不是更常用的 “RS”,但它们都表示相同的含义。)在如此高的速度下,RS-232 没有太多用处(除了非常短的电缆)。

21.2 EIA-422-A(平衡)和 EIA-423-A(不平衡)

EIA-423 就像不平衡的 RS-232,只是电压仅为 5 伏。由于这在 RS-232 规范范围内,因此可以连接到 RS-232 端口。其规范要求比 RS-232 稍高的速度(但这可能对长距离运行没有太大帮助,在长距离运行中,不平衡会导致干扰)。由于 EIA-423 对 RS-232 的改进不大,因此很少使用,除非在旧的 Mac 计算机上。

EIA-422 是双绞线(称为 “平衡” 或 “差分”),并且(根据规范)比 EIA-423 快 100 倍(EIA-423 反过来比 RS-232 稍快)。Apple 的 Mac 计算机在 1998 年中期之前将其与 RS-232/EIA-422 端口一起使用。Mac 使用小型圆形 “mini-DIN-8” 连接器,并将这些串行端口命名为 “调制解调器端口”、“打印机端口” 和/或 “GeoPort”。

Mac 还提供了传统的 RS-232,但电压仅为 5 伏(这仍然是合法的 RS-232)。要使其像 RS-232 一样工作,必须使用专用电缆,该电缆(信号)将 RxD+(平衡对的一侧)接地,并将 RxD- 用作接收引脚。虽然 TxD- 用作发送引脚,但由于某种原因,TxD+ 不应接地。请参阅 Macintosh 通信常见问题解答。但是,由于 Mac(及其升级)的成本高于 PC,因此它们作为 Linux 的主机计算机并不普及。

21.3 EIA-485

这类似于 EIA-422(平衡 = 差分)。它是半双工的。它不仅仅是点对点的,而是像以太网或 USB,因为其上的所有设备(节点)共享同一条 “总线”。它可用于多点 LAN(最多 32 个或更多节点)。不幸的是,Linux 当前不支持此功能,您只能在 Linux 下将其用于点对点,在这种情况下,它的行为类似于 RS-232。因此,只有当您对 Linux 支持它们时其功能如何工作感到好奇时,才继续阅读。

由于许多节点共享同一条双绞线,因此需要使用电气三态模式。因此,除了 0 和 1 二进制状态之外,还有开路状态,以允许其他节点使用双绞线线路。发送器不会在线路空闲期间在线路上保持 1 状态电压,而是将线路开路,所有节点都只是监听(接收模式)。

最常见的架构是主/从模式。主设备轮询从设备,以查看它们是否有任何数据要发送。从设备只能在被轮询后立即发送数据。但是 EIA-485 仅仅是一个电气规范,并没有指定任何用于主/从交互的协议。实际上,它甚至没有规定必须有一个主设备和从设备。因此,已经使用了各种协议。根据 2003 年 3 月在 linux-serial 邮件列表上关于 485 的讨论,似乎 Linux 当前不支持这些主/从协议中的任何一个。

还有一种替代实现方案,其中使用两对线来发送数据。一对线仅供主设备发送到从设备。由于除了主设备之外没有人在此线路上发送数据,因此不需要三态。因此,主设备可能只是 RS-232,但从设备仍然必须是 EIA-485。有关更多详细信息,请参阅 http://www.hw.cz/english/docs/rs485/rs485.html

21.4 EIA-530

EIA-530-A(平衡式,但也可以用作非平衡式)在 2Mbits/s(平衡式)的速度下,旨在替代 RS-232,但安装数量很少。它使用与 RS-232 相同的 25 针连接器。

21.5 EIA-612/613

高速串行接口(HSSI = EIA-612/613)使用 50 针连接器,速度高达约 50 Mbits/s,但距离仅限于几米。对于 Linux,有 PCI 卡支持 HSSI。销售这些卡的公司通常提供(或指向)Linux 驱动程序。需要一个关于此主题的 HOWTO 或类似文档。

21.6 通用串行总线 (USB)

通用串行总线 (USB) 正在被内置到 PCI 芯片中。较新的 PC 都配备了 USB 接口。最初的速度为 12 Mbps,但现在通过双绞线和 4 针连接器(2 根线是电源)可达 480 Mbps。它也限制在短距离内,最多 5 米(取决于配置)。Linux 支持 USB 总线,但并非所有可以插入总线的设备都受支持。

它是同步的,并像网络一样以特殊的数据包进行传输。就像网络一样,它可以连接多个物理设备,包括串行端口。每个设备在其上获得短暂的独占使用时间片。设备也可以保证在固定的时间间隔内使用总线。如果没有其他设备想要使用总线,则一个设备可以垄断它。详细描述它并不简单。

对于 USB 总线上的串行端口,在编译内核时有许多配置选项可供使用。它们都以:CONFIG_USB_SERIAL 开头。每个选项通常针对特定品牌/型号的串行端口,尽管也有通用选项。请参阅内核文档中的配置帮助文件。

有关文档,请参阅 /usr/share/doc/kernel 中的 USB 目录 ... 并查看文件:usb-serial.txt。支持 usb 串行设备的模块位于模块树中:kernel/drivers/usb/serial。最好能有一个关于 USB 的 HOWTO。另请参阅 http://www.linux-usb.org 和/或 http://www.qbik.ch/usb/

21.7 火线 (Firewire)

火线 (IEEE 1394) 有点像 USB,但速度更快(计划为 800 Mbps)。据称总线上的协议比 USB 的效率更高。它使用两对双绞线用于数据传输,加上两根电源线(总共 6 根线)。一种变体仅使用 4 根线。您可以将火线支持编译到 Linux 内核中。与 USB 一样,它也限制在短距离内。

21.8 MIDI

声卡通常有一个 15 针游戏端口连接器,用于 MIDI。它们用于将乐器键盘连接到 PC,以便您可以创建音乐录音。您也可以连接 MIDI 音响系统。MIDI 标准使用 31250 波特率(1M/32),这在普通的串行端口上是不可用的。一些 MIDI 设备的设计使其可以直接连接到普通的串行端口。

除了 15 针连接器外,5 针 DIN 连接器也是 MIDI 标准,但声音的流动仅是单向的,因此对于双向声音,您需要 2 个。分线电缆通常在一端有一个 15 针连接器,在另一端有 2 个或更多 5 针连接器。/dev/midi00 用于 MIDI。

21.9 同步和同步

除了异步 RS-232(和其他)之外,还有许多同步串行端口标准。实际上,RS-232 包括同步规范,但它们通常不在 PC 的串行端口上实现。但首先我们将解释什么是同步。

定义异步与同步

异步(async)意味着“非同步”。在实践中,异步信号是异步串行端口发送和接收的信号,它是由起始位和停止位构成的字节流。同步(sync)是几乎所有其他情况。但这并没有解释基本概念。

理论上,同步意味着字节以恒定的速率一个接一个地发送出去,与时钟信号滴答同步。通常有一根单独的线或通道用于发送时钟信号。时钟信号也可能嵌入在传输的字节中。异步字节可能以不规则的方式发送出去,字节之间的时间间隔各不相同(就像有人在键盘上键入字符一样)。

当通过异步串行端口发送文件时,字节流的速度很可能与端口的速度相同(例如 115.2k),这是一个恒定的速率。这种流动可能由于流控制而频繁地开始和停止。这是同步还是异步?忽略流控制停止,它可能看起来像同步,因为它是一个稳定的流动。但事实并非如此,因为没有时钟信号,并且字节可能是以不规则的方式发送的,因为它们是由起始位/停止位构成的。

另一种情况是将数据字节(没有任何起始停止位)放入数据包中,数据包之间可能存在不规则的间隔。这称为同步,因为每个数据包内的字节是同步传输的。

同步通信

您是否曾经想过 25 针串行端口连接器上所有未使用的引脚是做什么用的?它们中的大多数用于同步通信,而同步通信很少在 PC 的芯片中实现。有用于同步定时信号以及同步反向通道的引脚。RS-232 规范同时提供了同步和异步,但 PC 使用 UART(通用异步接收器/发送器)芯片,例如 16450、16550A 或 16650,并且无法处理同步。对于同步,需要 USRT 芯片或等效芯片,其中“S”代表同步。USART 芯片同时支持同步和异步。由于同步是一个小众市场,因此同步串行端口很可能非常昂贵。

SCC 代表“串行通信控制器”或“串行控制器芯片”。这可能是旧的术语,并且由于它没有说“同步”或“异步”,因此它可能同时支持两者。

除了 RS-232 的同步部分外,还有各种其他 EIA 同步标准。对于 RS-232,连接器的 3 个引脚保留用于时钟(或定时)信号。有时,调制解调器的任务是生成一些定时信号,这使得在没有同步调制解调器(或没有称为“同步调制解调器消除器”的设备,该设备提供定时信号)的情况下无法使用同步通信。

尽管很少有串行端口是同步的,但同步通信通常确实通过使用调制解调器的电话线进行,这些调制解调器使用 V.42 纠错。这会剥离起始位/停止位,并将数据字节放入数据包中,从而在电话线上实现同步操作。


22. 其他信息来源

22.1 书籍

  1. Axleson, Jan: Serial Port Complete, Lakeview Research, Madison, WI, 1998。
  2. Black, Uyless D.: Physical Layer Interfaces & Protocols, IEEE Computer Society Press, Los Alamitos, CA, 1996。
  3. Campbell, Joe: The RS-232 Solution, 2nd ed., Sybex, 1982。
  4. Campbell, Joe: C Programmer's Guide to Serial Communications, 2nd ed., Unknown Publisher, 1993。
  5. Levine, Donald: POSIX Programmer's Guide, O'Reilly, 1991。
  6. Nelson, Mark: Serial Communications Developer's Guide, 2nd ed., Hungry Minds, 2000。
  7. Putnam, Byron W.: RS-232 Simplified, Prentice Hall, 1987。
  8. Seyer, Martin D.: RS-232 Made Easy, 2nd ed., Prentice Hall, 1991。
  9. Stevens, Richard W.: Advanced Programming in the UNIX Environment, (ISBN 0-201-56317-7; Addison-Wesley)
  10. Tischert, Michael & Bruno Jennrich: PC Intern, Abacus 1996。第 7 章:串行端口

关于书籍的注释

  1. “... Complete”具有硬件细节(包括寄存器),但编程方面以 Windows 为导向。
  2. “Physical Layer ...”涵盖的内容远不止 RS-232。

22.2 串行软件

如果在您的 Linux 发行版中不可用,请尝试
串行软件,其中包含用于串行端口的 Linux 软件,包括 getty 和端口监视器。
串行通信,其中包含通信程序。

22.3 相关的 Linux 文档

22.4 串行邮件列表

Linux 串行邮件列表。要加入,请发送电子邮件至 majordomo@vger.kernel.org,邮件正文包含 ``subscribe linux-serial''。如果您在邮件正文中发送 ``help'',您将收到帮助消息。该服务器还服务于许多其他 Linux 列表。发送 ``lists'' 命令以获取邮件列表列表。

22.5 互联网


23. 附录 A:非常过时的硬件/软件

23.1 更换 1990 年之前的 UART

许多 486 PC(旧的)和所有奔腾(或类似的)都应该具有带 FIFO 的现代 16550A(通常简称为 16550)。如果您有非常旧的东西(1990 年之前),则芯片可能会被拔下,以便您可以通过找到插入式 16550A 芯片并替换旧的 16450 UART 来进行升级。如果功能已内置到另一种类型的芯片中,那么您就无能为力了。如果 UART 是插座式的,那么如果您能找到替代品,升级将很容易。新的和旧的是引脚到引脚兼容的。在互联网上购买新的串行卡(截至 2000 年,很少有零售商店备货)或找到二手串行卡可能更可行。

23.2 具有相同 IO 地址的两个端口

现代内核不应允许打开具有相同 IO 地址的端口。但是,即使端口未打开,也可以探测端口。如果两个端口具有相同的 IO 地址,则通过向该地址发送命令进行的旧式探测将错误地指示只有一个端口。但是,启动时的调制解调器设备检测应该会发现两个端口并报告冲突。在过去,对于非法尝试使用相同 IO 地址的设备,报告/观察到各种错误。请参阅 探测

23.3 通过修改源代码进行配置

过去,为了获得对某个串行端口的支持,可能需要修改 C 源代码,可能是通过向其中添加 #define。如今,模块或内核的参数的使用,或配置选项的使用应处理所有情况(除非可能用于古董硬件??)。

23.4 用于以 56k 速度发送数据的多端口卡上的调制解调器已过时

为了使调制解调器以接近 56k 的速度传输,它需要是特殊的数字调制解调器,并且具有到数字电话线(例如 T1 线)的数字连接。与串行卡一起使用的调制解调器(调制解调器可能在串行卡上或在另一张卡上)通常没有这样的数字连接,因此它们不能以 56k 的速度使用,因此除非不需要以 56k 的速度发送数据,否则它们是过时的。换句话说,对于 ISP 服务器来说它们是过时的,但对于小型企业或家庭使用来说可能还可以。

上述情况的一个部分例外是连接到多端口串行卡的调制解调器组,其中调制解调器组可以访问多路复用数字电话线。因此,可以使用带有几个 56k 数字调制解调器的多端口串行卡以 56k 的速度发送数据。对于模拟和数字调制解调器,每个串行端口上都有一个调制解调器,因此需要为每个调制解调器提供外部电缆(调制解调器组到多端口)。这可能会导致大量电缆。因此,使用没有多端口卡的内部调制解调器可以减少杂乱(也更便宜)。这使得即使是这种“例外”对于高容量工作来说也是过时的。这有点类似于台式 PC 的内部调制解调器的较低成本,与外部调制解调器的较高成本(和更多布线)相比。请参阅 Modem-HOWTO:调制解调器池,数字调制解调器。

23.5 如果您使用了已弃用的 devfs,则使用锁定文件

已废弃的设备文件系统 (devfs) 具有带有子目录的 /dev 目录。截至 2001 年末,锁定文件存在问题。例如,锁定文件机制认为 dev/usb/tts/0 和 /dev/tts/0 是名称为“0”的相同设备。对于所有其他具有相同“叶”名称的设备也是如此。此外,如果某些应用程序使用设备的旧名称,而其他应用程序使用同一设备的 devfs 名称,则锁定文件将具有不同的名称。但是串行驱动程序应该知道它们是相同的。

23.6 Devfs(已弃用的设备文件系统。历史)

内核 2.4 引入了现在已过时的可选“设备文件系统” (devfs),它为所有内容提供了一组全新的名称。有些人使用它,但大多数人可能没有使用。但在 2003-4 年,有人声称 devfs 存在无法解决的问题,并且从内核 2.6.12 开始,它被“udev”取代(2.6.12 之前的内核也可以使用 udev,但存在一些问题)。尽管 udev 没有提供 devfs 的所有功能,但它确实处理热插拔。此外,运行 Linux 不需要使用 udev,因此有些人不使用它。但是许多发行版默认安装它。

Devfs 是一个好主意,并且据称比 udev 更有效率。但不幸的是,devfs 的作者没有长期维护它,据称维护得不太好。因此,无论好坏,我们现在都使用 udev 代替,尽管关于 devfs 与 udev 的争论仍在继续。有关 devfs 的详细描述,请参阅:http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html 另请参阅内核文档树:filesystems/devfs。

devfs 的设备名称可以在 udev 中使用,但通常不使用,并且可能不容易激活。以下是串行设备的 devfs 名称:ttyS1 变为 tts/1,ttyUSB1 变为 /usb/tts/1,ttyACM1 变为 /usb/acm/1。请注意,上面的数字 1 只是一个示例。它可以替换为 0、2、3、4 等。udev 名称的更多示例:ttyS2 变为 tts/2(串行端口),tty3 变为 vc/3(虚拟控制台),ptyp1 变为 pty/m1(PTY 主设备),ttyp2 变为 pty/s2(PTY 从设备)。“tts”看起来像一个目录,其中包含设备“文件”:0、1、2 等。所有这些新名称都放在 /dev 目录中,尽管可以选择将它们放在其他地方。

对于 devfs,/dev 目录中的设备名称由相应的驱动程序自动创建。因此,如果串行支持来自模块,并且该模块尚未加载,则 /dev 目录中将没有任何串行设备。这可能会令人困惑:您物理上拥有串行端口,但在 /dev 目录中看不到它们。但是,如果通信程序请求设备名称(尝试打开它)并且串行模块未加载,则内核应该尝试为其找到驱动程序并在 /dev 目录中为其创建一个名称。

如果它找到驱动程序,这可以正常工作。但是,假设没有为其找到驱动程序。例如,如果您尝试使用“setserial”来配置驱动程序未能检测到的端口,它会声称没有这样的端口。在这种情况下,如何创建 devfs 端口?

例如,对于多端口设备,/dev/ttyF9 变为 /dev/ttf/9,或在更高版本中变为 /dev/tts/F9。将 F(或 f)替换为您的多端口板为此目的使用的任何字母。多端口驱动程序应该创建一个类似于上述的 devfs 名称,并将其放入 /dev 目录中

串行 HOWTO 结束