SX IO expansion with 3 io pins and 74HC595 serial shift register

by Ken Mathis

Ken Mathis of ASC shares this code:

;FILE NAME: 4 byte shift out short ver.
;date:8/28/03
;Programmer:Ken Mathis
;Purpose of this program is to expand the number of SX28 output
;ports using a 74HC595 serial shift register. Using 3 output pins of the
;SX will add 29 additional output ports. These additional output ports are
;used for non-critical timing applications, such as controlling an LED matrix
;or 4 seven segment displays.
;data is shifted out of the SX into the 74HC595's
;rc ports used to control the shift register and send data out to the 595's
;pin 13 of '595 (Output Enable\) hard wired to ground
;pin 10 of '595 (Master Reset\) hard wired to +5 via 10k ohms
;pin 9 (Q7') of the most significant '595 is connected to the next lower '595
;pin 14 (data input) and each sucessive pin 9 connects to the next lower 
;'595 pin 14 (data input). The Q7' output of the most significant '595 is the
;input to the next lower '595
;sx connections to most significant'595: rc.7 (data) >>> '595 pin14
;rc.5 (latch) >>> '595 pin12 - (all 595's)
;rc.4 (clock) >>> '595 pin11 - (all 595's)
;---------------------------
;4 byte data is loaded into temporary registers temp1 and the following 3 
;addresses (temp1+1, temp1+2, temp1+3) -- MOST SIGNIFICANT BYTE is temp1+3
;data is shifted out Least Significant Byte first. The 595's present each byte
;with the least significant bit on Q7 and the most significant bit on Q0
;---------------------------
;DELAY ROUTINE generated by using the Delay Code Generator, courtesy of
;NICKOLAI GOLOVCHENKO
ifdef __SASM
	DEVICE	SX28L, STACKX, OPTIONX
	IRC_CAL	IRC_FAST
	FREQ	50_000_000
else
	DEVICE	SX28AC, OPTIONX
endif
DEVICE	TURBO, OSCHS2, WATCHDOG
RESET	START
;place variables here
org	$08
temp1	ds	4	;used to hold 4 bytes to shift out
temp2	ds	1	;used to count down 8 bits
temp3	ds	1	;used to count down 4 bytes
d1	ds	1	;used in delay routine
d2	ds	1	;ditto
d3	ds	1	;ditto
data	=	rc.7	;assign data to rc.7
clock	=	rc.4	;assign clock to rc.4
latch	=	rc.5	;assign latch to rc.5
;any calls should be placed on first page between org $000 and org $100
org	$000
;-----5 uS delay (courtesy of Nickolai Golovchenko)
del_5uS
	mov	w, #$3d
	mov	d1, w
del_5uS_0
	decsz	d1
	jmp	del_5uS_0
	nop
	nop
	ret
;-----clock pulse generation to shift data out of SX
shift_out
	call	del_5uS		;5 uS set-up time
	setb	clock		;make clock (rc.4) high
	call	del_5uS		;5 uS hold time
	clrb	clock		;make clock low
	ret			;return
;-----move bit to shift out into carry
rotate
	rr	ind	;move into carry lsb of file register pointed to by
			;current value if fsr
	jc	high	;if carry is high jump to "high" and make data (rc.7) high
	clrb	data	;if carry is low make data (rc.7) low
	jmp	out	;skip over next line
high	
	setb	data	;make data (rc.7) high
out
	ret		;return
org	$100
Start
;port initialization
	mov	!ra,#$0		;ra outputs	mov	!rb,#$FF
	mov	!rb,#$01	;rb inputs
	mov	!rc,#$00	;rc outputs

again
	clrb	clock		;make clock pin low
	clrb	data		;make data pin low
	clrb	latch		;make latch pin low

;-----These lines of code used to verify operation of program by
;loading known values into the 4 bytes that will be shifted out of
;the SX28 into the four (4) 74HC595's. Change values as needed to
;test program
mov	w,#$93
mov	temp1,w
mov	w,#$11
mov	temp1+1,w
mov	w,#$44
mov	temp1+2,w
mov	w,#$7e
mov	temp1+3,w
;-----End of test section

;prepare fsr to load fsr with the register that will hold the 
;lease significant byte. EXAMPLE, the least significant byte will be in
;register $08, therefore fsr must start at $08 

	mov	w,#$08		
	mov	fsr,w		;load fsr with register $08
	mov	temp2,w		;load 8 bit countdown with $08
	mov	temp3,w		;load 4 byte countdown with $08 (will be changed
				;to 4 later
	clc			;ensure carry is zero
	rr	temp3		;change value from $08 to $04
	call	rotate		;move ls bit into carry and set data to reflect
				;carry was high or low (done inside rotate sub-routine)
	call	shift_out	;generate clock pulses to shift data out
	decsz	temp2		;decrement 8 bit countdown until zero
	jmp	$-3		;go up three lines to "call rotate"
	inc	fsr		;increment fsr so ind now refers to the next highest byte
	mov	w,#$08		
	mov	temp2,w		;reload 8 but countdown
	clc			;clear carry flag (if not cleared 4 byte countdown may
				;not work correctly if carry was set from last shiftout)
	decsz	temp3		;decrement 4 byte countdown
	jmp	$-9		;go up 9 lines to "call rotate"
	call	del_5uS		;wait 5 uS
	setb	latch		;move data from '595 internal registers to ouput registers
	call	del_5uS		;5 uS hold time
	clrb	latch		;make latch low
	nop			;
	jmp	again		;do it again - or continue with the rest of the "real program"
END				;end of the program