这里提供一些通用端口的编程信息,这些端口可以直接用于通用 TTL(或 CMOS)逻辑 I/O。
如果您想将这些或其他通用端口用于其预期目的(例如,控制普通打印机或调制解调器),您应该最有可能使用现有的驱动程序(通常包含在内核中),而不是像本 HOWTO 所描述的那样直接对端口进行编程。本节的目标读者是那些希望将 LCD 显示器、步进电机或其他定制电子设备连接到 PC 标准端口的人。
如果您想控制大众市场设备(如已上市一段时间的扫描仪),请查找现有的 Linux 驱动程序。Hardware-HOWTO 是一个很好的起点。
http://www.hut.fi/Misc/Electronics/ 是获取有关将设备连接到计算机(以及一般电子设备)的更多信息的好来源。
并行端口的基地址(以下称为“BASE
”)对于 /dev/lp0
是 0x3bc,对于 /dev/lp1
是 0x378,对于 /dev/lp2
是 0x278。如果您只想控制类似普通打印机的设备,请参阅 Printing-HOWTO。
除了下面描述的标准只输出模式外,大多数并行端口还具有“扩展”双向模式。有关此模式和较新的 ECP/EPP 模式(以及 IEEE 1284 标准)的信息,请参阅 http://www.fapo.com/ 和 http://www.senet.com.au/~cpeacock/parallel.htm。请记住,由于您无法在用户模式程序中使用 IRQ 或 DMA,您可能需要编写内核驱动程序才能使用 ECP/EPP;我认为有人正在编写这样的驱动程序,但我不知道详细信息。
端口 BASE+0
(数据端口)控制端口的数据信号(D0 到 D7 分别对应位 0 到 7;状态:0 = 低电平 (0 V),1 = 高电平 (5 V))。写入此端口会将数据锁存在引脚上。在标准或扩展写入模式下,读取操作返回上次写入的数据;在扩展读取模式下,读取操作返回来自另一设备引脚的数据。
端口 BASE+1
(状态端口)是只读的,并返回以下输入信号的状态
端口 BASE+2
(控制端口)是只写的(读取操作返回上次写入的数据),并控制以下状态信号
引脚排列(端口上的 25 针母 D 型连接器)(i=输入,o=输出)
1io -STROBE, 2io D0, 3io D1, 4io D2, 5io D3, 6io D4, 7io D5, 8io D6,
9io D7, 10i ACK, 11i -BUSY, 12i PE, 13i SLCT, 14o -AUTO_FD_XT,
15i ERROR, 16o INIT, 17o -SLCT_IN, 18-25 Ground
IBM 规范说明引脚 1、14、16 和 17(控制输出)具有通过 4.7 千欧姆电阻上拉至 5 V 的集电极开路驱动器(灌电流 20 mA,源电流 0.55 mA,高电平输出 5.0 V 减去上拉)。其余引脚灌电流 24 mA,源电流 15 mA,其高电平输出最小值为 2.4 V。两者的低电平状态最大值为 0.5 V。非 IBM 并行端口可能偏离此标准。有关此的更多信息,请参阅 http://www.hut.fi/Misc/Electronics/circuits/lptpower.html。
最后,一个警告:请注意接地。我通过在计算机开机时连接到并行端口而损坏了几个并行端口。对于此类操作,最好使用未集成在主板上的并行端口。(您通常可以使用廉价的标准“多 I/O”卡为您的机器获得第二个并行端口;只需禁用您不需要的端口,并将卡上的并行端口 I/O 地址设置为空闲地址即可。如果您不使用并行端口 IRQ,则无需关心它。)
游戏端口位于端口地址 0x200-0x207。如果您想控制普通的操纵杆,您最好使用 Linux 内核附带的驱动程序。
引脚排列(端口上的 15 针母 D 型连接器)
+5 V 引脚似乎通常直接连接到主板上的电源线,因此它们可能能够提供相当大的功率,具体取决于主板、电源和游戏端口。
数字输入用于连接到端口的两个操纵杆(操纵杆 A 和操纵杆 B,每个操纵杆有两个按钮)的按钮。它们应该是正常的 TTL 电平输入,您可以直接从状态端口读取其状态(见下文)。真正的操纵杆在按钮按下时返回低电平 (0 V) 状态,否则返回高电平(来自电源引脚的 5 V,通过 1 千欧姆电阻)。
所谓的模拟输入实际上测量电阻。游戏端口有一个四路单稳态多谐振荡器(558 芯片)连接到四个输入。在每个输入中,输入引脚和多谐振荡器输出之间有一个 2.2 千欧姆电阻,多谐振荡器输出和地之间有一个 0.01 uF 定时电容器。真正的操纵杆为每个轴(X 轴和 Y 轴)配备一个电位器,电位器连接在 +5 V 和相应的输入引脚之间(操纵杆 A 为 AX 或 AY,操纵杆 B 为 BX 或 BY)。
多谐振荡器激活后,将其输出线设置为高电平 (5 V),并等待每个定时电容器达到 3.3 V,然后降低相应的输出线。因此,多谐振荡器的高电平持续时间与操纵杆中电位器的电阻(即操纵杆在相应轴上的位置)成正比,如下所示
R = (t - 24.2) / 0.011,其中 R 是电位器的电阻(欧姆),t 是高电平持续时间(微秒)。
因此,要读取模拟输入,您首先激活多谐振荡器(通过端口写入;见下文),然后轮询四个轴的状态(通过重复端口读取),直到它们从高电平降至低电平状态,测量它们的高电平持续时间。这种轮询会占用大量 CPU 时间,并且在像(普通用户模式)Linux 这样的非实时多任务系统中,结果不是很准确,因为您无法持续轮询端口(除非您使用内核级驱动程序并在轮询时禁用中断,但这会浪费更多 CPU 时间)。如果您知道信号将需要很长时间(数十毫秒)才能下降,您可以调用 usleep() 在轮询之前将 CPU 时间交给其他进程。
您需要访问的唯一 I/O 端口是端口 0x201(其他端口的行为相同或不执行任何操作)。对该端口的任何写入(您写入的内容无关紧要)都会激活多谐振荡器。从该端口读取会返回输入信号的状态
如果您要与之通信的设备支持类似于 RS-232 的协议,您应该可以使用串行端口与之通信。Linux 串行驱动程序应该足以满足几乎所有应用程序的需求(您不应该直接对串行端口进行编程,并且您可能必须编写内核驱动程序才能做到这一点);它非常通用,因此使用非标准 bps 速率等应该不成问题。
有关在 Unix 系统上对串行端口进行编程的更多信息,请参阅 termios(3)
手册页、串行驱动程序源代码 (linux/drivers/char/serial.c
) 和 http://www.easysw.com/~mike/serial/。