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