⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interfacing the standard parallel port.htm

📁 并口的接口规范
💻 HTM
📖 第 1 页 / 共 5 页
字号:
        state the pin on the Parallel Port is high (+5v). When in this state, 
        your external device can pull the pin low and have the control port 
        change read a different value. This way the 4 pins of the Control Port 
        can be used for bi-directional data transfer. However the Control Port 
        must be set to xxxx0100 to be able to read data, that is all pins to be 
        +5v at the port so that you can pull it down to GND (logic 0). </P>
        <P>Bits 4 &amp; 5 are internal controls. Bit four will enable the IRQ 
        (See Using the Parallel Ports IRQ) and Bit 5 will enable the 
        bi-directional port meaning that you can input 8 bits using (DATA0-7). 
        This mode is only possible if your card supports it. Bits 6 &amp; 7 are 
        reserved. Any writes to these two bits will be ignored. </P></UL><A 
      name=6><I><FONT size=+2>Bi-directional Ports</FONT></I>
      <HR>
      </A> 
      <UL>
        <P>The schematic diagram below, shows a simplified view of the Parallel 
        Port's Data Register. The original Parallel Port card's implemented 74LS 
        logic. These days all this is crammed into one ASIC, but the theory of 
        operation is still the same. </P>
        <CENTER><IMG alt="Internal's of bi-directional Port" 
        src="Interfacing the Standard Parallel Port.files/bidi.gif" 
        border=0></CENTER>
        <P>The non bi-directional ports were manufactured with the 74LS374's 
        output enable tied permanent low, thus the data port is always output 
        only. When you read the Parallel Port's data register, the data comes 
        from the 74LS374 which is also connected to the data pins. Now if you 
        can overdrive the '374 you can effectively have a Bi-directional Port. 
        <I>(or a input only port, once you blow up the latches output!)</I> </P>
        <P>What is very concerning is that people have actually done this. I've 
        seen one circuit, a scope connected to the Parallel Port distributed on 
        the Internet. The author uses an ADC of some type, but finds the ADC 
        requires transistors on each data line, to make it work! No wonder why. 
        Others have had similar trouble, the 68HC11 cannot sink enough current 
        (30 to 40mA!) </P>
        <P>Bi-directional ports use Control Bit 5 connected to the 374's Output 
        Enable so that it's output drivers can be turned off. This way you can 
        read data present on the Parallel Port's Data Pins, without having bus 
        conflicts and excessive current drains. </P>
        <P>Bit 5 of the Control Port enables or disables the bi-directional 
        function of the Parallel Port. This is only available on true 
        bi-directional ports. When this bit is set to one, pins 2 to 9 go into 
        high impedance state. Once in this state you can enter data on these 
        lines and retrieve it from the Data Port (base address). Any data which 
        is written to the data port will be stored but will not be available at 
        the data pins. To turn off bi-directional mode, set bit 5 of the Control 
        Port to '0'. </P>
        <P>However not all ports behave in the same way. Other ports may require 
        setting bit 6 of the Control Port to enable Bi-directional mode and 
        setting of Bit 5 to dis-enable Bi-directional mode, Different 
        manufacturers implement their bi-directional ports in different ways. If 
        you wish to use your Bi-directional port to input data, test it with a 
        logic probe or multimeter first to make sure it is in bi-directional 
        mode. </P></UL><A name=7><I><FONT size=+2>Using The Parallel Port to Input 
      8 Bits.</FONT></I>
      <HR>
      </A> 
      <UL>
        <P>If your Parallel Port doesn't support bi-directional mode, don't 
        despair. You can input a maximum of 9 bits at any one given time. To do 
        this you can use the 5 input lines of the Status Port and the 4 inputs 
        (open collector) lines of the Control Port. </P>
        <CENTER><IMG 
        alt="Schematic showing how to input 8 bits using Control and Status Port" 
        src="Interfacing the Standard Parallel Port.files/8inputs.gif" 
        border=0></CENTER>
        <P>The inputs to the Parallel Port has be chosen as such, to make life 
        easier for us. Busy just happens to be the MSB (Bit 7) of the Status 
        Port, then in ascending order comes Ack, Paper Out and Select, making up 
        the most significant nibble of the Control Port. The Bars are used to 
        represent which inputs are Hardware inverted, i.e. +5v will read 0 from 
        the register, while GND will read 1. The Status Port only has one 
        inverted input. </P>
        <P>The Control port is used to read the least significant nibble. As 
        described before, the control port has open collector outputs, i.e. two 
        possible states, high impedance and GND. If we connect our inputs 
        directly to the port (For example an ADC0804 with totem pole outputs), a 
        conflict will result if the input is high and the port is trying to pull 
        it down. Therefore we use open collector inverters. </P>
        <P>However this is not always entirely necessary. If we were connecting 
        single pole switches to the port with a pull up resistor, then there is 
        no need to bother with this protection. Also if your software 
        initializes the control port with xxxx0100 so that all the pins on the 
        control port are high, then it may be unnecessary. If however you don't 
        bother and your device is connected to the Parallel Port before your 
        software has a chance to initialize then you may encounter problems. 
