📄 io-port-programming-6.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">
<META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.7">
<TITLE>如何在 Linux 下撰写程式来使用 I/O 埠: 一些有用的 I/O 埠</TITLE>
<LINK HREF="IO-Port-Programming-7.html" REL=next>
<LINK HREF="IO-Port-Programming-5.html" REL=previous>
<LINK HREF="IO-Port-Programming.html#toc6" REL=contents>
</HEAD>
<BODY>
<A HREF="IO-Port-Programming-7.html">Next</A>
<A HREF="IO-Port-Programming-5.html">Previous</A>
<A HREF="IO-Port-Programming.html#toc6">Contents</A>
<HR>
<H2><A NAME="s6">6. 一些有用的 I/O 埠</A></H2>
<P>本节提供一些常用 I/O 埠的程式撰写资讯这些都是可以直接拿来用的一般目的
TTL (或 CMOS) 逻辑位准的 I/O 埠.
<P>如果你要按照其原始的设计目的来使用这些或其他常用的I/O 埠
(例如, 控制一般的印表机或数据机), 你应该会使用现成的装置驱动程式
(他通常被含在核心中) 而不会如本文所说地去撰写 I/O 埠程式.
本节主要是提供给那些想要将 LCD 显示器, 步进马达, 或是其他商业电子产品
连接到 PC 标准 I/O 埠的人.
<P>如果你想要控制大众市场所贩卖的装置像是扫描器 (已经在市场贩卖了一段期间),
去找看看是否有现成的 Linux 装置驱动程式.
网页
<A HREF="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Hardware-HOWTO">Hardware-HOWTO</A> 是个好的参考起点.
<P>至於想要知道更多有关如何连接电子装置到电脑(以及一般的电子学原理)的相关资讯则网页
<A HREF="http://www.hut.fi/Misc/Electronics/">http://www.hut.fi/Misc/Electronics/</A> 是个好的资料来源.
<P>
<P>
<H2><A NAME="ss6.1">6.1 并列埠 (parallel port)</A>
</H2>
<P>并列埠的基本埠位址 (以下称之为 ``<CODE>BASE</CODE>'') 之於 <CODE>/dev/lp0</CODE>
是 0x3bc , 之於 <CODE>/dev/lp1</CODE> 是 0x378 , 之於 <CODE>/dev/lp2</CODE> 是 0x278 .
如果你只是想要控制一些像是一般印表机的动作, 可以参考网页
<A HREF="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Printing-HOWTO">Printing-HOWTO</A>.
<P>除了下面即将描述的标准仅输出 (output-only) 模式, 大多数的并列埠都有 `扩充的'
双向 (bidirectional) 模式. 至於较新的 ECP/EPP 模式 (以及一般的 IEEE 1284 标准) 埠口的相关资料,
可以参考网页
<A HREF="http://www.fapo.com/">http://www.fapo.com/</A> 以及
<A HREF="http://www.senet.com.au/~cpeacock/parallel.htm">http://www.senet.com.au/~cpeacock/parallel.htm</A>.
因为在使用者模式 (user-mode) 中的程式无法使用 IRQs 或 DMA, 想要使用 ECP/EPP
模式你或许得撰写一个核心的装置驱动程式; 我想应该有人写了这类的装置驱动程式,
但是详情我并不知道.
<P>埠位址 <CODE>BASE+0</CODE> (资料埠) 用来控制资料埠的信号位准 (D0 到 D7 分别代表著
bits 0 到 7, 位准状态: 0 = 低位准 (0 V), 1 = 高位准 (5 V)).
一个写入资料到该埠的动作会将资料信号位准拴住 (latches) 在埠的脚位 (pins) 上.
一个将该埠的资料读出的动作会将上一次以标准仅输出 (output-only)
模式或扩充的写入模式所拴住的资料信号位准读回, 或是以扩充读出模式 从另外一
个装置将脚位上的资料信号位准读回.
<P>埠位址 <CODE>BASE+1</CODE> (状态埠) 是个仅读 (read-only) 的埠, 会将下面的输入信号位准读回:
<UL>
<LI>Bits 0 和 1 保留不用.</LI>
<LI>Bit 2 IRQ 的状态 (不是个脚位 (pin) , 我不知道他的工作原理)</LI>
<LI>Bit 3 ERROR (1=高位准)</LI>
<LI>Bit 4 SLCT (1=高位准)</LI>
<LI>Bit 5 PE (1=高位准)</LI>
<LI>Bit 6 ACK (1=高位准)</LI>
<LI>Bit 7 -BUSY (0=高位准)</LI>
</UL>
(我不确定高低位准的电压状态.)
<P>埠位址 <CODE>BASE+2</CODE> (控制埠) 是个仅写 (write-only) 的埠
(一个将该埠的资料读出的动作仅会将上一次写入的资料信号位准读回), 用来控制下面的状态信号:
<UL>
<LI>Bit 0 -STROBE (0=高位准)</LI>
<LI>Bit 1 AUTO_FD_XT (1=高位准)</LI>
<LI>Bit 2 -INIT (0=高位准)</LI>
<LI>Bit 3 SLCT_IN (1=高位准)</LI>
<LI>Bit 4 当被设定为 1 时允许并列埠产生 IRQ 信号
(发生在 ACK 脚位的位准由低变高的瞬间) </LI>
<LI>Bit 5 用来控制扩充模式时埠的输出入方向 (0 = 写, 1 = 读),
这是个仅写 (write-only) 的埠 (一个将该埠的资料读出的动作对此 bit 一点用处也没有).</LI>
<LI>Bits 6 and 7 保留不用.</LI>
</UL>
(同样地, 我不确定高低位准的电压状态.)
<P>埠的脚位排列 (Pinout) 方式 (该埠是一个 25 只脚 D 字形外壳 (D-shell) 的母头连接器)
(i=输入, o=输出):
<BLOCKQUOTE><CODE>
<PRE>
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
</PRE>
</CODE></BLOCKQUOTE>
<P>IBM 的规格文件上说脚位 1, 14, 16, 和 17 (控制信号的输出) 采用电晶体的开集极
(open collector) 驱动方式必需使用 4.7 仟欧姆 (kiloohm) 的提升电阻接至
5 V 的电压 (可流入电流 20 mA, 流出电流 0.55 mA, 高位准的输出电压就是
5.0 V 减去提升电阻的电压). 剩下来的脚位可流入电流 24 mA, 流出电流 15 mA,
高位准的输出电压最小 2.4 V. 低位准的输出电压二者都是最大 0.5 V.
那些非 IBM 规格的并列埠或许会偏离这个标准. 更多的相关资料请参考网页
<A HREF="http://www.hut.fi/Misc/Electronics/circuits/lptpower.html">http://www.hut.fi/Misc/Electronics/circuits/lptpower.html</A>.
<P>最後, 给你一个警告: 留心接地的问题. 我曾经在电脑还是开机的状况就去连接他因而
弄坏好几个并列埠. 发生了这种事情你可能会觉得还是不要将并列埠整
合到主机板里面比较好. (你通常可以拿一片便宜的标准 `multi-I/O' 卡安装第二个
并列埠; 只要将其他不需要的埠停用, 然後将卡片上并列埠的埠位址设定在
空著的位址即可. 你不需在意并列埠的 IRQ 设定, 因为通常不会被用到.)
<P>
<H2><A NAME="ss6.2">6.2 游戏 (操纵□) 埠 (game port)</A>
</H2>
<P>游戏埠的埠位址□围为 0x200-0x207. 想要控制一般的操纵□,
有一个核心层次的操纵□驱动程式, 可参考网址
<A HREF="ftp://sunsite.unc.edu/pub/Linux/kernel/patches/">ftp://sunsite.unc.edu/pub/Linux/kernel/patches/</A>,
档名 <CODE>joystick-*</CODE>.
<P>埠的脚位排列 (Pinout) 方式 (该埠是一个 15 只脚 D 字形外壳 (D-shell) 的母头连接器):
<UL>
<LI>1,8,9,15: +5 V (电源)</LI>
<LI>4,5,12: 接地</LI>
<LI>2,7,10,14: 分别是 BA1, BA2, BB1, 和 BB2 等数位输入</LI>
<LI>3,6,11,13: 分别是 AX, AY, BX, 和 BY 等``类比''输入</LI>
</UL>
<P>+5 V 的脚位似乎通常会被直接连接到主机板的电源线上, 所以他应该能够提供相当的电力,
这还要看所使用主机板, 电源供给器, 以及游戏埠的类型.
<P>数位输入用於操纵□的按钮可以让你连接二个操纵□的四个按钮 (操纵□ A 和 操纵□ B,
各有二个按钮) 到游戏埠也就是数位输入的四个脚位. 他们应该是一般 TTL 电压位准的输入,
你可以直接从状态埠 (参考下面说明) 读出他们的位准状态.
一个实际的操纵□在按钮被压下时会传回低位准 (0 V) 状态否则就是高位准
(5V 经由 1 Kohm 的电阻连接到电源脚位) 状态.
<P>所谓的类比输入实际是量测到的阻抗值. 游戏埠有四个单击多谐振□器
(one-shot multivibrator) (一个 558 晶片) 连接到四个类比输入脚位.
每个类比输入脚位与多谐振□器的输出之间连接著一个 2.2 Kohm 的电阻,
而且多谐振□器的输出与地之间连接著一个 0.01 uF 的时序电容
(timing capacitor). 一个实际的操纵□其每个座标 (X 和 Y) 上会有一个可变电阻,
连接在 +5 V 与每个相对的类比输入脚位之间 (脚位 AX 或 AY 是给操纵□ A 用的,
而脚位 BX 或 BY 是给操纵□ B用的).
<P>操作的时候, 多谐振□器将其输出设定为高位准 (5 V) 并且等到时序电容上的电压达到
3.3 V 之後将相对的输出设定为低位准. 因此操纵□中多谐振□器输出的高位准时间周期
与可变电阻的电阻值成正比 (也就是, 操纵□在相对座标的位置), 如下所示:
<BLOCKQUOTE>
R = (t - 24.2) / 0.011,
</BLOCKQUOTE>
其中 R 是可变电阻的阻抗值 (ohms) 而 t 是高位准时间周期的长度 (秒).
<P>因此要读出类比输入脚位的数值, 首先你得启动多谐振□器 (以埠写入的方式; 请看下面),
然後查询四个座标的信号状态(以持续的埠读出方式)一直到信号状态由高位准变成低位准,
计算其高位准时间周期的长度. 这个持续查询的动作花费相当多的 CPU 时间,
而且在一个非即时的多工环境像是 (一般的使用者模式 (user-mode) ) Linux,
所得的结果不是非常准确因为你无法以固定的时间来查询信号的状态
(除非你使用核心层次的驱动程式而且你得在你查询的时候抑制掉中断的产生,
但是这样做会浪费更多的 CPU 时间). 如果你知道信号的状态将会花费一段不短的时间
(数十毫秒) □会成为低位准, 你可以在查询之前呼叫函式 usleep() 将 CPU
的时间让给其他想要执行的行程 (processes).
<P>游戏埠中唯一需要你来存取的埠位址是 0x201 (其他的埠位址不是动作一样就是没用).
任何对这个埠位址所做的写入动作 (不论你写入什麽) 都会启动多谐振□器.
对这个埠位址做读出动作会取回输入信号的状态:
<UL>
<LI>Bit 0: AX ( (1=高位准) 多谐振□器的输出状态)</LI>
<LI>Bit 1: AY ( (1=高位准) 多谐振□器的输出状态)</LI>
<LI>Bit 2: BX ( (1=高位准) 多谐振□器的输出状态)</LI>
<LI>Bit 3: BY ( (1=高位准) 多谐振□器的输出状态)</LI>
<LI>Bit 4: BA1 (数位输入, 1=高位准)</LI>
<LI>Bit 5: BA2 (数位输入, 1=高位准)</LI>
<LI>Bit 6: BB1 (数位输入, 1=高位准)</LI>
<LI>Bit 7: BB2 (数位输入, 1=高位准)</LI>
</UL>
<P>
<P>
<H2><A NAME="ss6.3">6.3 串列埠 (serial port)</A>
</H2>
<P>如果你所说的装置是支援一些像是 RS-232 那类的东西, 你应该可以如你所愿地使用串列埠.
Linux 所提供的串列埠驱动程式应该能够应用在任何地方 (你应该不需要直接撰写串列埠程式,
或是核心的驱动程式); 他相当具有通用性, 所以像是使用非标准的 bps 速率以及其他等等应该不是问题.
请参考 <CODE>termios(3)</CODE> 说明文件, 串列埠驱动程式原始程式码
(<CODE>linux/drivers/char/serial.c</CODE>), 以及网页
<A HREF="http://www.easysw.com/~mike/serial/index.html">http://www.easysw.com/~mike/serial/index.html</A>
上有更多在 Unix 作业系统撰写串列埠程式的相关资料.
<P>
<HR>
<A HREF="IO-Port-Programming-7.html">Next</A>
<A HREF="IO-Port-Programming-5.html">Previous</A>
<A HREF="IO-Port-Programming.html#toc6">Contents</A>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -