Serial LCD dmo

Code to drive an LCD and a serial routine so that serial data can be displayed.

 
 ;**************************************************************************
 ; LC001.ASM
 ;
 ; PROGRAM: Simple LCD project
 ;
 ; DESCRIPTION: 
 ; 
 ; AUTHOR:  Douglas Rice
 ; Copyright 2000
 ;
 ;	Crystal:	4MHz
 ;
 ;	I/O used:-
 ;
 ;	; Port B is used for the LCD
 ;
 
 	INCLUDE "p16F84.inc"       
 ;
 ;**************************************************************************
 
         LIST P=16F84, R=DEC
 	__idlocs  0x1234
 	__config  _XT_OSC&_PWRTE_ON & _WDT_OFF
 
 ;	NOEXPAND
 	cblock 	0x0c
 	endc
 
 ;--------------------------------------------------------------------------
 ; Sec 1. Equates and Constants
 ;--------------------------------------------------------------------------
 ; The General Purpose Registers start at the end of the 
 ; Special Purpose Registers.
 
 ; IPMentState values
 ; in normal running or in time setting modes
 ;
 
 ; DoTimeSlice bits
 ; these bits are set to schedule a timer chain event
 DTsS4event	EQU	0	; 
 DTsSevent	EQU	1
 DTsMevent	EQU	2
 DTSTriggered	EQU	3	; a capture should take place
 DTsTurnOff	EQU	4
 DTsMeasFreq	EQU	5
 DTsDispFreq	EQU	6
 DTsDispCount	EQU	7
 
 ; IPtrigMenu
 DTSWaitForEdge	EQU	0	; if set, then wait for 0 to 1 edge on PA0
 DTSSingle	EQU	1
 
 ; IPtrigMenu
 DTSFast		EQU	0
 
 ;--------------------------------------------------------------------------
 ; Sec 1.1 Button and LED 
 ;--------------------------------------------------------------------------
 
 BUTTON_RS232	EQU	0	; EDG  - Bottom Buttom
 
 BUTTON_DOWN	EQU	6	; EDG  - Bottom Buttom
 BUTTON_UP		EQU	7	; TRIG - Middle Button 
 
 
 LCDnumSamples	EQU	40
 ; PORTA binary values
 
 ;--------------------------------------------------------------------------
 ; Sec 1.2 Button and LED 
 ;--------------------------------------------------------------------------
 
 ;--------------------------------------------------------------------------
 ; Sec 2.0 Variables
 ;--------------------------------------------------------------------------
 ; Variables start 0x0C
 ;
 ; Variables for FlashLED ( FL ) process 
 ;
 
 ;	DoTimeSlice Bits, to schedule, set bit
 
 	cblock 	
 DoTimeSlice
 
 IPnew
 IPlast
 IPbuttonEvent
 
 IPnewFast
 IPlastFast
 IPbuttonEventUp
 
 IPtrigMenu
 
 LCDAnalSpeed
 LCDcnt3
 LCDgetCharFlag
 
 LCDbase
 LCDbaseCnt
 
 CLtmr4sec
 
 RSloopCnt
 RSdata
 RSdell
 	endc
 
 ; *********** I/O EQUATES **************
 PORTA           EQU  5          ; 5 BITS
 PA0             EQU  0		
 PA1             EQU  1		
 PA2             EQU  2		
 PA3             EQU  3          
 PA4             EQU  4          
 
 PORTB           EQU  6         
 PB0             EQU  0		; Serial In
 PB1             EQU  1		
 PB2             EQU  2		
 PB3             EQU  3		
 PB4             EQU  4		
 PB5             EQU  5		
 PB6             EQU  6		
 PB7             EQU  7		
 
 RS232tx         EQU  PA0	; Serial Out
 RS232rx         EQU  PB0	; Serial In
 
 buildLCD_HD44780
 
 TEST_STRADDLE	MACRO	START
 	if high( $ ) != high( START ) 
 	    Error "Table straddles Page Boundary " + Start
 	endif
 	endm
 
 ;--------------------------------------------------------------------------
 ; Sec 3. Program Code
 ;--------------------------------------------------------------------------
 
 
 		ORG     0       
 		GOTO    Start
 
 		ORG 	4
 		RETFIE
 		GOTO 	Intrtn
 
 ;--------------------------------------------------------------------------
 ; Sec 3.1	Main Program Init Code
 ;--------------------------------------------------------------------------
 
 Start
 
 		CALL	LCDdelaylong
 		CALL	LCDdelaylong
 		CALL	LCDdelaylong
 
 
 		; Enable Interupts
 		MOVLW	H'00'
 		MOVWF	INTCON
 
 		; Set up PortB:7 as output.
 		BSF	STATUS, RP0
 		MOVLW	0XF0
 		MOVWF	TRISB
 		MOVLW	0xFF	; Make PORTA 3:0 INPUTS.
 		MOVWF	TRISA
 		BCF	STATUS, RP0
 
 		CLRF	DoTimeSlice	
 
 		; Change Prescaler
 		CLRWDT
 		; Configure Tmr 0
 		BSF	STATUS,RP0
 		; Set up prescaller for 8192 / 16 = 512 ticks perseconds.
 		MOVLW	0x0 + 2 	; For Tmr0 0=/2, 1=/4, 2=/8,3=/16
 		MOVWF	OPTION_REG
 
 		BCF	STATUS,RP0
 		CALL 	LCDstart
 
 		MOVLW	LCDCurLeftLower
 		CALL 	LCDwrtCmd	
 		
 		CLRF	LCDbase
 		CLRF	IPbuttonEvent
 		CLRF	IPbuttonEventUp
 
 		GOTO	MainLoop
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.2	Main Program 
 ;--------------------------------------------------------------------------
 
 MainLoop	
 	; Enable Interupts
 	; Disable Interupts
 MLdisableInt	
 
 		CALL	CLtimeslice
 
 		CALL	IPtimesliceFast
 		
 		
 		; test for rising edge
 		BTFSC	IPbuttonEventUp,BUTTON_RS232	; RS232 input start 
 		CALL	IPrs232
 
 		; test for button presses
 		BTFSC	IPbuttonEvent,BUTTON_UP	; On BUTTON_RATE Press
 		CALL	IPupPressed
 
 		BTFSC	IPbuttonEvent,BUTTON_DOWN	; On BUTTON_RATE Press
 		CALL	IPdownPressed
 
 
 		GOTO 	MainLoop
 
 
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3 	Jump Table for running or time setting mode
 ;--------------------------------------------------------------------------
 
 LCDInit
 	; We run this from the toggle state and 
 	; Prevent update of time display on second ticks.
 	RETURN
 
 	include "lcd4mhz.inc"
 
 ; the code below must be kept together.
 LCDgetByte
 	; we should have set up PCLATH
 	; and reset LCDgetCharFlag
 	
 ;	BCF	LCDPortB,LCDgetCharFlag
 	MOVLW	high $
 	MOVWF	PCLATH 
 	MOVFW	LCDstrPtr;
 ;	INCF	LCDstrPtr,f
 ;	ADDWF	PCL,f
 	MOVWF	PCL
 
 LCDstrs
 LCDstrLFast	;equ	$ - LCDstrs
 	DT	"del"
 	GOTO	LCDgetByteEnd2		; now print out 4 blanks
 
 LCDstrLCont	;equ	$ - LCDstrs
 	DT	"C   "
 	GOTO	LCDgetByteEnd1
 
 LCDstrLContEdge	;equ	$ - LCDstrs
 	DT	"C_- "
 	GOTO	LCDgetByteEnd1
 
 LCDstrLSingle	;equ	$ - LCDstrs
 	DT	"S   "
 	GOTO	LCDgetByteEnd1
 
 LCDstrLSingleEdge	;equ	$ - LCDstrs
 	DT	"S_- "
 	GOTO	LCDgetByteEnd1
 
 LCDstrLFreq		;equ	$ - LCDstrs
 	DT	"Freq"
 	GOTO	LCDgetByteEnd1
 
 LCDstrLTime		;equ	$ - LCDstrs
 	DT	"Time LCD001.asm"
 	GOTO	LCDgetByteEnd1
 
 LCDLastStr
 	TEST_STRADDLE	LCDgetByte
 
 	; Jump into these to select how many spaces printed
 	; at the end, so that 9 chars are printed.
 LCDgetByteEnd0
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd1
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd2
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd3
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd4
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd5
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd6
 	BSF	LCDPortB,LCDgetCharFlag
 	CLRF	LCDstrPtr
 	DECFSZ	LCDstrPtr,f
 	NOP
 	RETURN
 
 ;--------------------------------------------------------------------------
 ; Sec 4.	Subroutines, procedures and functions
 ;--------------------------------------------------------------------------
 
 ;--------------------------------------------------------------------------
 ; Sec 4.1	Button Poll Routine
 ;--------------------------------------------------------------------------
 		
 IPtimeslice
 		;	--_____	button press
 		;	----___	
 		
 		;	__-----  /IPnew
 		;	----___  IPlast
 		;	__--___  
 		;
 		;
 		;
 		; This reads all Port B inputs and looks for Press
 		MOVFW	IPnew
 		MOVWF	IPlast
 		MOVFW	PORTB
 		MOVWF	IPnew
 		; IP last contains new setting, IPlast contains previous
 		; look for falling edges
 		COMF	IPnew,W
 		ANDWF	IPlast,W
 		; now force IPbuttonEvent bits to high for new pressed button
 		; the service routine should reset the bit to clear the event.
 		IORWF	IPbuttonEvent,F
 
 	
 		RETURN
 
 IPtimesliceFast
 		; Look for rising edges
 		MOVFW	IPnewFast
 		MOVWF	IPlastFast
 		MOVFW	PORTB
 		MOVWF	IPnewFast
 
 		COMF	IPlastFast,W
 		ANDWF	IPnewFast,W
 		IORWF	IPbuttonEventUp,F
 		RETURN
 
 
 ;--------------------------------------------------------------------------
 ; Sec 4.2	
 ;--------------------------------------------------------------------------
 
 IPupPressed 
 	BCF IPbuttonEvent,BUTTON_UP
 
 	MOVLW	LCDCurLeftLower
 	CALL 	LCDwrtCmd	
 	
 	MOVLW	0x10
 	MOVWF	LCDbaseCnt
 	
 IPupPressed1 
 
 	MOVFW	LCDbase
 	CALL 	LCDwrtChar
 	INCF	LCDbase,f	
 	
 	DECFSZ	LCDbaseCnt
 	GOTO 	IPupPressed1 
 	
 	MOVLW	LCDCurLeftLower
 	CALL 	LCDwrtCmd	
 
 	return
 
 
 IPdownPressed 
 	BCF IPbuttonEvent,BUTTON_DOWN
 
 	MOVLW	LCDCurLeftLower
 	CALL 	LCDwrtCmd	
 	
 	MOVLW	0x10
 	MOVWF	LCDbaseCnt
 	
 IPdownPressed1 
 
 	MOVFW	LCDbase
 	CALL 	LCDwrtChar
 	DECF	LCDbase,f	
 	
 	DECFSZ	LCDbaseCnt
 	GOTO 	IPdownPressed1 
 	
 	MOVLW	LCDCurLeftLower
 	CALL 	LCDwrtCmd	
 	
 	return
 
 
 
 IPrs232
 	BCF IPbuttonEventUp,BUTTON_RS232
 	GOTO RS232in 	
 	
 
 
 ;--------------------------------------------------------------------------
 ; Sec 4.3	Clock Chain Routine
 ;--------------------------------------------------------------------------
 		
 CLtimeslice
 		;
 		BTFSS	INTCON,T0IF
 		RETURN
 
 		; TMR0 timeout
 		BCF	INTCON,T0IF
 		BSF	DoTimeSlice,DTsS4event
 		
 		CALL	IPtimeslice
 	
 
 		RETURN
 
 ;--------------------------------------------------------------------------
 ; Sec 4.6	Event Handler Routine - Buttons
 ;--------------------------------------------------------------------------
 ; come here and combine the current state and the current event to index into 
 ; the state jump table.
 ;
 
 IPtrigMenuJT
 		MOVLW	high $
 		MOVWF	PCLATH
 
 		MOVFW 	IPtrigMenu
 		ANDLW	0x03
 
 		ADDWF	PCL,f
 		; set choice State Table - limited to 2 states and two events
 		RETLW	LCDstrLCont
 		RETLW	LCDstrLContEdge
 		RETLW	LCDstrLSingle
 		RETLW	LCDstrLSingleEdge
 
 
 
 	TEST_STRADDLE IPtrigMenuJT
 
 DTSTriggered	EQU	3	; a capture should take place
 DTsTurnOff	EQU	4
 DTsMeasFreq	EQU	5
 DTsDispFreq	EQU	6
 DTsDispCount	EQU	7
 
 ;--------------------------------------------------------------------------
 ; Sec 4.7	Serial Input Routine
 ;--------------------------------------------------------------------------
 
 ;**************************************************
 
 RS232in
 		; spin for a start bit 
 ;		CLRWDT
 ;		BTFSS	PORTB,RS232rx	
 ;		GOTO	RS232in		
 		
 		
 		CALL 	Delay6
 		CALL    Delay5
 		movlw	8
 		movwf	RSloopCnt
 RS232inL0
 ;		BTFSC	PORTB,RS232rx
 ;		GOTO	RS232inL1
 ;		BSF		STATUS,C
 ;		GOTO	RS232inL2
 ;RS232inL1	BCF		STATUS,C
 ;RS232inL2	RRF		RSdata,F
 
 		MOVFW	PORTB
 		ANDLW	 1<< RS232rx		; mask off bit
 		ADDLW	-1<< RS232rx		; use ripple carry to move into C
 		RRF		RSdata,F
 		
 		CALL	Delay5
 		DECFSZ	RSloopCnt,f
 		goto	RS232inL0
 
 		; test for Stop bit
 		COMF	RSdata,f
 
 		MOVFW	RSdata		
 		ADDLW	-0x0D
 		SKPNZ
 		GOTO	RSfoundCR
 		ADDLW	0x0D
 		CALL 	LCDwrtChar	
 		RETURN
 		
 
 RSfoundCR
 
 		MOVLW	LCDCurLeftLower
 		CALL 	LCDwrtCmd	
 
 
 		RETURN
 	
 
 Delay5		
 ;		RETURN
 ;		NOP
 		NOP
 		MOVLW	0x1E
 		MOVWF	RSdell
 Delay51		DECFSZ	RSdell		; 1
 		GOTO	Delay51		; 2 clk
 		CLRWDT
 		RETURN
 
 ;***************
 ;		Delay 0x0F * 3 ticks of 4Mhz ~= 45us
 Delay6		
 ;		RETURN
 ;		MOVLW	0x0F
 		MOVLW	0x08		; shorten delay as edge detector takes about 22 us
 
 		MOVWF	RSdell
 Delay61		DECFSZ	RSdell
 		GOTO	Delay61
 		CLRWDT
 		RETURN
 
 
 		
 		
 		
 
 
 ;--------------------------------------------------------------------------
 ; Sec 5.0	Interrupt Routines
 ;--------------------------------------------------------------------------
 
 Intrtn		
 		; Which Interupt ?
 		; No Context Save in these routines.
 ;		BTFSC	INTCON,2
 ;		GOTO	IntTmr0
 ;		BTFSC	INTCON,1
 ;		GOTO	Intfint
 ;		BTFSC	INTCON,0
 ;		GOTO	IntRbport
 IntTmr0
 ;		BCF INTCON,2
 		RETFIE
 Intfint
 ;		BCF INTCON,1
 ;		RETFIE
 IntRbport
 ;		BCF INTCON,0
 		RETFIE
 
 ;--------------------------------------------------------------------------
 ; Program End
 ;--------------------------------------------------------------------------
 
 ;--------------------------------------------------------------------------
 ; EEPROM data
 ;--------------------------------------------------------------------------
 		ORG	0x2100
 		; first 2 on and off are general ones
 		DE	0x24,0x00  ; 4
 	cblock 	
 LastVar
 	endc
                END
 
 
 
 

