原创 DOS下的并口编程

2008-7-17 22:37 2750 5 5 分类: 工业电子

DOS下的并口编程

凡是能够输出并行数据的端口(与串行端口相对应)都可以称之为并行端口,但应用过程中,并行端口总是和打印机联系在一起。在计算机工业中至少使用过四种不同的名称:并行打印机适配器、Centronics适配器、Centronics端口或简单地称为并行端口。


并行端口最早由Centronics Data Computer Corporation公司在60年代中期制定。Centronics公司当初是为点阵行式打印机设计的并行接口,1981年被IBM公司采用,后来成为IBM PC计算机的标准配置。它每次单向并行传输1字节(8-bit)数据,速度高于当时的串行接口,获得广泛应用,成为打印机的接口标准。在标准的并行并行端口上(SPP),包括8个输出的数据信号线,4个输出的控制信号线,5个输入的状态信号线,在I/O空间上有三个并行端口寄存器,分别是数据寄存器,控制寄存器和状态寄存器,每一条信号线都对应I/O寄存器上的一位,可以编程进行控制。缺点就是数据线只能单向输出,传输速率在200~300K bps。


增强型并行端口协议最初是由Intel、Xircom和Zenith Data System共同开发完成的,当初开发该协议的目的是寻求一种高性能的并行端口连接方式,并要满足向下兼容所有现存的并行接口和外设。Intel在360SL I/O控制芯片上使用了该协议。


为了给打印机端口定义新的协议而成立的IEEE 1284委员会于1994年3月发布了“PC机上的双向并行端口的标准信号方法”的标准协议,正是由于该标准才引出了Enhanced Parallel Port(EPP,增强型并行端口)的概念。它和Intel制订的协议有些细微的差别,Intel的协议称为EPP 1.7标准,IEEE 1284的协议称为EPP 1.9标准。在本文中,这个细微的差别对我们并没有影响,为了更放心地去描述,本文以IEEE 1284的EPP 1.9为依据。


IEEE 1284标准确定了数据传输协议,并为数据传输定义了物理和电气接口。不过,该标准并没有定义任何一个特殊的命令或者地址,它仅仅定义了一种发送数据的方法,因此,IEEE 1284标准属于一种低级的物理层协议。还有,它没有定义在一定条件下数据传输如何被主机中断,也没有确定EPP设备如何在准备好发送数据或者产生错误时向主机发出通知,这些都给了开发人员很大的自主权。同时,我在写这些内容也该感觉到困难,因为并口的程序开发总是和外设中的逻辑紧密相关。


根据主机适配器端口的实现和外设的性能,EPP可以达到500K bps到2M bps的数据传输速率。另外,还有一种扩展性能端口(ECP)协议,允许在并行适配器上共存多个逻辑设备,对传输数据的同时进行数据压缩。由于ECP远不如EPP应用的普遍,所以本文也不对它进行讨论了。


第二章 BIOS中的设置
我的电脑中,BIOS中对并口的设置是:
Intergrated Peripherals
……


Parallel Port Address
378
Parallel Port Mode
Normal
……


在BIOS设置的Intergrated Peripherals页中,端口地址是378,还有两个可选的地址是278,和3BC。并行端口模式是Normal,共4个选项[ Normal,EPP,ECP,EPP + ECP]。


我手中那个工控机小主板的设置也和上面类似,小主板说明书上有简要的介绍。Onboard Parallel Port:指定I/O端口的基地址,有四个选择[ Disabled,378h,278h,3BCh ]。Parallel Port Mode:指定端口的模式[ Normal,Bi-Dir,EPP,ECP ]。Bi-Dir:支持在并行端口上的双向传输。EPP:增强型并行端口,使用现有的并行端口信号提供对设备和主机之间异步双向传输的支持。ECP:扩展性能端口,使用DMA协议,数据传输速率达到每秒2.5M比特,支持双向异步通信。EPP Version:EPP 1.9 或者 1.7。Parallel Port IRQ:并行端口使用IRQ 5或者IRQ 7。