</P>
        <P>Another problem to be aware of is the pull up resistors on the 
        control port. The average pull-up resistor is 4.7k. In order to pull the 
        line low, your device will need to sink 1mA, which some low powered 
        devices may struggle to do. Now what happens if I suggest that some 
        ports have 1K pull up resistors? Yes, there are such cards. Your device 
        now has to sink 5mA. More reason to use the open collector inverters. 
        </P>
        <P>Open collector inverters were chosen over open collector buffers as 
        they are more popular, and thus easier to obtain. There is no reason, 
        however why you can't use them. Another possibility is to use 
        transistors. </P>
        <P>The input, D3 is connected via the inverter to Select Printer. Select 
        Printer just happens to be bit 3 of the control port. D2, D1 &amp; D0 
        are connected to Init, Auto linefeed and strobe, respectively to make up 
        the lower nibble. Now this is done, all we have to do is assemble the 
        byte using software. The first thing we must do is to write xxxx0100 to 
        the Control Port. This places all the control port lines high, so they 
        can be pulled down to input data. </P>
        <UL></FONT><PRE>outportb(CONTROL, inportb(CONTROL) &amp; 0xF0 | 0x04);
</PRE><FONT face=ARIAL></UL>
        <P>Now that this is done, we can read the most significant nibble. This 
        just happens to be the most significant nibble of the status port. As we 
        are only interested in the MSnibble we will AND the results with 0xF0, 
        so that the LSnibble is clear. Busy is hardware inverted, but we won't 
        worry about it now. Once the two bytes are constructed, we can kill two 
        birds with one stone by toggling Busy and Init at the same time. </P>
        <UL></FONT><PRE>a = (inportb(STATUS) &amp; 0xF0); /* Read MSnibble */
</PRE><FONT face=ARIAL></UL>
        <P>We can now read the LSnibble. This just happens to be LSnibble of the 
        control port - How convenient! This time we are not interested with the 
        MSnibble of the port, thus we AND the result with 0x0F to clear the 
        MSnibble. Once this is done, it is time to combine the two bytes 
        together. This is done by OR'ing the two bytes. This now leaves us with 
        one byte, however we are not finished yet. Bits 2 and 7 are inverted. 
        This is overcome by XOR'ing the byte with 0x84, which toggles the two 
        bits. </P>
        <UL></FONT><PRE>a = a |(inportb(CONTROL) &amp; 0x0F); /* Read LSnibble */