LCD code

 ;**************************************************************************
 ;
 ;
 ; LCD4MHZ.inc	LCD code to drive an epson SED1200 ( 32Khz clk ) or  Hitachi HD44780 ( 4Mhz clk)
 ;	
 ; Description: 	Drives EPSON EA-C20017AR based upon Epson 
 ;		SED1200F if buildLCDsed1200 defined
 ;
 ;		Drives Hitachi HD44780 based Modules if if buildLCD_hd44780 defined
 ;
 ;		Common Procedures:-
 ;			LCDwrtStr	- display a String into 10 byte window starting at 0x80.
 ;			LCDdispByte	- display byte as two hex nibbles
 ;			LCDwrtChar	- write Char to module
 ;			LCDwrtCmd	- write CMD  to module
 ;
 ;			Cursor addres 0x80 is line 1 on both modules
 ;			Cursor addres 0xC0 is line 2 on both modules.
 ;
 ;			On SED1200 line 1 is left 10 Chars
 ;			On SED1200 line 2 is Right10 Chars
 ;
 ;			Treat the two sides separately, as two lines
 ;			
 ;			On HD557840 line 1 is top line
 ;			On HD557840 line 2 is bottom line
 ;	
 ;			LCDstart	- Initilizes Module
 ;
 ;Define one of these to select the module in main file.
 ;
 ; buildLCDsed1200
 ; buildLCD_HD44780
 ;
 ;
 ; Author: 	Doug Rice
 ;
 ;
 ;           
 ;
 ;**************************************************************************
 
 
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3	LCD routines stuff 
 ;--------------------------------------------------------------------------
 
 		cblock
 LCDtemp		;
 LCDcnt		;
 LCDnibble	;
 LCDPortB	; image of port B for unused bits
 LCDeraseCnt	;
 LCDstrPtr 	;
 		endc
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.4.2	LCD procedures LCD string write displayes
 ;--------------------------------------------------------------------------
   ifdef buildLCDgetByte
 LCDgetByte
 	; we should have set up PCLATH
 	; When LCDstrPtr gets to 0xFF
 	MOVLW	high $
 	MOVWF	PCLATH 
 	MOVFW	LCDstrPtr;
 	ADDWF	PCL,f
 
 LCDstrs
 LCDstrLTime	equ	$ - LCDstrs
 	DT	"Hello"
 	GOTO	LCDgetByteEnd4		; now print out 4 blanks
 
 
 LCDstrLblank	equ	$ - LCDstrs
 	DT	"   "
 	GOTO	LCDgetByteEnd6
 
 LCDstrLOff	equ	$ - LCDstrs
 	DT	"OFF"
 	GOTO	LCDgetByteEnd6
 
 LCDstrLOn	equ	$ - LCDstrs
 	DT	"ON "
 	GOTO	LCDgetByteEnd6
 LCDstrLOnp	equ	$ - LCDstrs
 	DT	"ON+"
 	GOTO	LCDgetByteEnd6
 
 
 LCDLastStr
 
 	IF  0 !=  ( high ( LCDLastStr ) - high ( LCDgetByte ) )
 	Error "String Table straddles Page Boundary "
 	ENDIF
 	; Jump into these to select how many spaces printed
 	; at the end, so that 9 chars are printed.
 LCDgetByteEnd0
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd1
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd2
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd3
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd4
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd5
 	DECF	LCDeraseCnt,f
 LCDgetByteEnd6
 	CLRF	LCDstrPtr
 	DECF	LCDstrPtr,f
 	RETURN
   endif ; buildLCDgetByte
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.4.3	LCD procedures LCD string write displayes
 ;--------------------------------------------------------------------------
 
 LCDwrtStr	; W contains the string offset
 	MOVWF	LCDstrPtr;
 	
 	; 	Erase upto 6 chars at end of string
 	MOVLW	0x06
 	MOVWF	LCDeraseCnt
 
 	; position cursor at left on line 1.
 	; erase old display
 	MOVLW	LCDCurLeft0	; 0x80
 	CALL 	LCDwrtCmd
 	GOTO	LCDwrtStr1
 
 LCDwrtStr0
 	CALL 	LCDwrtChar
 LCDwrtStr1
 	CALL	LCDgetByte
 	INCFSZ	LCDstrPtr,f
 	GOTO	LCDwrtStr0
 	GOTO 	LCDwrtStrFlush
 
 ; write 10 chars to blank rest of right
 LCDwrtStrFlush
 	; 	W contains the number of Chars to flush
 LCDwrtStrLoop
 	DECFSZ	LCDeraseCnt,f
 	GOTO	LCDwrtStrLoop1
 	RETURN
 LCDwrtStrLoop1
 	MOVLW	0x20
 	CALL 	LCDwrtChar
 	GOTO	LCDwrtStrLoop	
 
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.4	LCD procedures
 ;--------------------------------------------------------------------------
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.4.1	LCD procedures - Multi entry display procedure for commands, nibbles,bytes,chars
 ;--------------------------------------------------------------------------
 
 
 LCDdispByte
 	MOVWF	LCDnibble
 
 	; Display top nipple
 	SWAPF	LCDnibble,w
         CALL    LCDwrtDecNibble
 	; Display bottom nipple
 	MOVFW   LCDnibble
         CALL    LCDwrtDecNibble
 	RETURN
 
 LCDwrtCmd
 	BCF	LCDPortB,LCDbitA0
 	GOTO	LCDwrtByte
 
 LCDwrtDecNibble	; currently only displays 0..9, A..F
 	ANDLW	0x0F
 	ADDLW	0x06	; is it A..F, if so trigger a digit overflow
 	SKPNDC
 	ADDLW	7; subtract 10, then add 'A'-'0'
 	ADDLW	0x30-6	; Subtract extra 6 added to cause DC
 LCDwrtChar
 	BSF	LCDPortB,LCDbitA0
 
 
 
 
   ifdef buildLCD_HD44780
 
 ;You don't need to read the busy line on the display.
 ;
 ;PORT B		Display		LCD Pin
 ;DB7		DB7		14
 ;DB6		DB6		13
 ;DB5		DB5		12
 ;DB4		DB4		11
 ;DB3		E		 6
 ;		R/W	gnd	 5
 ;DB2		RS		 4
 ;		V0	Vlcd	 3
 ;		Vss	0	 2
 ;		Vdd  +5  	 1
 
 ;R/W	==X====================x====
 ;RS	____________________________	0 for CMD, 1 for DATA
 ;E	____/----\____/-----\_______
 ;DB	==X=========X==========X====
 ;	      MSN	LSN
 
 ; define bits - these need to be defined for the HD44780 chip
 ;LCDbitCS        EQU     1	; PORTB:1
 ;LCDbitWR        EQU	3	; PORTB:3
 ;LCDbitCLK       EQU	3	; PORTB:3 or OSC Out
 
 LCDbitE		EQU	3
 LCDbitRS	EQU	2
 
 LCDbitA0	EQU	LCDbitRS	; RS - PORTB:2 ; sometimes used for bit number
 
 LCDCurOff       EQU     0x0C	; DisplayOn, Cursor Off, Blink Off
 LCDCurOn	EQU     0x0F	; DisplayOn, Cursor On, Blink On
 
 LCDCurLeft0     EQU     0x80	; display 80,..,89,C0..C9 ; top
 LCDCurRight0    EQU     0xC0	; left
 LCDCurLeftLower    EQU     0xC0	; left
 
 
 
 LCDwrtByte
 ; assume that the A0 line is correctly set,
 ; Byte to be displayed is in W
 ; SED1200 LCD chip
 ; CS    ----________------------------------------------------
 ; WR,CLK-----__--__------_-_-_-_--_-_-_-_--_-_-_-_--_-_-_-_---
 ; DB,A0 ---x====x====x----------------------------------------
 
 ; HD44780 LCD chip
 ;R/W	==X====================x====
 ;RS	____________________________	0 for CMD, 1 for DATA
 ;E	____/----\____/-----\_______
 ;DB	==X=========X==========X====
 ;	      MSN	LSN
 
 
 ; Assumes:- 
 ; LCD_DB0..3 connected to PORTB:4..7
 ; R/~w connected to Gnd.
 ; R/S,E  are equated, but connected to PORTB
 ; on exit PORTB<4:7> are left as inputs, so that they can
 ; be used for the keyboard/buttons.
 
 	MOVWF   LCDtemp
 	; set up PORTB<0:3> to Outputs,PORTB<4:7> to Outputs	
 	MOVLW	0x00		; This is only required if
 	MOVWF	PORTB		; The MS nibble is used as
 	BSF	STATUS, RP0	; inputs when reading buttons.
 	MOVLW	0x01		;
 	MOVWF	TRISB		;
 	BCF	STATUS, RP0	;
 
 	BTFSC	LCDPortB, LCDbitA0 ; set RS line early
 	BSF	PORTB,LCDbitA0	
 	BTFSS	LCDPortB, LCDbitA0 ; set
 	BCF	PORTB,LCDbitA0	
 
 ; set up to write top nibble, then pulse WR
 	MOVFW	LCDtemp
 	ANDLW	0xF0 	; assumes DB0..DB3 is MSB
 	BTFSC	LCDPortB, LCDbitRS ; set
 	IORLW	 1 << LCDbitRS 
 	MOVWF   PORTB
 	
 	BSF     PORTB,LCDbitE
 	NOP       
 	BCF     PORTB,LCDbitE
 
 ; set up to write bottom nibble, then pulse WR
 	SWAPF	LCDtemp,w
 	ANDLW	0xF0 	; assumes DB0..DB3 is MSB
 	BTFSC	LCDPortB, LCDbitA0 ; set
 	IORLW	 1 << LCDbitRS 
 	MOVWF   PORTB
 
 	BSF     PORTB,LCDbitE
 	NOP
 	BCF     PORTB,LCDbitE
 	NOP
 
 	; set up PORTB<0:3> to Outputs,PORTB<4:7> to Inputs
 	BSF	STATUS, RP0	;
 	MOVLW	0xF1		;
 	MOVWF	TRISB		;
 	BCF	STATUS, RP0	;
 
 ; Run a little delay to allow the instructions to take place.
 	MOVLW	20
 ;	MOVLW	1
 
 	MOVWF	LCDtemp
 ; Hold CS high and pulse WR low at least 16 times
 ; Now pulse CLK low 16 times to execute command
 LCDloop
 
 ;        BCF     PORTB,LCDbitCLK
 	NOP
 	NOP
 ;        BSF     PORTB,LCDbitCLK
         DECFSZ  LCDtemp,f
         GOTO    LCDloop
 
         RETURN
 
 
 LCDdelay
 	; 1.79 ms delay
 	MOVLW	255
 	MOVWF	LCDtemp
 LCDdelay1
 	GOTO	$+1
 	GOTO	$+1
         DECFSZ  LCDtemp,f
         GOTO    LCDdelay1
         RETURN
 
 
 LCDdelaylong
 	; 1.79 ms delay
 
 	CLRF	LCDtemp
 LCDdelaylong1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 	GOTO	$+1
 
         DECFSZ  LCDtemp,f
         GOTO    LCDdelaylong1
         RETURN
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.4.2	LCD procedures - Initilization
 ;--------------------------------------------------------------------------
 
 LCDstart
 
 ; Minimum reset instructions:
 
 ; System Reset,Line Select(2),Display On
 ; set up for LCD commands
 
 ;     wlcdCmd($33);
 ;     wlcdCmd($32);
 ;     wlcdCmd($28);	 { 4 bit, 2 line, 5x7 display }
 ;     wlcdCmd($01);     { Clear Display }
 ;     wlcdCmd($0F);     { $0F - Display On,CursorOn,Blink }
 ;     wlcdCmd($C9);     { set dd address }
 
 
         MOVLW   0x33		; 40us force to 8 bit mode, from any mode
         CALL    LCDwrtCmd
         MOVLW   0x32		; 40us force to 4 bit mode 
         CALL    LCDwrtCmd
         MOVLW   0x28		; 40us 4 bit, 2 line, 5x7 display 
         CALL    LCDwrtCmd
         MOVLW   0x01		; Clear display
         CALL    LCDwrtCmd
 
  	   CALL	   LCDdelay
 
         MOVLW   0x0F		; Display On,Cursor On,Blink
         CALL    LCDwrtCmd
         MOVLW   0x80
 
         MOVLW   10
         MOVWF   LCDcnt
 	; Now actually display something
 	MOVLW	LCDstrLTime
 	CALL	LCDwrtStr
 	RETURN
 
 
 ;To know wwhich nibble is being sent initilize to 8 bit then
 ;go into 4 bit mode and keep track of each nibble sent
 ;
 ;If using 4 bit interface only use the DB4 to DB7 pins.
 ;The 8 bits comands to convert to 4 bits mode do not care
 ;about the 4 LSB.
 ;
 ;With R/W =0 and RS=0:
 ;
 ;0x01	;clear display 		82us @250Hz
 ;0x02	;return home 		82us @250Hz
 ;0x04	;EntryModeSet 		40us @250Hz
 ;  0x01	; S	1 = shift
 ;  0x02  ; I/D	1= increment/0=decrement
 ;0x08	;Display ON/OFF		40us @250Hz
 ;  0x01	; B	Blink
 ;  0x02	; C	Cursor On
 ;  0x04	; D	Display On
 ;0x10	;Cursor and Display Shift		40us @250Hz
 ;  0x04	; s/c	Shift Display/ 0=shift Cursor
 ;  0x08	; r/l	Shift Right,0=shift left
 ;0x20	;Function Set		40us @250Hz
 ;  0x04	; F	5x10 dots /5x7dots
 ;  0x08	; N	2lines	/1lines
 ;  0x10	; DL	8bits interface /4 bits interface.
 ;0x40	;Set CG RAM address	40us @250Hz
 ;0x80	;Set DD RAM address;	40us @250Hz
 
 ;With R/W =0 and RS=1:
 ;write data to CG or DD 
 ;With R/W =1 and RS=1:
 ;Read data from CG or DD 
 ;
 ;Send the commands below to Initilize.
 ;First mop up any 4 bit commands, and convert to 8 bit,
 ;either from 4 bit mode or 8 bit mode.
 ;Then from 8 bit node move to  4 bit mode.
 ;Then issue 4 bit commands.
 
 ;     wlcdCmd($33);	 8 bit mode  - could be in 4 bit  mode	
 ;     wlcdCmd($32);	 8 bit mode  - could be in 4 bit  mode	
 ;     wlcdCmd($28);	 4 bit mode, 2 lines 5x7 dots
 ;     wlcdCmd($01);      Clear Display could take 1.6ms
 ;     wlcdCmd($0F);      $0F - Display On,CursorOn,Blink 
 ;     wlcdCmd($C9);      set dd address 
 
 ;You don't need to read the busy line on the display.
 ;
 ;PORT B		Display		LCD Pin
 ;DB7		DB7		14
 ;DB6		DB6		13
 ;DB5		DB5		12
 ;DB4		DB4		11
 ;DB3		E		 6
 ;		R/W	gnd	 5
 ;DB2		RS		 4
 ;		V0	Vlcd	 3
 ;		Vdd     +5  	 2
 ;		Vss	0	 1
 
 
   endif
 
 
   ifdef buildLCDsed1200
 
 ;
 ;
 ;================================================================
 ;this needs to be changed
 ;
 ;
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.1	LCD introduction - SED1200F
 ;--------------------------------------------------------------------------
 
 ;LCD Information
 ;==================
 ;
 ;Having brought a number of displays for a bargin price, and finding that the 
 ;information provided was inadequate, this document summarizes what has been 
 ;found out.
 ;
 ;
 ;Epson EA-C20017AR
 ;==================
 ;
 ;20 char by one line.
 ;
 ;The display appears to be based on an SED1200F controller.
 ;
 ;Pin Connections        when looking at display, contacts on left.
 ;
 ;       1       +5V     2       Gnd        |------------------|
 ;       3       Vlcd    4       Clk        |                  |
 ;       5       -CS     6       A0         |    DISPLAY 20x1  |
 ;       7       -WR     8       -RD        |      -           |
 ;       9       DB3     10      DB2        |                  |
 ;       11      DB1     12      DB0        |------------------
 ;
 ; Display is 20 x 1
 ; Suggested values for single line mode , 10 x 1 repeated 10 x 1.
 ;
 ; + 5V   Pin 1
 ;    |  
 ;   [ ]   10k ohm
 ;    |  
 ;Vlcd    Pin 3
 ;    |
 ;   [ ]   3k ohm
 ;    |
 ;  GND  
 ;
 ;
 ; For proper operation run the display as two line mode.
 ;
 ;
 ; Initialization. leaves random characters.
 ;
 ;       CMD, System Reset       0,0x10
 ;       CMD, DISPLAY ON         0,0x0D
 ;       CMD, Line Select-On     0,0x13
 ;       CMD, Cursor Home        0,0x80
 ;       DATA,0x20 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.2	LCD command equates
 ;--------------------------------------------------------------------------
 
 ;
 ; SED 1200F config commands A0=0
 ;
 LCDsetCurDirInc EQU     0x04
 LCDsetCurDirDec EQU     0x05
 LCDCurInc       EQU     0x06
 LCDCurDec       EQU     0x07
 LCDCurBlock     EQU     0x09
 LCDCurUL	EQU     0x08
 LCDCurConst     EQU     0x0A
 LCDCurBlink     EQU     0x0B
 LCDCurDispOff   EQU     0x0C
 LCDCurDispOn    EQU     0x0D
 LCDCurOff       EQU     0x0E
 LCDCurOn	EQU     0x0F
 LCDSysReset     EQU     0x10
 LCD1line	EQU     0x12
 LCD2line	EQU     0x13
 LCDCurX0Y0      EQU     0x80	; display has two halfs of 10 chars each
 LCDCurX1Y0      EQU     0xC0	;
 LCDCurLeft0     EQU     0x80	; display 80,..,89,C0..C9
 LCDCurRight0    EQU     0xC0	;
 
 LCDCgRamAddr    EQU     0x20
 LCDCgRamData    EQU     0x40
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.3	LCD control line / hardware to port mapping equates
 ;--------------------------------------------------------------------------
 
 
 ; define binary Mask for bits
 LCD_CS          EQU     2	; PORTB:1
 LCD_WR          EQU	8	; PORTB:3
 LCD_CLK         EQU	8	; PORTB:3 or OSC Out
 LCD_A0		EQU	4	; PORTB:2 ; sometimes used for bit number
 ; define bits
 LCDbitCS        EQU     1	; PORTB:1
 LCDbitWR        EQU	3	; PORTB:3
 LCDbitCLK       EQU	3	; PORTB:3 or OSC Out
 LCDbitA0	EQU	2	; PORTB:2 ; sometimes used for bit number
 
 
 
 LCDwrtByte
 ; assume that the A0 line is correctly set,
 ; Byte to be displayed is in W
 ;
 ; CS    ----________------------------------------------------
 ; WR,CLK-----__--__------_-_-_-_--_-_-_-_--_-_-_-_--_-_-_-_---
 ; DB,A0 ---x====x====x----------------------------------------
 
 
 ; Assumes:- 
 ; LCD_DB0..3 connected to PORTB:4..7
 ; RD connected to +5
 ; WR,CS,A0,CLK are equated, but connected to PORTB
 ; on exit PORTB<4:7> are left as inputs, so that they can
 ; be used for the keyboard/buttons.
 
         MOVWF   LCDtemp
 	; set up PORTB<0:3> to Outputs,PORTB<4:7> to Outputs	
 	MOVLW	0xFF		; This is only required if
 	MOVWF	PORTB		; The MS nibble is used as
 	BSF	STATUS, RP0	; inputs when reading buttons.
 	MOVLW	0x01		;
 	MOVWF	TRISB		;
 	BCF	STATUS, RP0	;
 
 	BTFSC	LCDPortB, LCDbitA0 ; set A0 line early
 	BSF	PORTB,LCDbitA0	
 	BTFSS	LCDPortB, LCDbitA0 ; set
 	BCF	PORTB,LCDbitA0	
 
 ; set up to write top nibble, then pulse WR
 	MOVFW	LCDtemp
 	IORLW	0x0F 	; -CS,-A0,-WR
 	BTFSS	LCDPortB, LCDbitA0 ; set
 	ANDLW	~LCD_A0
         MOVWF   PORTB
         BCF     PORTB,LCDbitCS
 
         BCF     PORTB,LCDbitWR
 	NOP
         BSF     PORTB,LCDbitWR
 
 ; set up to write bottom nibble, then pulse WR
 	SWAPF	LCDtemp,w
 	IORLW	0x0F 	; -CS,-A0,-WR
 	BTFSS	LCDPortB, LCDbitA0 ; set
 	ANDLW	~(LCD_A0 | LCD_CS)
 
 	ANDLW	~LCD_CS
         MOVWF   PORTB
         BCF     PORTB,LCDbitWR
 	NOP
 	NOP
 
         BSF     PORTB,LCDbitWR
 	NOP
 	NOP
         BSF     PORTB,LCDbitCS
 
 	; set up PORTB<0:3> to Outputs,PORTB<4:7> to Inputs
 	BSF	STATUS, RP0	;
 	MOVLW	0xF1		;
 	MOVWF	TRISB		;
 	BCF	STATUS, RP0	;
 
 	MOVLW	20
 ;	MOVLW	1
 
 	MOVWF	LCDtemp
 ; Hold CS high and pulse WR low at least 16 times
 ; Now pulse CLK low 16 times to execute command
 LCDloop
 
         BCF     PORTB,LCDbitCLK
 	NOP
 	NOP
         BSF     PORTB,LCDbitCLK
         DECFSZ  LCDtemp,f
         GOTO    LCDloop
 
 	; set up PORTB<0:3> to Outputs,PORTB<4:7> to Inputs
 	BSF	STATUS, RP0	;
 	MOVLW	0xF1		;
 	MOVWF	TRISB		;
 	BCF	STATUS, RP0	;
         RETURN
 
 
 ;--------------------------------------------------------------------------
 ; Sec 3.3.4.2	LCD procedures - Initilization
 ;--------------------------------------------------------------------------
 
 LCDstart
 
 ; Minimum reset instructions:
 
 ; System Reset,Line Select(2),Display On
 ; set up for LCD commands
 ;       CMD, System Reset       0,0x10
 ;       CMD, DISPLAY ON         0,0x0D
 ;       CMD, Line Select 2
 ;       CMD, Cursor On          0,0x0F
 ;       CMD, Cursor Dir         0,0x04
 ;       CMD, Cursor Blink off   0,0x0A
 ;       CMD, Cursor Home        0,0x80
 ;       DATA,0x20       BCF     PORTA,LCDA0
 
    	; LCD system reset
         MOVLW   0x10
         CALL    LCDwrtCmd
 
    	; LCD Display On
         MOVLW   0x0D
         CALL    LCDwrtCmd
 
         ; LCD Set 2 Line Mode
         MOVLW   0x13
         CALL    LCDwrtCmd
 
         ; LCD Display On
         MOVLW   0x0D
         CALL    LCDwrtCmd
 
         ; LCD Cursor Home
         MOVLW   0x80
         CALL    LCDwrtCmd
 
         MOVLW   10
         MOVWF   LCDcnt
 	; now write some characters
 LCDloop1
         MOVLW   0x20
         CALL    LCDwrtChar
         DECFSZ  LCDcnt,f
         GOTO    LCDloop1
                 
         ; LCD Cursor Home
 
         MOVLW   0xC0
         CALL    LCDwrtCmd
 
         MOVLW   10
         MOVWF   LCDcnt
 LCDloop2
         MOVLW   0x20
         CALL    LCDwrtChar
         DECFSZ	LCDcnt,f
         GOTO    LCDloop2
 LCDloop2A
 	; Now actually display something
 	MOVLW	LCDstrLTime
 	CALL	LCDwrtStr
 	RETURN
 
   endif ;buildLCDsed1200
 
 ;
 ;
 ;=======================================================================
 ;
 ;
 ;: Symbols that need to be defined differently for different LCD chips
 
 
 ;RT003.ASM 390 : (LCDstart)
 ;LCD.INC 151   : (LCDbitA0) ; check the sense
 ;LCD.INC 152   : (LCDwrtByte)
 
 ;RT003.ASM 803 : (LCDCurOn)
 ;RT003.ASM 812 : (LCDCurOff)
 ;RT003.ASM 680 : (LCDCurRight0)
 ;LCD.INC 104   : (LCDCurLeft0)
 
 
 ;--------------------------------------------------------------------------
 ; 	END OF FILE
 ;--------------------------------------------------------------------------
 
 
 

