PIO

16 Bits
Input/Output
Unit


One thing I like to do with computers is controlling hardware. That's the reason for creating a parallel communication interface connected to the printer port of a computer.

This is way before I gathered knowledge about USB interfaces.

First I started with a Z80PIO chip on a Z80CPU controlled ZX Spectrum. When I bought my first laptop I knew I would need a complete new interface.

The Z80PIO interface had 16 channels of witch each channel could be configured for input or output. Because of the limitations of the parallel port I decided to create 16 input channels and 16 output channels. 

The top of the case has an experiment feature with build-in AD converter.



See the drawings below (click on them for enlargements) for detailed info on used components. Because the parallel port has no 5V supply, you'll need a separate one.

If you just need an 8 channel input/output interface, click on the drawing above for the complete schematic.

I'll recommend the 16 channel version though!

If you wonder how the circuit board should look after building it, I use Euro board for all my prototypes, as you can see below.

To create this you'll need a bit of experience in the TTL systems.

Below is some information about controlling the Parallel port.

Parallel port info


Here is a listing for Quick basic which you can reference. It's ready to control the 16 bit version. Just copy the text and save it in Notepad as PIO16.BAS. 

Remember to disconnect any printer or scanner connected to the parallel port !!

        CLS
        REM GOTO BIT8
        GOTO B16
        T = 1
        A = 1
        B = 16
LOP:    V = A
        D = 1
        GOSUB CONTO
        V = B
        D = 2
        GOSUB CONTO
        A = A * 2: IF A = 256 THEN A = 1
        B = B * 2: IF B = 256 THEN B = 1
        FOR c = 1 TO 1000: NEXT c
        GOTO LOP

B16:    T = 1
BIT16:  FOR A = 0 TO 255: B = 255 - A
        REM A = INT(RND * 255) + 1
        REM B = INT(RND * 255) + 1
        V = A: D = 1
        GOSUB CONTO
        V = B: D = 2
        GOSUB CONTO
       
        REM FOR c = 1 TO 500: NEXT c
       
        D = 3: GOSUB CONTI
        v1 = V
        D = 4: GOSUB CONTI
        v2 = V
        va = (INT(v1 / 8)) + ((INT(v2 / 8)) * 16)
        IF va <> A THEN PRINT "Ain="; va; " Auit="; A: T = T + 1
        REM FOR c = 1 TO 500: NEXT c
      
        D = 5: GOSUB CONTI
        v1 = V
        D = 6: GOSUB CONTI
        v2 = V
        va = (INT(v1 / 8)) + ((INT(v2 / 8)) * 16)
        IF va <> B THEN PRINT "Bin="; va; " Buit="; B: T = T + 1
       
        FOR c = 1 TO 1000: NEXT c
      
        NEXT A
        GOTO BIT16

BIT8:   FOR A = 0 TO 255
        OUT &H378, (A)
        OUT &H37A, (1)
      
        OUT &H37A, (2)
        v1 = INP(&H379)
        OUT &H37A, (4)
        v2 = INP(&H379)
        OUT &H37A, (0)
        va = (INT(v1 / 8)) + ((INT(v2 / 8)) * 16)
        IF va <> A THEN PRINT va; " ";
        FOR c = 1 TO 500: NEXT c
        NEXT A
        GOTO BIT8

CONTI:  OUT &H37A, (D + 8)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (D)
        FOR c = T TO 0 STEP -1: NEXT c
        V = INP(&H379)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (D + 8)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (8)
        FOR c = T TO 0 STEP -1: NEXT c
        RETURN

CONTO:  OUT &H378, (V)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (D + 8)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (D)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (D + 8)
        FOR c = T TO 0 STEP -1: NEXT c
        OUT &H37A, (8)
        FOR c = T TO 0 STEP -1: NEXT c
        RETURN


Below is the assembler source code to set waitloop variable. The value of this variable should be high on fast PC's. You need to connect the outputs of the interface directly to the inputs, so OUT0 to IN0 and so on.


; Scumari R&D 1996
; Parallel 16 bit In/Out interface suppressing test
; IO.ASM

	JMP START		;
TWRD:	DW 1			;

START:	MOV CX,255		;
LOP:	MOV AL,1		;
	MOV AH,CL		;
	CALL COUT		; Value in CL to output 1
	MOV AL,2		;
	MOV AH,CH		;
	CALL COUT		; Value in CH to output 2
				;
	MOV AL,3 		;
	CALL CIN		;
	CMP CL,BL		;
	JNZ TELW		;
	MOV AL,5 		;
	CALL CIN		;
	CMP CH,BL		;
	JZ NOTEL		;
				;
TELW:	MOV AX,[TWRD]		;
	INC AX			;
	MOV [TWRD],AX		;
	CMP AX,0		;
	JZ EIND			;
	CALL NUMBR		;
NOTEL:	DEC CL			;
	INC CH			;
				;
;	MOV BX,65535		;
;L0:	DEC BX			;
;	JNZ L0		;

	MOV AH,1		; Check break keys
	INT 16H			;
	JZ LOP			;
EIND:	MOV AX,[TWRD]		;
	CALL NUMBR		;
	MOV AH,4CH		;
	INT 21H			;
				;
; OUT subroutine
; AL=port number  AH=Value
				;
COUT:	MOV DX,0378H		;
	PUSH AX			;
	MOV AL,AH		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0			;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	ADD AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0			;
				;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0			;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	ADD AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0			;
				;
	MOV DX,037AH		;
	MOV AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0			;
				;
	POP AX			;
	RET			;
				;
; IN subroutine
; AL=port nummer BL=Value
				;
CIN:	MOV DX,037AH		;
	PUSH AX			;
	ADD AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,0379H		;
	IN AL,DX		;
	MOV BL,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	ADD AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,037AH		;
	POP AX			;
	INC AL			;
	PUSH AX			;
	ADD AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,0379H		;
	IN AL,DX		;
	MOV BH,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,037AH		;
	POP AX			;
	PUSH AX			;
	ADD AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	MOV DX,037AH		;
	MOV AL,8		;
	OUT DX,AL		;
	MOV AX,[TWRD]		;
L0:	DEC AX			;
	JNZ L0		;
				;
	POP AX			;
	SHR BL,3		;
	SHL BH,1		;
	AND BH,240		;
	ADD BL,BH		;
	RET			;
	
; SCUMARI R&D
; NUMBERS.BIB
; Number in AX is printed

numbr:	PUSH AX			; Print at position 0,0
	MOV AH,2		;
	MOV BH,0		;
	MOV DX,0		;
	INT 10H			;
	POP AX			;
				;
	mov cx,10000		;
	call numb		;
	mov cx,1000		;
	call numb		;
numbr0:	mov cx,100		;
	call numb		;
	mov cx,10		;
	call numb		;
	mov dl,al		;
	add dl,48		;
	jmp near numb2		; 
				;
numb:	mov dl,48		;
numb0:	sub ax,cx		;
	jc numb1		;
	inc dl			;
	jmp near numb0		;
numb1:	add ax,cx		;
numb2:	push ax			;
	mov ah,2		;
	int 21h			;
	pop ax			;
	ret			;