	title	"18F UART Example"

; **************************************
; 18F UART Example
; By PEK ´2004
;
; Version: 1.0.0
;
; MCU: PIC18F248
; Clock: 6 MHz
;
; **************************************

	list P=18F248, R=DEC

	include "P18F248.INC"

	__CONFIG _CONFIG1H, _HS_OSC_1H
	__CONFIG _CONFIG2L, _BOR_ON_2L & _BORV_42_2L & _PWRT_ON_2L
	__CONFIG _CONFIG2H, _WDT_OFF_2H


; **************************************
; Definitions
; **************************************
#define COMMAND_GETVERSION	0x01	; Get Version
#define COMMAND_INVALID		0xFF	; Invalid command

#define VERSION_MAJOR		0x01
#define VERSION_MINOR		0x00


; **************************************
; RAM locations
; **************************************
_w		EQU	0x0000			; Registers for saving during ISR
_status		EQU 0x0001
_bsr		EQU 0x0002
msgBytes	EQU 0x0003			; Bytes received/send during one message
msgByte1	EQU 0x0004			; Bytes in message
msgByte2	EQU 0x0005
msgByte3	EQU 0x0006


; **************************************
; Vectors
; **************************************
	org	0x00000				; Reset vector
	goto	Start
	
	org	0x00008				; Interrupt vector
	goto	ISR


; **************************************
; Start of Program
; ************************************** 
Start
; Init Ports
	movlw	B'10111111'
	movwf	TRISC				; RC6 as output

; Init UART
	movlw	38
	movwf	SPBRG				; 9600 bps, 0.16% error (at 6 MHz)
	movlw	B'00100100'
	movwf	TXSTA				; asynchronous, 8-bit, transmit enable, high speed
	movlw	B'10010000'
	movwf	RCSTA				; enable serial port, 8-bits, continous receive
	bsf	PIE1,RCIE			; Rx Interrupt Enable

; Init Registers
	clrf	msgBytes			; Zero bytes received/Send

	bsf	INTCON,PEIE			; Peripheral Interrupt Enable
	bsf	INTCON,GIE			; Global Interrupt Enable


; **************************************
; Main loop
; ************************************** 
Main
	goto	Main


; **************************************
; Interrupt Service Routine
; **************************************
ISR
	movwf	_w				; Save WREG
	movff	STATUS,_status			; Save STATUS
	movff	BSR,_bsr			; Save BSR

	btfsc	PIR1,RCIF			; Rx interrupt?
	goto	ISRRx_Int

	btfsc	PIR1,TXIF			; Tx interrupt?
	goto	ISRTx_Int

ISREnd
	movff	_bsr,BSR			; Restore BSR
	movf	_w,w				; Restore WREG
	movff	_status,STATUS			; Restore STATUS
	retfie


ISRRx_Int
	movlw	06h
	andwf	RCSTA,w				; Check for errors
	btfss	STATUS,Z			; Was there an error?
	goto	ISRRx_Err

	movf	msgBytes,w
	btfsc	STATUS,Z			; First byte of message?
	movff	RCREG,msgByte1

	movf	msgBytes,w
	xorlw	1
	btfsc	STATUS,Z			; Second byte of message?
	movff	RCREG,msgByte2

	movf	msgBytes,w
	xorlw	2
	btfsc	STATUS,Z			; Third byte of message?
	goto	ISRRx_DoCommand	

	incf	msgBytes			; Increase bytes counter
	goto	ISREnd

ISRRx_Err
	bcf	RCSTA,CREN			; Clear error status
	bsf	RCSTA,CREN

	clrf	msgBytes			; Sender must restart sending

;; Do something else here, send an error message?
	goto	ISREnd

ISRRx_DoCommand
	movff	RCREG,msgByte3
	clrf	msgBytes			; Clear bytes counter
	
	movf	msgByte1,w
	xorlw	COMMAND_GETVERSION
	btfsc	STATUS,Z			; Command: GETVERSION ?
	goto	ISRRx_GetVersion
	
	goto	ISRRx_InvalidCmd		; Command: Invalid

ISRRx_GetVersion
	movlw	VERSION_MAJOR
	movwf	msgByte2
	movlw	VERSION_MINOR
	movwf	msgByte3
	call	SendMessage			; Send Version
	goto	ISREnd

ISRRx_InvalidCmd
	movlw	COMMAND_INVALID
	movwf	msgByte1
	clrf	msgByte2
	clrf	msgByte3
	call	SendMessage			; Send Invalid Command
	goto	ISREnd


ISRTx_Int
	movf	msgBytes,w
	btfsc	STATUS,Z			; First byte of message?
	movff	msgByte1,TXREG

	movf	msgBytes,w
	xorlw	1
	btfsc	STATUS,Z			; Second byte of message?
	movff	msgByte2,TXREG

	movf	msgBytes,w
	xorlw	2
	btfsc	STATUS,Z			; Third byte of message?
	goto	ISRTx_LastByte

	incf	msgBytes			; Increase bytes counter
	goto	ISREnd

ISRTx_LastByte
	movff	msgByte3,TXREG			; Send last byte
	clrf	msgBytes			; Clear bytes counter
	bcf	PIE1,TXIE			; No further Tx interrupts	
	bsf	PIE1,RCIE			; Rx Interrupt Enable
	goto	ISREnd

SendMessage
	clrf	msgBytes			; Zeros bytes send
	bcf	PIE1,RCIE			; No further Rx interrupts
	bsf	PIE1,TXIE			; Tx Interrupt Enable	
	return


	END

