; 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. 

	device	pic16c55,xt_osc,wdt_off,protect_off
	reset	start

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
	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


See:

http://www.piclist.com/techref/microchip/time.htm PIC Micro Controller Time / Clocks / Delays Library
