; PROGRAM: SERIN4.SRC  

; Taken from Parallax PIC Application Note: Receiving RS-232 Serial Data. 

;Note that this is in Parallax 'dialect' which groups several commands into 
;one. There is a translation supplied in the Parallax assembler manual, now
;distributed by Tech Tools at www.tech-tools.com. A program to convert to  
;the Microchip 'dialect' is available from either Tech Tools as above or from 
;Advanced Transdata at www.adv-transdata.com. Assemblers that handle this
;dialect are also available from the above sources (eg. SPASM). The object 
;code, serinsw.obj, should run on any programmer.

;       ****** This runs at 2400 BAUD, PIN 13 (RB.7) input *********
;       ****** Note also that it is computer only, it will NOT *****
;       ****** work with the stopwatch module **********************


;   The crystal is 4.000 MHz, and the module number is determined 
; by testing the DIP switches connected to port RA. Note that RA3 and 2
; are pulled high and RA1 and 0 are pulled low on the PC board

; Note that the opto coupler inverts the input from the transmitter
;and the output is an NPN transistor, logic 1 is off for the opto
;and consequetly the input to the micro is high (stop bit is high)


bit_K           =       102             
half_bit        =       bit_K/2         
serial_in       =       rb.7
data_out        =       rb
location        =       10h                
number          =       11h

ident           =       12h   ;This is the module selected


; Variable storage above special-purpose registers. 

		org     8 

delay_cntr      ds      1               ;Counter for serial delay routines
bit_cntr        ds      1               ;Number of received bits
rcv_byte        ds      1               ;The received byte

; Org 0 sets ROM origin to beginning for program.

		org     0

		device  pic16c54,xt_osc,wdt_off,protect_off
		reset   begin

; Set up I/O ports. 

begin           mov     !ra, #00001111b ;Use rb.7 for serial input (pin13)
		mov     !rb, #10000000b         ;Output to LEDs. 
		mov      data_out,#3Fh   ;Display zero on start up
		
:start_bit      snb     serial_in       ;Detect start bit. Change to
					;sb serial_in if using 22k resistor
					;input. 

		jmp     :start_bit      ;No start bit yet? Keep watching.
		call    start_delay     ;Wait one-half bit time to the middle
					;of the start bit. 

		jb      Serial_in,:start_bit

					;If the start bit is still good,
					;continue. Otherwise, resume waiting.
					;Change to jnb Serial_in, :start_bit
					;if using 22k resistor input. 

		mov     bit_cntr, #8    ;Set the counter to receive 8 data bits
		clr     rcv_byte        ;Clear the receive byte to get ready
					;for new data. 

:receive        call    bit_delay       ;Wait one bit time. 

		movb    c,Serial_in     ;Put the data bit into carry. 
					;Change to movb c,/Serial_in if using
					;22k resistor input. 

		rr      rcv_byte        ;Rotate the carry bit into the receive
					;byte.

		djnz    bit_cntr,:receive ;Not eight bits yet? Get next bit.

		call    bit_delay       ;Wait for stop bit. 
		

		mov     number,rcv_byte    ;load number
		mov     location,rcv_byte  ;number location

		and     number,#00001111b    ;mask upper nibble
		and     location,#11110000b  ;mask lower nibble
		swap    location             ;move upper nibble down

		clrb    ident.7              ;ident register is used
		clrb    ident.6              ; when assessing is the 
		clrb    ident.5              ; received number is directed
		clrb    ident.4              ; to the particular module
		movb    ident.1,/RA.3        ;Must flip bits 3 & 2 due to 
		movb    ident.0,/RA.2        ; set up of PC board
		movb    ident.2,RA.1
		movb    ident.3,RA.0
		

		cse     location,ident      ;Correct number?
		jmp     begin:start_bit     ; No, receive  next byte

		mov     W,number
		call    getpattern
		mov     data_out,W           ;light up LED's

		jmp     begin:start_bit      ;receive  next byte


getpattern      jmp     PC+W

		retw    3Fh,06h,5Bh
		retw    4Fh,66h,6Dh
		retw    7Dh,07h,7Fh
		retw    6Fh 

		
; This delay loop takes four instruction cycles per loop, plus eight
; instruction cycles for other operations (call, mov, the final djnz, and ret).
; These extra cycles become significant at higher baud rates. The values for
; bit_K in the table take the time required for additional instructions into
; account.   

bit_delay       mov     delay_cntr,#bit_K 
:loop           nop
		djnz    delay_cntr, :loop
		ret     

; This delay loop is identical to bit_delay above, but provides half the delay
; time. 

start_delay     mov     delay_cntr,#half_bit 
:loop           nop
		djnz    delay_cntr, :loop
		ret
