; SERIN port, pin, baud, polarity, bytes, filter
; Receives data serially at the specified rate and polarity via the specified
; port pin. Stores the data as a counted string starting at buffer-1 (buffer is
; the number of bytes in the string). An optional filter causes the routine to
; ignore data outside a range of ASCII character values set by filt_lo and
; filt_hi.

buffer	=	31	; String storage.
B2400	=	30	; Bit delay for 2400 baud.
B1200	=	62	; Bit delay for 1200 baud.
B600	=	126	; Bit delay for 600 baud.
B300	=	255	; Bit delay for 300 baud.
filt_lo =	'0'     ; Set filter for ASCII
filt_hi =	'9'     ; chars representing 0-9.

	org	8
baud	ds	1	; Baud rate.
pin	ds	1	; Pin number (0-7).
port	ds	1	; Port number (0-2).
bytes	ds	1	; Number of bytes to receive.
temp1	ds	1	; Temporary counter for Serin.
temp2	ds	1	; Temporary counter for Serin.
temp3	ds	1	; Temporary counter for delay.
ser_fl	ds	1	; Flags for serin switches.

polarity	=	ser_fl.0	; Polarity: 0=true, 1=inverted.
filter		=	ser_fl.1	; Range filter: 0=off, 1=on.
filt_1st	=	ser_fl.2	; 1st filter byte passed?: 0=no, 1=yes.
aux		=	ser_fl.3	; Temporary flag for filter comparisons.

; Device data and reset vector
	device	pic16c55,xt_osc,wdt_off,protect_off
	reset	start
	org	0
; Table to convert pin number (0-7) into bit mask (00000001b to 10000000b).
Pinz	jmp	pc+w
	retw	1,2,4,8,16,32,64,128

; Subroutine used by Serin to get a bit and delay for a number of loops
; set by temp3. Jumping into get_bit:loop provides the delay, but ignores the
; input bit.
get_bit mov	fsr,port	; Point to port.
	mov	w,indirect	; IF Polarity = 0 THEN w = Port
	snb	Polarity	; ELSE w = NOT Port
	mov	w,/indirect
	AND	w,pin
	snz			; IF w AND pin THEN carry = 1
	clc			; ELSE carry = 0.
	sz
	stc
	mov	fsr,temp1	; Point to buffer location.
	rr	indirect	; Rotate carry into msb of data byte.
:loop	jmp	$+1		; Two-cycle nops.
	jmp	$+1
	jmp	$+1
	jmp	$+1
	jmp	$+1
	djnz	temp3,:loop
	ret

; Main program start. Receives a single byte of data, filtered for numeric
; characters, and displays the data bits on LEDs connected to port RB.
start	mov	!ra, #15	; All inputs.
	mov	!rb,#0		; All outputs for LEDs.
	clr	rc		; Clear the LEDs.
	clr	ser_fl		; Clear serial flags.
	mov	bytes,#1	; Receive 1 byte
	clrb	filter		; not filtered
	setb	polarity	; inverted polarity
	mov	baud,#B2400	; at 2400 baud
	mov	pin,#2		; via pin 2
	mov	port,#0 	; of port ra.
	CALL	SERIN		; Receive the data.
	mov	rb,buffer-1	; Move byte to LEDs on RB.
	jmp	start		; Endless loop


; Body of the Serin routine. Expects the baud constant in baud, number of
; bytes to receive in bytes, the I/O port (0-2 for RA through RC) in port,
; the pin number (0-7) in pin, and the flag settings in ser_fl
SERIN	clr	buffer		; Clear buffer counter.
	clrb	filt_1st
	ADD	port,#RA	; Add offset for port RA.
	mov	w,pin
	CALL	Pinz		; Get bit mask from the table.
	mov	pin,w		; Put the mask into pin.
	mov	temp1,#buffer-1 ; Pointer for first data address.
:poll	mov	fsr,port
	mov	w,indirect	; IF Polarity = 0 THEN w = Port
	snb	Polarity	; ELSE w = NOT Port
	mov	w,/indirect
	AND	w,pin		; IF pin = 0 THEN receive data
	jnz	:poll		; ELSE poll
	clc
	mov	w,>>baud	; LET temp3 = baud/2
	mov	temp3,w 	; Set up 1/2 bit time delay.
	CALL	get_bit:loop	; Jump into delay of get_bit.
	mov	temp3,baud	; Set up full bit time delay.
	CALL	get_bit:loop	; Jump into delay of get_bit.
	mov	temp2,#8	; Eight data bits.
:rcv	mov	temp3,baud	; Set up bit delay.
	CALL	get_bit 	; Get the next data bit.
	djnz	temp2,:rcv	; Eight bits received?
:done	mov	temp3,baud	; Set up bit delay.
	CALL	get_bit:loop	; Wait for stop bit.
	jnb	filter,:skip	; IF filter=0 (off) THEN :skip
	clrb	aux		; LET aux = 0.
	csae	indirect,#filt_lo	; IF byte < filt_lo THEN aux=1
	setb	aux
	csbe	indirect,#filt_hi	; IF byte > filt_hi THEN aux=1
	setb	aux
	jnb	aux,:skip	; If aux = 0 (byte is within
	snb	filt_1st	; filter range) :skip. If byte is
	ret			; out of range, but valid bytes have
	jmp	:poll		; been received, return. Else poll.
:skip	setb	filt_1st
	DEC	temp1		; Decrement buffer pointer.
	inc	buffer		; Increment buffer counter.
	djnz	bytes,:poll	; More bytes to receive: poll.
	ret

BACK