;12clock3.asm
;WWW.MWFTR.COM/book.html
;Charles Kim
;DIGITAL CLOCK ON LCD
; NO BUTTONS FOR THE MOMENT
;20x4 LCD module
;by Truly (HD44780 compatible)
;
; 4-bit interfacing
;
; Pin Connection from LCD to 16F877
; LCD (pin#)	16F877 (pin#)
;DB7 (14) -----RB7(40)
;DB6 (13) ----RB6(39)
;DB5 (12) ----RB5(38)
;DB4 (11) ----RB4(37)
;DB3 (10) 
;DB2 (9)
;DB1 (8) 
;DB0 (7) 
;E (6) ------RB2(35)
;RW (5) -----RB3(36)
;RS (4) -----RB1(24)
;Vo (3) -----GND
;Vdd (2) ----+5V
;Vss (1) -----GND
;
;Example code to display:
;	PIC CLOCK
;	HH:MM:SS
;

      list P = 16F877

STATUS		EQU	0x03
PORTB		EQU	0x06
TRISB		EQU	0x86
RS		EQU	0x01	;RB1
E		EQU	0x02	;RB2
RW		EQU	0x03	;RB3
CARRY		EQU	0x00
TMR0		EQU	0x01		;Timer0 module
INTCON		EQU	0x0B		;Intcon
OPTION_REG	EQU	0x81		;Option Register		
T0IF		EQU	0x02		;tmr0 overflow flag
T0IE		EQU	0x05		;Tmr0 interrupt enable/disable
ZERO		EQU	0x02		;Zero flag on STATUS (1: zero)
GIE		EQU	0x07		;Global Interrupt
;RAM 
       
	CBLOCK	0x20
		COUNT
		Kount120us   ;Delay count (number of instr cycles for delay)
		Kount100us
		Kount1ms
		Kount10ms

		Hms		;general variables for HH, MM, and SS
		hms1hex
		hms0hex
		hms1dec
		hms0dec
		hmstemp

		HH
		HHtemp
		HH1
		HH0
		HH1hex
		HH0hex
		hh1dec
		hh0dec
		MM
		MMtemp
		MM1
		MM0
		mm1hex
		mm0hex
		mm1dec
		mm0dec
		SS
		SStemp
		SS1
		SS0
		ss1hex
		ss0hex
		ss1dec
		ss0dec
		HILO10
		HILO20
		TENtemp
		TWENTYtemp
		Temp		;temp storage
	ENDC

;program should start from 0005h
;0004h is allocated to interrupt handler

        org 	0x0000      	
	goto	START		


	org	0x05
Start
	BANKSEL	TRISB
; 1 for input, 0 for output

	movlw	0x00
	movwf	TRISB		;All output

;	banksel	PORTB
;	clrf	PORTB		;RW set LOW here

;LCD routine starts
	call	delay10ms
	call	delay10ms

	banksel	PORTB
	bcf	PORTB, RW		;RW set LOW here
			;give LCD module to reset automatically

;For TMR0
	banksel	INTCON
	clrf	INTCON			;int disabled
	clrf	TMR0
	movlw	0xC7	
	banksel	OPTION_REG		;pre-scaler at 256
	movwf	OPTION_REG		;11000111
     	banksel	TMR0
	clrf	TMR0

;END FOR TMR0

;THE ONLY CHANGE IN 4-BIT INTERFACING 
;EXCEPT 2 SUBROUTINES
;
;Function for 4-bit (only one write must be done)
;In other words, send only the high nibble
;IMPORTANT
	movlw	0x28
	call	hnibble4	
;Fundtion for 4-bit, 2-line display, and 5x8 dot matrix
	movlw	0x28
	call	instw4
;Display On, CUrsor On, No blinking
	movlw	0x0E		;0F would blink
	call	instw4
;DDRAM address increment by one & cursor shift to right
	movlw	0x06
	call	instw4
;DISPLAY CLEAR

	movlw	0x01
	call	instw4

;Set DDRAM ADDRES
	movlw	0x80		;00
	call	instw4
;WRITE DATA in the 1st position of line 1
	movlw	0x50		;P
	call	dataw4	

	movlw	0x49		;I
	call	dataw4

	movlw	0x43		;C
	call	dataw4
	movlw	' '
	call	dataw4
	movlw	'C'
	call	dataw4
	movlw	'L'
	call	dataw4
	movlw	'O'
	call	dataw4
	movlw	'C'
	call	dataw4
	movlw	'K'
	call	dataw4
;
	call	clear
AGAIN
;CLOCK DISPLAY
;Set DDRAM address for the 1st position of line 2 (40h)

	movlw	0xC0			;B'11000000'
	call	instw4			;RS=0

;CLOCK DISPLAY PART

	movf	SS,0
	movwf	hms
	call	h2d2
	movf	hms1dec,0
	movwf	ss1dec
	movf	hms0dec,0
	movwf	ss0dec

	movf	MM,0
	movwf	hms
	call	h2d2
	movf	hms1dec,0
	movwf	mm1dec
	movf	hms0dec,0
	movwf	mm0dec

	movf	HH,0
	movwf	hms
	call	h2d2
	movf	hms1dec,0
	movwf	hh1dec
	movf	hms0dec,0
	movwf	hh0dec

	call	clockLCDdisplay
	call	delay1s
	incf	SS
	movf	SS,0
	clrf	STATUS
	xorlw	B'00111100'	;if SS=60(d) or 3C or 0011 1100
	btfss	STATUS, ZERO
	goto	again

	clrf	SS
	incf	MM
	movf	MM,0
	clrf	STATUS
	xorlw	B'00111100'
	btfss	STATUS,ZERO
	goto	again

	clrf	MM
	incf	HH
	movf	HH,0
	clrf	STATUS
				;check 24hour 24d = 00011000
	xorlw	B'00011000'
	btfss	STATUS,ZERO
	goto	again
	clrf	STATUS
	call	clear
	goto	again



;====SUBROUTINES =====	
;===h2d2====
;1 byte hex to 2 digit DECIMAL 
; for SS second (MM minute, or HH hour)
h2d2
;convert 1-byte hex number to 2 digit decimal number
	movf	hms,0		;W<--hms
	andlw	0x0F		;lower nibble
	movwf	hms0hex		;hms0hex
	movf	hms,0
	movwf	hmstemp
	swapf	hmstemp,0
	andlw	0x0F		;upper nibble
	movwf	hms1hex
;	
	clrf	hms1dec
	clrf	hms0dec
	btfss	hms1hex,0x01	;B1 check  (note: 0000 0011 is the highest)
	goto	b0check
	incf	hms1dec
	incf	hms1dec
	incf	hms1dec		;32(d)
	incf	hms0hex
	incf	hms0hex
b0check	btfss	hms1hex,0x00	;B0 check
	goto	hms0check
	incf	hms1dec		;16(d)
	incf	hms0hex
	incf	hms0hex
	incf	hms0hex
	incf	hms0hex
	incf	hms0hex	
	incf	hms0hex			
hms0check
	bcf	HILO20,0x00	
	movf	hms0hex,0		;check if it's begger than 20(d)
	call	TWENTY
	btfss	HILO20,0x00
	goto	hms0check2
	movlw	0x14
	subwf	hms0hex
	movf	hms0hex,0
	movwf	hms0dec
	incf	hms1dec
	incf	hms1dec			;two decimal digits
;	bcf	HILO20,0x00
	return
hms0check2
	bcf	HILO10,0x00
	movf	hms0hex,0		;then check >10
	call	TEN
	btfss	HILO10,0x00	
	goto	less			;less than <10
	movlw	0x0A
	subwf	hms0hex
	movf	hms0hex,0
	movwf	hms0dec
	incf	hms1dec
	return

less	movf	hms0hex,0
	movwf	hms0dec			;so keep it to ss0dec
	return


;========================================


;DELAY SUBROUTINE for 1 Second delay
;
DELAY1s  	
	banksel	count
	movlw	0x40			;Count=76 for 1 second to expire
					;later lowered to 64 to
					;accommodate LCD delays
	movwf	count

over	btfss	INTCON,	T0IF		;Tmr0 overflow?
	goto 	over
	bcf	INTCON, T0IF		;reset 
	decfsz	count
	goto	over
	return

;subroutin CLOCKDISPLAY
clockLCDdisplay
	banksel	hh1dec
	movlw	0x30
	addwf	hh1dec
	addwf	hh0dec
	addwf	mm1dec
	addwf	mm0dec
	addwf	ss1dec
	addwf	ss0dec
	movf	hh1dec,0			;A
	call	dataw4
	movf	hh0dec,0
	call	dataw4
	movlw	':'
	call	dataw4
	movf	mm1dec,0
	call	dataw4
	movf	mm0dec, 0
	call	dataw4
	movlw	':'
	call	dataw4
	movf	ss1dec,0
	call	dataw4	
	movf	ss0dec,0
	call	dataw4	
	return
;
;----------------------
;subroutine to check >=10 or <10 ==================
; >=10  ---> HILO10=1
;<10 --->HILO10=0
TEN	
	banksel	HILO10
	clrf	HILO10
	movwf	TENtemp
	btfss	TENtemp, 0x04	;4th bit
	goto	thirdbit
	bsf	HILO10, 0x00
	return
thirdbit
	btfss	TENtemp, 0x03	;3rd bit
	return
	btfss	TENtemp, 0x02
	goto	nextbit
	bsf	HILO10,0x00
	return
nextbit btfss	TENtemp,0x01
	return
	bsf	HILO10, 0x00
	return
;========================================
;subroutine to check >=20 or <10 ==================
; >=20  ---> HILO20=1
;<20 --->HILO20 =0
;20d = 0001 0100   b4& b2=1
TWENTY	
	banksel	HILO20
	clrf	HILO20
	movwf	Twentytemp
	btfss	Twentytemp, 0x04	;4th bit
	return
	btfss	Twentytemp, 0x02	;2nd bit
	goto	secondbit
	bsf	HILO20,0x00
	return
secondbit
	btfss	Twentytemp, 0x02	;2nd bit
	return
	bsf	HILO20,0x00
	return
;
;clock clear-reset subroutine 	
clear
	clrf	STATUS
	banksel	SS
	movlw	0x00	;W=0
	clrf	HH
	clrf	MM
	clrf	SS

	clrf	hh1hex
	clrf	hh0hex
	clrf	hh1dec
	clrf	hh0dec

	clrf	mm1hex
	clrf	mm0hex
	clrf	mm1dec
	clrf	mm0dec

	clrf	ss1hex
	clrf	ss0hex
	clrf	ss1dec
	clrf	ss0dec
	clrf	hms
	return
;
;high nibble only write for the first step of 4-bit set up
hnibble4	
	movwf   Temp		;Temp storage
      	movf    Temp,0      	;Now W also holds the data    
      	andlw   0xF0            ; get upper nibble
      	movwf   PORTB		   ; send data to lcd
	call	delay1ms
	bcf	PORTB, RS
	call	delay1ms
	bsf	PORTB, E
	call	delay1ms
	bcf	PORTB, E
	call	delay10ms		;end of high nibble for 4-bit setup
	return	
;	
;subroutine instw (4-bit interface instruction write)
;instruction to be written is stored in W before the call
instw4	
	movwf   Temp		;Temp storage
      	movf    Temp,0      ;Now W also holds the data    
      	andlw   0xF0            ; get upper nibble
      	movwf   PORTB		   ; send data to lcd
	call	delay1ms
	bcf	PORTB, RS
	call	delay1ms
	bsf	PORTB, E
	call	delay1ms
	bcf	PORTB, E
	call	delay10ms		;end of higher nibble
      	swapf   Temp,0		;get lower nibble to W
      	andlw   0xf0  
	movwf	PORTB			;Write to LCD          
  	call	delay1ms
	bcf	PORTB, RS
	call	delay1ms
	bsf	PORTB, E
	call	delay1ms
	bcf	PORTB, E		;end of lower nibble
	call	delay10ms	             
	return

;subroutine dataw (4-bit interface data write)

dataw4	
	movwf   Temp		;Temp storage
      	movf    Temp,0      ;Now W also holds the data    
      	andlw   0xF0            ; get upper nibble
      	movwf   PORTB		   ; send data to lcd
	call	delay1ms
	bsf	PORTB, RS
	call	delay1ms
	bsf	PORTB, E
	call	delay1ms
	bcf	PORTB, E
	call	delay10ms		;end of higher nibble
      	swapf   Temp,0		;get lower nibble to W
      	andlw   0xF0  
	movwf	PORTB			;Write to LCD          
  	call	delay1ms
	bsf	PORTB, RS
	call	delay1ms
	bsf	PORTB, E
	call	delay1ms
	bcf	PORTB, E		;end of lower nibble
	call	delay10ms	             
	return
;
;==========================================================
Delay100us
	banksel	Kount100us
	movlw	H'A4'
	movwf	Kount100us
R100us	decfsz	Kount100us
	goto	R100us
	return
;
;1ms delay
Delay1ms
	banksel	Kount1ms
	movlw	0x0A	;10
	movwf	Kount1ms
R1ms	call	delay100us
	decfsz	Kount1ms
	goto	R1ms
	return
;
;10ms delay
; call 100 times of 100 us delay  (with some time discrepancy)
Delay10ms 
	banksel	Kount10ms
	movlw	H'64'	;100
	movwf	Kount10ms
R10ms	call	delay100us
	decfsz	Kount10ms
	goto	R10ms
	return

;======================================================
	END