第三章 EPP的信号线和寄存器
1 信号线
这是是我们经常见到的25针打印机电缆公插头,然后在表格中列出每一条信号线的意义。因为每一根信号线和I/O寄存器中的一位是对应的,所以先在这里把对应寄存器的数据位也列出来。D表示数据寄存器,S表示状态寄存器,C表示控制寄存器,后面的数字表示第几位。在下一节将详细介绍并口的I/O寄存器。



线序
数据位
EPP信号
方向
描述
1
C0*
nWrite
输出
低电平有效,表示正在写,高电平表示正在读。
2-9
D1-D8
AD[1:8]
双向
双向地址/数据线。
10
S6
nINTR
输入
外围设备的中断信号,用来向主机发送中断请求
11
S7*
nWait
输入
握手信号,该信号处于低电平状态时,表明可以开始数据传输(通过设置选通信号),当处于高电平状态时,表明可以终止数据传输(通过取消选通信号)。
12
S5
user defined
输入
供外设使用
13
S4
user defined
输入
供外设使用
14
C1*
nDataStrobe
输出
低电平有效,表示正在写或者读数据。(数据选通信号)
15
S3
user defined
输入
供外设使用
16
C2
nReset
输出
低电平有效,外围设备的复位信号
17
C3*
nAddrStrobe
输出
低电平有效,表示正在写或者读地址。(地址选通信号)
18-25


ground



数据位后面的*表示,数据位和信号线相位相反,数据位是1时信号线低电平。


2 寄存器
EPP模式中的寄存器是对IBM标准并行端口(SPP)寄存器的延伸,它包含并扩展了SPP的三个寄存器。并行端口在I/O空间上的基地址一般可以由BIOS中设定(请看前一章),通常,并行端口一(LPT1)对应地地址是378h,并行端口二(LPT2)对应的地址是278h。


MS-DOS把大多数硬件的I/O地址信息都保存在内存中的一个确定的区域,也就是BIOS数据区。PC最多能辨认3个逻辑并行适配器,它们的I/O寄存器基地址分别保存在[40h:08h]、[40h:0Ah]、[40h:0Ch]共六个字节中,每个值占两个字节,如果等于0表示不存在这个适配器。有时候在BIOS中不能确认I/O地址时,会采用这种读内存的方法。


EPP的寄存器:
名称
偏移地址
类型
描述
SPP DATA
+0

一个字节,对应端口上8条数据线
SPP STATUS
+1

一个字节,读取外设传来的状态信号
SPP CONTROL
+2

一个字节,设置到外设的控制信号
EPP ADDRESS
+3
读/写
一个字节,产生“地址读”或者“地址写”周期
EPP DATA
+4
读/写
一个字节,产生“数据读”或者“数据写”周期

+5~+7
读/写
不确定


寄存器+5到+7有时候供各种各样的硬件设备使用有时候用来实现16位或者32位的软件接口,有时候可能作为配置寄存器来使用,而有时它们根本什么都不做。大多数的并口控制器使用它们来支持32位传输。


状态寄存器(SPP STATUS)和信号线的对应,后面的*表示数据位和信号线相位相反,数据位是1时信号线低电平。
7
6
5
4
3
2
1
0
nWait*
nINTR
//
//
//



控制寄存器(SPP CONTROL)和信号线的对应
7
6
5
4
3
2
1
0


Direction
IRQEN
nAddrStrobe*
nReset
nDataStrobe*
nWrite*
第4位是允许中断位,第5位是传输方向位,都不和信号线对应。


第四章 数据传输
一部教材前后章节的内容总是有交叉,前一部分知识是后一部分知识的基础,但是前一部分介绍的东西多多少少会涉及到后一部分,看后一部分的时候还要经常往前翻。所以,学习是个反反复复的过程,最难写的也是前几章(放水)。


EPP协议中定义了四种数据传输模式:
(1) 数据写周期(data write cycle)
(2) 数据读周期(data read cycle)
(3) 地址写周期(address write cycle)
(4) 地址读周期(address read cycle)


不管读还是写,设备总是很被动,程序总是很主动。程序要求设备发送一个字节,设备就发送一个。程序要向设备写一个字节,设备就接收一个。除了有个中断信号,设备不会打扰计算机和并口控制器。
1 数据写周期


把一个字节数据发送到外设,程序这个数写到EPP DATA寄存器,EPP控制器就可以产生必要的握手信号和选通信号,就像上面的时序图表示的一样,红色竖线表示主机已经把数放到了线路上,绿色竖线表示设备已经收到数据。


(1) 首先EPP控制器把nWrite设置成低电平,表示EPP正在处于写状态,不能读了。同时数据出现在并行端口的数据线上。
(2) nWait处于低电平,表示设备空闲,那么EPP就插入数据选通信号(nDataStrobe低电平),请求设备去读数据。
(3) 设备把nWait设置成高电平(应答信号),表示读完。然后EPP取消数据选通信号(nDataStrobe高电平),结束写状态。
(4) 这时设备把nWait置成低电平,表明可以开始下一个周期。


2 数据读周期



程序从EPP DATA寄存器读一个数,EPP控制器就开始了一个“数据读”周期。红线表示设备已经把数据放到线路上,绿线表示主机读完了。


(1) nWrite低电平表示EPP处于读状态,不能写。
(2) 在nWait低电平的时候(设备空闲),EPP插入数据选通信号(nDataStrobe低电平)请求设备发送数据。
(3) 设备把数送到线路上的时候,给主机一个应答信号(nWait高电平)。
(4) 主机去读数据,然后取消数据选通信号(nDataStrobe高电平)表示读完。
(5) 设备回到空闲状态。


3 地址写周期


和数据写周期一样,只不过是把数据选通信号换成了地址选通信号,程序向EPP ADDRESS寄存器中写数。


4 地址读周期


和数据读周期一样,只不过是把数据选通信号换成了地址选通信号。程序从EPP ADDRESS寄存器中读数。


第五章 程序
EPP本来就是一个很低级的协议,软件的每一个操作都和设备息息相关,离开设备谈软件没有任何意义,所以,我只能参考dongsuoying的采集系统来讲程序。下面就是系统的示意图:



采集卡的接头和计算机的并行端口通过排线连接,采集卡先将采集的数据暂时存放在卡内的存储器中,当计算机需要的时候,再通过并行端口EPP模式把数据上传给计算机。下面就是一些比较有代表性的程序。


1 初始化采集卡
采集卡在设计时规定:向地址00写初始化命令字00,采集卡对存储器,必要的寄存器等进行初始化,并等待主机其它设置信息。代码是


 #define BASE 0x378        //并口I/O基地址 
 outportb(BASE + 2, 0x04); //方向=写,EPP不接收中断
 outportb(BASE + 3, 0);    //使用EPP ADDRESS寄存器写地址00
 outportb(BASE + 4, 0);    //使用EPP DATA寄存器写数据00


第二句话outportb(BASE + 2, 0x04)有多个作用:SPP CONTROL寄存器低四位设置成0100使4根信号线在传输之前回到空闲状态;第4位设置0,禁止EPP接受中断;第5位是传输方向位,设置 0只能进行写操作。设置1只能进行读操作。这都是一些比较有个性的EPP控制器这么要求的。


2 设置采样率
采集卡在设计时规定:向地址01写入采样率信息数据,00对应 3200点/秒,01对应6400点/秒,02对应12800点/秒。


 outportb(BASE + 3, 1);
 outportb(BASE + 4, 0); //3200点/秒


3 启动采集卡
采集卡在设计时规定:向地址00写入01,采集卡开始以设定的采样率和触发条件运行。


 outportb(BASE + 3, 0);
 outportb(BASE + 4, 1);


4 读采集卡触发状态和数据地址
采集卡在设计时规定:从地址04读数据,第一个字节表示采集的数据在卡上RAM中的地址;第二个字节第7位表示触发状态,0表示已触发,1表示未触发。


 outportb(BASE + 2, 0x04);      //方向=写,EPP不接收中断信号
 outportb(BASE + 3, 4);         //设置地址
 outportb(BASE + 2, 0x24);      //方向=读
 BYTE addr = inportb(BASE + 4);
 BYTE trig = inportb(BASE + 4);
 if(trig < 0x80)
 {
     //已触发,保存数据
 }
 outportb(BASE + 2, 0x34);      //EPP可以接收中断信号


5 读采集的数据
采集卡在设计时规定:主机从地址03连续执行数据读操作,每次读取10毫秒数据,每个数据2字节。


 BYTE buffer[SAM_COUNT * 2]; 
 outportb(BASE + 2, 0x04);           //方向=写
 outportb(BASE + 3, 3);
 outportb(BASE + 2, 0x24);           //方向=读
 for(i = 0; i < SAM_COUNT * 2; i++)
 {
  buffer = inport(BASE + 4);
 }
 WORD* pSam = (WORD *)buffer;
 outportb(BASE + 2, 0x34);           //EPP可以接收中断信号


6 中断
当采集卡有数据需要上传的时候,会通过nINTR信号线给主机发送一个中断,并口默认的中断是IRQ7,在小我的小主板上还可以设置成IRQ5。下面这个图就是IBM PC机硬件中断机构。


外设发出的中断请求到CPU相应中断,有两个控制条件是起决定作用的,一是该外设的中断请求是否屏蔽,另一个是CPU是否允许响应中断。这两个条件分别由8259A(可编程中断控制芯片)的中断屏蔽寄存器和CPU标志寄存器(FLAGS)中的中断允许位IF控制。


中断屏蔽寄存器的I/O地址是21H,允许并口中断,就把第7位设置0。
7
6
5
4
3
2
1
0
LPT1
软盘
LPT2
COM1
COM2
8259从片
键盘
定时器


允许CPU响应外设中断请求(IF=1)叫做开中断,反之叫做关中断(IF=0),Borland C++中使用enable()和disable()函数对应开中断和关中断。需要注意的是,CPU在任何中断发生的时候,当前的FLAGS要保存入栈,然后设置IF=0,在退出中断处理程序的时候恢复FLAGS先前的值(包括IF)。所以如果允许一个中断处理程序在执行过程中再发生外设中断,则必须用enable()开中断。


在一次中断发生后,必须设置中断结束位,8259A才能允许同级或者低级的中断再发生。中断结束位(EOI,end of interrupt)是中断命令寄存器的第5位,I/O地址是20H。其它位都和外设的中断优先级有关系。


中断命令寄存器
7
6
5
4
3
2
1
0
R
SL
EOI
0
0
L2
L1
L0


IBM PC机中由8259A管理的16级中断均有规定的中断向量存储地址,主片中IRQ0-IRQ7分别对应08H-0FH,从片中IRQ8-IRQ15分别对应70H-77H。主片的中断控制寄存器和中断屏蔽寄存器的口地址分别为20H和21H,从片的相应寄存器口地址分别为A0H和A1H。IRQ7对应的中断向量是15。


并口的中断处理程序
void interrupt my_irq7(...)
{
    //从采集卡读数据,保存……


    enable();              //允许CPU再处理中断
    outportb(0x20, 0x20);  //设置中断结束位


    //计算,显示,其它无关紧要的事情……
}


修改中断向量,当发生并口中断的时候执行my_irq7()
void init_irq()
{
    disable();                  //禁止CPU处理中断(保护)


    old_irq7 = getvect(15);     //保存以前的中断处理入口
    setvect(15, my_irq7);       //设置新处理程序


    BYTE value = outportb(0x21);
    value &= 0x7F;              // 01111111b
    outportb(0x21, value);      //清除屏蔽位
  outportb(0x20, 0x20);       //为安全起见,设置中断结束位
  
  //设置,启动采集卡……
  
  outportb(BASE + 2, 0x34);   //第4位=1,EPP接受中断
    enable();                   //再允许CPU处理中断
}


7 复杂的采集系统
董师傅做的采集系统相当复杂,并口的应用只是其中的一小部分,在讲并口的时候,顺便让大家看一下董师傅采集系统的全貌。当然我不能把所有电路逻辑还有程序说的清楚,咱们只从数据转存的角度去浏览。



采集卡不间断地采集数据保存在RAM中,每10毫秒通过并口上传到计算机,先保存在数组中,同时在图形界面上实时显示,同时保存在扩展内存中。当有触发信号时,程序从扩展内存取出数据保存在文件中。


总结
在系统中实现并口通信并不是一件简单的事情,感谢董师傅的程序。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条