a = a ^ 0x84; /* Toggle Bit 2 &amp; 7 */
</PRE><FONT face=ARIAL></UL>
        <P><B>Note: Some control ports are not open collector, but have totem 
        pole outputs. This is also the case with EPP and ECP Ports. Normally 
        when you place a Parallel Port in ECP or EPP mode, the control port 
        becomes totem pole outputs only. Now what happens if you connect your 
        device to the Parallel Port in this mode? Therefore, in the interest of 
        portability I recommend using the next circuit, reading a nibble at a 
        time. </B></P></UL><A name=8><I><FONT size=+2>Nibble Mode.</FONT></I>
      <HR>
      </A> 
      <UL>
        <P>Nibble mode is the preferred way of reading 8 bits of data without 
        placing the port in reverse mode and using the data lines. Nibble mode 
        uses a Quad 2 line to 1 line multiplexer to read a nibble of data at a 
        time. Then it "switches" to the other nibble and reads its. Software can 
        then be used to construct the two nibbles into a byte. The only 
        disadvantage of this technique is that it is slower. It now requires a 
        few I/O instructions to read the one byte, and it requires the use of an 
        external IC. </P>
        <P>
        <CENTER><IMG alt="Schematic - 8 inputs using 74ls157 Multiplexer" 
        src="Interfacing the Standard Parallel Port.files/74hc157.gif" 
        border=0></CENTER>
        <P>The operation of the 74LS157, Quad 2 line to 1 line multiplexer is 
        quite simple. It simply acts as four switches. When the A/B input is 
        low, the A inputs are selected. E.g. 1A passes through to 1Y, 2A passes 
        through to 2Y etc. When the A/B is high, the B inputs are selected. The 
        Y outputs are connected up to the Parallel Port's status port, in such a 
        manner that it represents the MSnibble of the status register. While 
        this is not necessary, it makes the software easier. </P>
        <P>To use this circuit, first we must initialize the multiplexer to 
        switch either inputs A or B. We will read the LSnibble first, thus we 
        must place A/B low. The strobe is hardware inverted, thus we must set 
        Bit 0 of the control port to get a low on Pin 1. 
        <P>
        <UL></FONT><PRE>outportb(CONTROL, inportb(CONTROL) | 0x01); /* Select Low Nibble (A)*/
</PRE><FONT face=ARIAL></UL>
        <P>Once the low nibble is selected, we can read the LSnibble from the 
        Status Port. Take note that the Busy Line is inverted, however we won't 
        tackle it just yet. We are only interested in the MSnibble of the 
        result, thus we AND the result with 0xF0, to clear the LSnibble. </P>
        <UL></FONT><PRE>a = (inportb(STATUS) &amp; 0xF0); /* Read Low Nibble */
</PRE><FONT face=ARIAL></UL>
        <P>Now it's time to shift the nibble we have just read to the LSnibble 
        of variable a, </P>
        <UL></FONT><PRE>a = a &gt;&gt; 4; /* Shift Right 4 Bits */
</PRE><FONT face=ARIAL></UL>
        <P>We are now half way there. It's time to get the MSnibble, thus we 
        must switch the multiplexer to select inputs B. Then we can read the 
        MSnibble and put the two nibbles together to make a byte, </P>
        <UL></FONT><PRE>outportb(CONTROL, inportb(CONTROL) &amp; 0xFE); /* Select High Nibble (B)*/