12F675 A/D module demo

Reads each A/D input and outputs serially at 32K baud on Pin GPIO5.

Strap GPIO3 low for serial.

Strap GPIO3 high to allow A/D0 bit5 to be copied to GPIO5.

 ;**********************************************************
 ;*  dm002.asm
 ;**********************************************************
 ;*  This program configures the A/D Module to convert on
 ;*  A/D channels and outputs the results serial at 32K
 ;**********************************************************
 
 	list p=12f675
 
 	; Include file, change directory if needed
 	include "p12f675.inc"
 	__idlocs  0x1234
 	__config  _PWRTE_ON & _WDT_OFF & _BODEN_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF 
 
 
 	cblock 	0x20
 	  ; variables used for context saving 
 	  w_temp
 	  status_temp
 	  ADrh
 	  ADrl
 	  ADcnt
 
 
 	  SRtxTemp
 	  SRtxCnt
 	  SRout
 	  SRdel
 
 
 	  cnt1
 	  cnt2
 	  cnt3
 	  
 	
 		
 	endc
 	
 
 	; Start at the reset vector
 	org	0x000
 ;	goto	test
 	goto	Init
 
 
 test
 	movlw	0
 	movwf	cnt1
 	movlw	1
 	movwf	cnt2
 
 test1
 	incf	cnt1,f
 	incf	cnt2,f
 
 	movfw	cnt1
 	xorwf	cnt2,w
         andlw	0x88
 	movwf	cnt3
 
 	goto test1
 
 
 
 
 Init
 
 	org	0x010
 	
 	banksel 0x3FF
 	CALL 	0x3FF
 	MOVWF	OSCCAL
 	banksel	TRISIO 
 
 	BSF		STATUS, RP0
 ;	movlw	0xCF
 	movlw	0xDF
 	MOVWF	TRISIO		; Set output high to start Measurement
 	BCF		STATUS, RP0
 
 	movlw	0x0D
 	call	SRtxChar
 	movlw	0x0A
 	call	SRtxChar
 	movlw	0x0D
 	call	SRtxChar
 	movlw	0x0A
 	call	SRtxChar
 	movlw	0x55
 	call	SRtxChar
 	movlw	0xAA
 	call	SRtxChar
 	movlw	' '
 	call	SRtxChar
 	movlw	'A'
 	call	SRtxChar
 	movlw	'/'
 	call	SRtxChar
 	movlw	'D'
 	call	SRtxChar
 	movlw	' '
 	call	SRtxChar
 	movlw	'('
 	call	SRtxChar
 	movlw	'8'
 	call	SRtxChar
 	movlw	'7'
 	call	SRtxChar
 	movlw	'6'
 	call	SRtxChar
 	movlw	')'
 	call	SRtxChar
 	movlw	' '
 	call	SRtxChar
 	movlw	0x55
 	call	SRtxChar
 	movlw	0xAA
 	call	SRtxChar
 	movlw	0x0D
 	call	SRtxChar
 	movlw	0x0A
 	call	SRtxChar
 ;	goto 	Init
 
 Start
 	; output p(,ad0,ad1,ad2,ad3,ad5,);
 
 	movlw	0x0D
 	call	SRtxChar
 	movlw	0x0A
 	call	SRtxChar
 	movlw	'p'
 	call	SRtxChar
 	movlw	'('
 	call	SRtxChar
 	movlw	','
 	call	SRtxChar
 
 	movlw	0 << 2
 	call	ADconvert
 
 	call	LDled
 
 
 	movlw	1 << 2
 	call	ADconvert
 	
 
 	movlw	2 << 2
 	call	ADconvert
 
 	movlw	3 << 2
 	call	ADconvert
 
 
 ;	movlw	','
 ;	call	SRtxChar
 	movlw	')'
 	call	SRtxChar
 
 	movlw	';'
 	call	SRtxChar
 
 	goto	Start		;Do it again
  
 
 ADconvert
 
 	; W contains the channel in bit 5-3
 
 	banksel  ADCON0
 	addlw	B'00000001'	;Fosc/8, A/D enabled
 	movwf	ADCON0
  
 	banksel  ANSEL
 	movlw	B'00010111'	;Fosc/8, A/D enabled
 	movwf	ANSEL
 	
 	banksel OPTION_REG
 	movlw	B'10000111'	;TMR0 prescaler, 1:256
 	movwf	OPTION_REG
 	banksel  ADCON0
 	movlw	0x80 | 2			;Left justify,5 analog channel
 	addwf	ADCON0,f		;VDD and VSS references
 
 	banksel GPIO
 	banksel INTCON
 
 Main
       ;	goto	StartConvert
 ;	btfss	INTCON,T0IF	;Wait for Timer0 to timeout
 ;	goto	Main
 ;	bcf	INTCON,T0IF
 
 	;
 	; use PORTA 4  as a delay.
 	;
 	;Vdd - [ Rt ] + [ R ] - pin RA4
 	;
 	;	     C
 	;	     |
 	;	    gnd	
 	;
 	; make RA4 an output to discharge C
 	; then make it an input
 	; Wait for C to Charge, then proceed.
 	;
 
 
 
 StartConvert
 	bcf		PIR1,ADIF
 
 	banksel	ADCON0 
 	bsf		ADCON0,GO	;Start A/D conversion
 
 Wait
 	btfss	PIR1,ADIF	;Wait for conversion to complete
 	goto	Wait
 
 
 	nop
 	nop
 	movfw	ADRESH
 	movwf	ADrl
 
 	; now output the value in Hex
 	swapf	ADrl,W		;Write A/D result to GPIO
 	call 	SRwrtHexNibble
 
 	movf	ADrl,W		;Write A/D result to GPIO
 	call 	SRwrtHexNibble
 
 	banksel ADRESL
 	movfw	ADRESL
 
 	banksel  ADrl
 	movwf	ADrl
 
 	swapf	ADrl,W		;Write A/D result to GPIO
 	call 	SRwrtHexNibble
 
 	movf	ADrl,W		;Write A/D result to GPIO
 	call 	SRwrtHexNibble
 
 	movlw	','
 	call	SRtxChar
 
 	return	
 
 
 
 SRwrtHexNibble	; currently only displays 0..9, A..F
 	ANDLW	0x0F
 	ADDLW	0x06	; is it A..F, if so trigger a digit overflow
 	SKPNDC
 	ADDLW	7; subtract 10, then add 'A'-'0'
 	ADDLW	0x30-6	; Subtract extra 6 added to cause DC
 	MOVWF	SRout
 	GOTO	SRtxChar
 
 
 
 SRtxChar
 
 	; test GPIO bit 3 to see if serial out or LED out
 	; GPIO bit 3 must be low
 	BTFSC	GPIO,3
 	RETURN
 	
 
 	;
 	;Output Start Bit
 	;Output LSB first
 	;use
 	
 TxOnBit  equ 5
 
 	
 	movwf	SRtxTemp
 	comf	SRtxTemp,f
 	
 	BCF		GPIO,TxOnBit
 	MOVLW	~( 3 << TxOnBit )
 ;	TRIS	GPIO
 	BSF		STATUS, RP0
 	MOVWF	TRISIO		; Set output high to start Measurement
 	BCF		STATUS, RP0
 
 	; 1200 baud output
 	; move the char into SRtxtemp, it is destroyed.
 	;Start Bit
 	BSF		GPIO,TxOnBit
 	GOTO	$+1
 	call	delay	
 	movlw	TxOnBit
 	movwf	SRtxCnt
 	GOTO 	$+1
 SRtxCharLp1
 
 	; This outputs two bits at a time 
 	; this takes 6.5 cycles each
 	
 	; After start bit, which is 1, then test each bit
 	; I need to set PA:0 to same as LSB SRtxTemp
 	; this compares PA:0 with SRtxTemp so see if it needs toggling
 	; The xorwf PORTA,f causes the bit to be toggled if required.
 
 	; Toggle bit if next bit is different 
 	RRF		SRtxTemp,f
 	movfw	STATUS
 	andlw	1 << C		; mask off bit
 	addlw   ( 1 << TxOnBit) -1	; shift bit by using a ripple carry
 		
 	xorwf	GPIO,W
 	andlw	0x1 << TxOnBit
 	xorwf	GPIO,f		;t+6,19
 
 	GOTO	$+1	
 	call	delay	
 	RRF		SRtxTemp,f
 
 	movfw	STATUS
 	andlw	1 << C
 	addlw   ( 1 << TxOnBit) -1
 
 	xorwf	GPIO,W
 	andlw	0x1 << TxOnBit
 	xorwf	GPIO,f		;t+11,24
 	GOTO	$+1	
 	call	delay	
 	decfsz	SRtxCnt
 	goto	SRtxCharLp1
 	GOTO	$+1	
 	GOTO	$+1	
 	call	delay	
 	BCF		GPIO,TxOnBit
 	GOTO	$+1	
 	GOTO	$+1	
 	RETURN
 
 
 
 
 
 delay	
 	nop
 	movlw	0x03
 	movwf	SRdel
 delay1	
 	decfsz	SRdel
 	goto	delay1
 	return
 
 ;---------------------------
 ; LD process
 ;---------------------------
 
 LDled
 
 	; test GPIO bit 3 to see if serial out or LED out
 	BTFSS	GPIO,3
 	RETURN
 
 
 	banksel ADRESL
 	movfw	ADRESL
 	movwf	ADrl
 
 	banksel	GPIO
 	bcf		GPIO,5
 	BTFSC	ADrl,5
 	bsf		GPIO,5
 	
 	return
 	
 
 
 	org	0x3FD
 	RETLW	0x6C
 	RETLW	0x6C
 	RETLW	0x6C
 
 	end