a = a |(inportb(STATUS) &amp; 0xF0); /* Read High Nibble */
byte = byte ^ 0x88;
</PRE><FONT face=ARIAL></UL>
        <P>The last line toggles two inverted bits which were read in on the 
        Busy line. It may be necessary to add delays in the process, if the 
        incorrect results are being returned. </P></UL><A name=9><I><FONT 
      size=+2>Using the Parallel Port's IRQ</FONT></I>
      <HR>
      </A> 
      <UL>
        <P>The Parallel Port's interrupt request is not used for printing under 
        DOS or Windows. Early versions of OS-2 used them, but don't anymore. 
        Interrupts are good when interfacing monitoring devices such as high 
        temp alarms etc, where you don't know when it is going to be activated. 
        It's more efficient to have an interrupt request rather than have the 
        software poll the ports regularly to see if something has changed. This 
        is even more noticeable if you are using your computer for other tasks, 
        such as with a multitasking operating system. </P>
        <P>The Parallel Port's interrupt request is normally IRQ5 or IRQ7 but 
        may be something else if these are in use. It may also be possible that 
        the interrupts are totally disabled on the card, if the card was only 
        used for printing. The Parallel Port interrupt can be disabled and 
        enabled using bit 4 of the control register, Enable IRQ Via Ack Line. 
        Once enabled, an interrupt will occur upon a low to high transition 
        (rising edge) of the nACK. However like always, some cards may trigger 
        the interrupt on the high to low transition. </P>
        <P>The following code is an Interrupt Polarity Tester, which serves as 
        two things. It will determine which polarity your Parallel Port 
        interrupt is, while also giving you an example for how to use the 
        Parallel Port's Interrupt. It checks if your interrupt is generated on 
        the rising or falling edge of the nACK line. To use the program simply 
        wire <B>one of</B> the Data lines (Pins 2 to 9) to the Ack Pin (Pin 10). 
        The easiest way to do this is to bridge some solder from DATA7 (Pin 9) 
        to ACK (Pin 10) on a male DB25 connector. </P><BR>
        <UL></FONT><PRE>/*  Parallel Port Interrupt Polarity Tester                           */
/*  2nd February 1998			                              */
/*  Copyright 1997 Craig Peacock                                      */
/*  WWW     - http://www.beyondlogic.org                              */
/*  Email   - cpeacock@senet.com.au                                   */

#include &lt;dos.h&gt;

#define PORTADDRESS 0x378  /* Enter Your Port Address Here */
#define IRQ 7              /* IRQ Here */

#define DATA PORTADDRESS+0
#define STATUS PORTADDRESS+1
#define CONTROL PORTADDRESS+2

#define PIC1 0x20
#define PIC2 0xA0

int interflag; /* Interrupt Flag */
int picaddr;   /* Programmable Interrupt Controller (PIC) Base Address */

void interrupt (*oldhandler)();

void interrupt parisr()  /* Interrupt Service Routine (ISR) */
{
  interflag = 1;
  outportb(picaddr,0x20); /* End of Interrupt (EOI) */
}

void main(void)
{
 int c;
 int intno;    /* Interrupt Vector Number */
 int picmask;  /* PIC's Mask */

 /* Calculate Interrupt Vector, PIC Addr &amp; Mask. */

 if (IRQ &gt;= 2 &amp;&amp; IRQ &lt;= 7) {
			    intno = IRQ + 0x08;
			    picaddr = PIC1;
			    picmask = 1;
                            picmask = picmask &lt;&lt; IRQ;
			   }
 if (IRQ &gt;= 8 &amp;&amp; IRQ &lt;= 15) {
			     intno = IRQ + 0x68;
			     picaddr = PIC2;
			     picmask = 1;
                             picmask = picmask &lt;&lt; (IRQ-8);
			    }
 if (IRQ &lt; 2 || IRQ &gt; 15)
	{
	 printf("IRQ Out of Range\n");
	 exit();
	}

 outportb(CONTROL, inportb(CONTROL) &amp; 0xDF); /* Make sure port is in Forward Direction */
 outportb(DATA,0xFF);
 oldhandler = getvect(intno);  /* Save Old Interrupt Vector */
 setvect(intno, parisr);      /* Set New Interrupt Vector Entry */
 outportb(picaddr+1,inportb(picaddr+1) &amp; (0xFF - picmask)); /* Un-Mask Pic */
 outportb(CONTROL, inportb(CONTROL) | 0x10); /* Enable Parallel Port IRQ's */

 clrscr();
 printf("Parallel Port Interrupt Polarity Tester\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -