• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC calculator

Hello guys I want to built a pic calculator using PIc16f877a or any Pic16f87X. Main components are a small calculator keypad and LCD(LM020L). I will be using proteus for the circuit. On the attachment I have shown the calculator keypad and LCD(LM020L) I want to use.

I am familir with assembly so I would like to know which language is suitable for this kind of a project between C, C++ and assembly
 

Attachments

birdman0_o

Active Member
Disclaimer: I have not tested the contents of this code recently, am uploading to help friend here.

Code:
;*************************************
; Author  : Mike Baird
; Program : 32 bit calculator
; Date    : June 13th, 2010
;*************************************


	List	P=16F88
	#include	"P16F88.INC"
	__CONFIG	_CONFIG1,   _PWRTE_OFF  & _WDT_OFF & _INTRC_IO & _BODEN_OFF & _LVP_OFF & _CP_OFF & _MCLR_OFF
	__CONFIG    _CONFIG2,	_IESO_OFF & _FCMEN_OFF
	errorlevel -302,-305
;*** Cblock ***

	CBLOCK	0x20		 
	Count1								; For delay!
	CountA								;
	CountB								;
	CountC
	TempLCD								; For LCD

; For all math
	InputA3
	InputA2								; For storing input keys
	InputA1
	InputA0								; 
	
	InputB3
	InputB2
	InputB1								; 							
	InputB0								; 

	REGA3						      	; 32-bit Accumulator a, lsb+3, ms-byte
	REGA2								; 32-bit Accumulator a, lsb+2
	REGA1								; 32-bit Accumulator a, lsb+1
	REGA0	 							; 32-bit Accumulator a, ls-byte

	REGB3								; 32-bit Accumulator b, lsb+3, ms-byte
	REGB2								; 32-bit Accumulator b, lsb+2
	REGB1								; 32-bit Accumulator b, lsb+1
	REGB0								; 32-bit Accumulator b, ls-byte

	REGC3								; Scracth for Remainder and Multiplication
	REGC2	
	REGC1
	REGC0

	DSIGN
	DIGIT1								; 10^9, billions
	DIGIT2								; 10^8
	DIGIT3								; 10^7
	DIGIT4								; 10^6, millions
	DIGIT5			 					; 10^5
	DIGIT6								; 10^4
	DIGIT7								; 10^3, thousands
	DIGIT8								; 10^2
	DIGIT9								; 10^1
	DIGIT10								; 10^0

	DCOUNT								; digit count
	MCOUNT	
	MTEMP

	Temp
	Operation
	ENDC

;*** Defines ***

; PORTB

#Define		Column1		PORTB,3
#Define		Column2		PORTB,2
#Define		Column3		PORTB,1
#Define		Column4		PORTB,0

#Define		Row1		PORTB,7
#Define		Row2		PORTB,6
#Define		Row3		PORTB,5
#Define		Row4		PORTB,4

LCD_Port	EQU		PORTA
RS			EQU		0x04
RW			EQU		0x06
E			EQU		0x07	

;*** START OF RAM ***
	ORG	0x000							; Start of program vector
	GOTO	Start						;
	ORG	0x004							; Interrupt vector
						
;*** Configuration ***
Start
	clrf	PORTA						; PortA all low
	clrf	PORTB						; PortB all low
	
	bsf		STATUS,RP0					; Bank 1
	movlw	b'01100000'					; Make clock 4Mhz
	iorwf	OSCCON						;
	movlw	b'00100000'					; Bit 5 input
	movwf	TRISA
	movlw	0xF0						; PortA all output except MCLR
	movwf	TRISB						; PortB half in half out
	clrf 	ANSEL						; Make PORTA all digital I/O
	bcf		STATUS,RP0					; Bank 0
	
	call	Delay100					; wait for LCD to settle
	call	LCD_Init					; Initialize LCD

;*** Main ***
	bsf		Column1						; set up columns
	bsf		Column2
	bsf		Column3
	bsf		Column4
	
Main
	movlw	.32							; 32 registers to clear	
	movwf	CountC
	movlw	InputA3
	movwf	FSR

	clrf	INDF						; Clear all registers sequentially
	incf	FSR	
	decfsz	CountC
	goto	$-3

; *** Input and Load ACa0-4 ***
	call 	Delay255
	call 	CheckKeys
	movwf	Temp
	call	LCD_Char
	movlw	.48							; Turn into 0-9 (Not ASCII)
	subwf	Temp,W
	movwf	REGA0
	movwf	InputA0

InputACa
	call 	Delay255
	call 	CheckKeys
	movwf	Temp						; Hold temporarily
	xorlw	'*'							; was operation pressed?
	btfsc	STATUS,Z
	goto	ChooseOperation				; yes it was

	movlw	.10							; multiply by 10
	movwf	REGB0						; on every other pass it will now x10
	call	multiply						; e.g. for 1 digit * X

	movf	Temp,W						; Show key
	call	LCD_Char
	movlw	.48							; Turn into 0-9 (Not ASCII)
	subwf	Temp,W
	addwf	REGA0,W
	movwf	REGA0
	movwf	InputA0	
	addcf	REGA1

	movf	REGA1,W
	movwf	InputA1
	movf	REGA2,W
	movwf	InputA2
	movf	REGA3,W
	movwf	InputA3

	goto	InputACa

;*** Input and Load ACb0-4 ***
ChooseOperation:
	call	LCD_Line2
	call 	Delay255
	call	CheckKeys
	movwf	Temp
	xorlw	'*'
	bz		RedrawFirst

	movf	Temp,w
	movwf	Operation
	movlw	.48	
	subwf	Operation,w
	call	OperationTable
	call	LCD_Char

	goto	ChooseOperation

OperationTable
	addwf	PCL
	nop		
	retlw	'+'
	retlw	'-'
	retlw	'*'
	retlw	'/'
	retlw	's'

RedrawFirst
	call	LCD_Clr
	call	LCD_Line1
	movf	InputA0,w
	movwf	REGA0
	movf	InputA1,w
	movwf	REGA1
	movf	InputA2,w
	movwf	REGA2
	movf	InputA3,w
	movwf	REGA3
	call	bin2dec

	movlw	.10
	movwf	CountC
	movlw	DIGIT1
	movwf	FSR

clearzeros
	movf	INDF,W							; Clear all leading 0's
	bnz		answerdisplay
	incf	FSR
	decf	CountC
	movf	CountC,W						; If answer is actually 0, display just one Zero
	xorlw	.1	
	btfsc	STATUS,Z
	goto	answerdisplay
	goto	clearzeros

answerdisplay:	
	movf	INDF,W		
	call	LCD_CharD
	incf	FSR								; point at next digit
	decfsz	CountC
	goto	answerdisplay

	movlw	.48	
	subwf	Operation,w
	call	OperationTable
	call	LCD_Char	

NextInput
	call 	Delay255
	call 	CheckKeys
	movwf	Temp
	call	LCD_Char
	movlw	.48							; Turn into 0-9 (Not ASCII)
	subwf	Temp,W
	movwf	REGA0
	movwf	InputB0
	clrf	REGA1
InputACb
	call 	Delay255
	call	CheckKeys
	movwf	Temp				; Hold temporarily
	xorlw	'*'					; was multiply again pressed?
	btfsc	STATUS,Z
	goto	MathTime			; yes it was, we are done getting inputs

	movlw	.10					; multiply by 10
	movwf	REGB0				; on every other pass it will now x10
	call	multiply

	movf	Temp,W				; Show key
	call	LCD_Char
	movlw	.48
	subwf	Temp,W
	addwf	REGA0,W
	movwf	REGA0
	movwf	InputB0	
	addcf	REGA1

	movf	REGA1,W
	movwf	InputB1
	movf	REGA2,W
	movwf	InputB2
	movf	REGA3,W
	movwf	InputB3
	
	goto	InputACb


;*** Perform Operation ***
MathTime
	movf	InputA0,W
	movwf	REGA0
	movf	InputA1,W
	movwf	REGA1
	movf	InputA2,W
	movwf	REGA2
	movf	InputA3,W
	movwf	REGA3

	movf	InputB0,W
	movwf	REGB0
	movf	InputB1,W
	movwf	REGB1
	movf	InputB2,W
	movwf	REGB2
	movf	InputB3,W
	movwf	REGB3

	movlw	.48
	subwf	Operation
	clrc
	rlf		Operation,w

	addwf	PCL
	nop
	nop
	call	add
	goto	DisplayResult
	call	subtract
	goto	DisplayResult
	call	multiply
	goto	DisplayResult
	call	divide
	goto	DisplayResult
	call	sqrt

;*** Display Result ***
DisplayResult
	call	bin2dec

	call	LCD_Line2						; Display answer on Line 2
	movlw	'='
	call	LCD_Char
	movlw	' ' 
	call	LCD_Char

	movlw	.1
	xorwf	DSIGN
	skpz
	goto	$+3
	movlw	'-'
	call	LCD_Char

	movlw	.10
	movwf	CountC
	movlw	DIGIT1
	movwf	FSR

ClearZeros	
	movf	INDF,W							; Clear all leading 0's
	bnz		AnswerDisplay
	incf	FSR
	decf	CountC
	movf	CountC,W						; If answer is actually 0, display just one Zero
	xorlw	.1	
	btfsc	STATUS,Z
	goto	AnswerDisplay
	goto	ClearZeros

AnswerDisplay:	
	movf	INDF,W		
	call	LCD_CharD
	incf	FSR								; point at next digit
	decfsz	CountC
	goto	AnswerDisplay

	call	Delay255	
	call	CheckKeys						;	A key press will now restart the calculator
	call	LCD_Clr
	call	LCD_Line1
	call	Delay255						; Debouncing

	goto	Main

;********************************** Math Subroutines **************************************
;{
;*** 32 BIT SIGNED SUTRACT ***
;REGA - REGB -> REGA
;Return carry set if overflow

subtract
	call	negateb		;Negate REGB
	skpnc
	return			;Overflow

;*** 32 BIT SIGNED ADD ***
;REGA + REGB -> REGA
;Return carry set if overflow

add	
	movf	REGA3,w		;Compare signs
	xorwf	REGB3,w
	movwf	MTEMP

	call	addba		;Add REGB to REGA

	clrc			;Check signs
	movf	REGB3,w		;If signs are same
	xorwf	REGA3,w		;so must result sign
	btfss	MTEMP,7		;else overflow
	addlw	0x80
	return

;*** 32 BIT SIGNED MULTIPLY ***
;REGA * REGB -> REGA
;Return carry set if overflow

multiply
	clrf	MTEMP		;Reset sign flag
	call	absa		;Make REGA positive
	skpc
	call	absb		;Make REGB positive
	skpnc
	return			;Overflow

	call	movac		;Move REGA to REGC
	call	clra		;Clear product

	movlw	D'31'		;Loop counter
	movwf	MCOUNT

muloop	
	call	slac		;Shift left product and multiplicand
	
	rlf	REGC3,w		;Test MSB of multiplicand
	skpnc			;If multiplicand bit is a 1 then
	call	addba		;add multiplier to product

	skpc			;Check for overflow
	rlf	REGA3,w
	skpnc
	return

	decfsz	MCOUNT,f	;Next
	goto	muloop

	btfsc	MTEMP,0		;Check result sign
	call	negatea		;Negative
	return


;*** 32 BIT SIGNED DIVIDE ***
;REGA / REGB -> REGA
;Remainder in REGC
;Return carry set if overflow or division by zero

divide
	clrf	MTEMP		;Reset sign flag
	movf	REGB0,w		;Trap division by zero
	iorwf	REGB1,w
	iorwf	REGB2,w
	iorwf	REGB3,w
	sublw	0
	skpc
	call	absa		;Make dividend (REGA) positive
	skpc
	call	absb		;Make divisor (REGB) positive
	skpnc
	return			;Overflow

	clrf	REGC0		;Clear remainder
	clrf	REGC1
	clrf	REGC2
	clrf	REGC3
	call	slac		;Purge sign bit

	movlw	D'31'		;Loop counter
	movwf	MCOUNT

dvloop	
	call	slac		;Shift dividend (REGA) msb into remainder (REGC)

	movf	REGB3,w		;Test if remainder (REGC) >= divisor (REGB)
	subwf	REGC3,w
	skpz
	goto	dtstgt
	movf	REGB2,w
	subwf	REGC2,w
	skpz
	goto	dtstgt
	movf	REGB1,w
	subwf	REGC1,w
	skpz
	goto	dtstgt
	movf	REGB0,w
	subwf	REGC0,w
dtstgt	
	skpc			;Carry set if remainder >= divisor
	goto	dremlt

	movf	REGB0,w		;Subtract divisor (REGB) from remainder (REGC)
	subwf	REGC0,f
	movf	REGB1,w
	skpc
	incfsz	REGB1,w
	subwf	REGC1,f
	movf	REGB2,w
	skpc
	incfsz	REGB2,w
	subwf	REGC2,f
	movf	REGB3,w
	skpc
	incfsz	REGB3,w
	subwf	REGC3,f
	clrc
	bsf	REGA0,0		;Set quotient bit

dremlt	
	decfsz	MCOUNT,f	;Next
	goto	dvloop

	btfsc	MTEMP,0		;Check result sign
	call	negatea		;Negative
	return

;*** ROUND RESULT OF DIVISION TO NEAREST INTEGER ***

round	
	clrf	MTEMP		;Reset sign flag
	call	absa		;Make positive
	clrc
	call	slc		;Multiply remainder by 2
	movf	REGB3,w		;Test if remainder (REGC) >= divisor (REGB)
	subwf	REGC3,w
	skpz
	goto	rtstgt
	movf	REGB2,w
	subwf	REGC2,w
	skpz
	goto	dtstgt
	movf	REGB1,w
	subwf	REGC1,w
	skpz
	goto	rtstgt
	movf	REGB0,w
	subwf	REGC0,w
rtstgt	
	skpc			;Carry set if remainder >= divisor
	goto	rremlt
	incfsz	REGA0,f		;Add 1 to quotient
	goto	rremlt
	incfsz	REGA1,f
	goto	rremlt
	incfsz	REGA2,f
	goto	rremlt
	incf	REGA3,f
	skpnz
	return			;Overflow,return carry set
rremlt
	btfsc	MTEMP,0		;Restore sign
	call	negatea
	return


;*** 32 BIT SQUARE ROOT ***
;sqrt(REGA) -> REGA
;Return carry set if negative

sqrt	
	rlf	REGA3,w		;Trap negative values
	skpnc
	return

	call	movac		;Move REGA to REGC
	call	clrba		;Clear remainder (REGB) and root (REGA)

	movlw	D'16'		;Loop counter
	movwf	MCOUNT

sqloop	
	rlf	REGC0,f		;Shift two msb's
	rlf	REGC1,f		;into remainder
	rlf	REGC2,f
	rlf	REGC3,f
	rlf	REGB0,f
	rlf	REGB1,f
	rlf	REGB2,f
	rlf	REGC0,f
	rlf	REGC1,f
	rlf	REGC2,f
	rlf	REGC3,f
	rlf	REGB0,f
	rlf	REGB1,f
	rlf	REGB2,f

	setc			;Add 1 to root
	rlf	REGA0,f		;Align root
	rlf	REGA1,f
	rlf	REGA2,f

	movf	REGA2,w		;Test if remdr (REGB) >= root (REGA)
	subwf	REGB2,w
	skpz
	goto	ststgt
	movf	REGA1,w
	subwf	REGB1,w
	skpz
	goto	ststgt
	movf	REGA0,w
	subwf	REGB0,w
ststgt	
	skpc			;Carry set if remdr >= root
	goto	sremlt

	movf	REGA0,w		;Subtract root (REGA) from remdr (REGB)
	subwf	REGB0,f
	movf	REGA1,w
	skpc
	incfsz	REGA1,w
	subwf	REGB1,f
	movf	REGA2,w
	skpc
	incfsz	REGA2,w
	subwf	REGB2,f
	bsf	REGA0,1		;Set current root bit

sremlt
	bcf	REGA0,0		;Clear test bit
	decfsz	MCOUNT,f	;Next
	goto	sqloop

	clrc
	rrf	REGA2,f		;Adjust root alignment
	rrf	REGA1,f
	rrf	REGA0,f
	return


;*** 32 BIT SIGNED BINARY TO DECIMAL ***
;REGA -> DIGITS 1 (MSD) TO 10 (LSD) & DSIGN
;DSIGN = 0 if REGA is positive, 1 if negative
;Return carry set if overflow
;Uses FSR register

bin2dec	
	clrf	MTEMP		;Reset sign flag
	call	absa		;Make REGA positive
	skpnc
	return			;Overflow

	call	clrdig		;Clear all digits

	movlw	D'32'		;Loop counter
	movwf	MCOUNT

b2dloop	
	rlf	REGA0,f		;Shift msb into carry
	rlf	REGA1,f
	rlf	REGA2,f
	rlf	REGA3,f

	movlw	DIGIT10
	movwf	FSR		;Pointer to digits
	movlw	D'10'		;10 digits to do
	movwf	DCOUNT

adjlp	
	rlf	INDF,f		;Shift digit and carry 1 bit left
	movlw	D'10'
	subwf	INDF,w		;Check and adjust for decimal overflow
	skpnc
	movwf	INDF

	decf	FSR,f		;Next digit
	decfsz	DCOUNT,f
	goto	adjlp

	decfsz	MCOUNT,f	;Next bit
	goto	b2dloop

	btfsc	MTEMP,0		;Check sign
	bsf	DSIGN,0		;Negative
	clrc
	return


;*** 32 BIT SIGNED DECIMAL TO BINARY ***
;Decimal DIGIT1 thro DIGIT(X) & DSIGN -> REGA
;Set DSIGN = 0 for positive, DSIGN = 1 for negative values
;Most significant digit in DIGIT1
;Enter this routine with digit count in w register
;Return carry set if overflow
;Uses FSR register

dec2bin	
	movwf	MTEMP		;Save digit count

	movlw	D'32'		;Outer bit loop counter
	movwf	MCOUNT

d2blp1
	movlw	DIGIT1-1	;Set up pointer to MSD
	movwf	FSR
	movf	MTEMP,w		;Inner digit loop counter
	movwf	DCOUNT

	movlw	D'10'
	clrc			;Bring in '0' bit into MSD

d2blp2
	incf	FSR,f
	skpnc
	addwf	INDF,f		;Add 10 if '1' bit from prev digit
	rrf	INDF,f		;Shift out LSB of digit

	decfsz	DCOUNT,f	;Next L.S. Digit
	goto	d2blp2

	rrf	REGA3,f		;Shift in carry from digits
	rrf	REGA2,f
	rrf	REGA1,f
	rrf	REGA0,f

	decfsz	MCOUNT,f	;Next bit
	goto	d2blp1

	movf	INDF,w		;Check for overflow
	addlw	0xFF
	skpc
	rlf	REGA3,w
	skpnc
	return

	btfsc	DSIGN,0		;Check result sign
	call	negatea		;Negative
	return


;UTILITY ROUTINES


;Add REGB to REGA (Unsigned)
;Used by add, multiply,

addba
	movf	REGB0,w		;Add lo byte
	addwf	REGA0,f

	movf	REGB1,w		;Add mid-lo byte
	skpnc			;No carry_in, so just add
	incfsz	REGB1,w		;Add carry_in to REGB
	addwf	REGA1,f		;Add and propagate carry_out

	movf	REGB2,w		;Add mid-hi byte
	skpnc
	incfsz	REGB2,w
	addwf	REGA2,f

	movf	REGB3,w		;Add hi byte
	skpnc
	incfsz	REGB3,w
	addwf	REGA3,f
	return


;Move REGA to REGC
;Used by multiply, sqrt

movac
	movf	REGA0,w
	movwf	REGC0
	movf	REGA1,w
	movwf	REGC1
	movf	REGA2,w
	movwf	REGC2
	movf	REGA3,w
	movwf	REGC3
	return

;Clear REGB and REGA
;Used by sqrt

clrba	
	clrf	REGB0
	clrf	REGB1
	clrf	REGB2
	clrf	REGB3

;Clear REGA
;Used by multiply, sqrt

clra
	clrf	REGA0
	clrf	REGA1
	clrf	REGA2
	clrf	REGA3
	return

;Check sign of REGA and convert negative to positive
;Used by multiply, divide, bin2dec, round

absa	
	rlf	REGA3,w
	skpc
	return			;Positive

;Negate REGA
;Used by absa, multiply, divide, bin2dec, dec2bin, round

negatea	
	movf	REGA3,w		;Save sign in w
	andlw	0x80

	comf	REGA0,f		;2's complement
	comf	REGA1,f
	comf	REGA2,f
	comf	REGA3,f
	incfsz	REGA0,f
	goto	nega1
	incfsz	REGA1,f
	goto	nega1
	incfsz	REGA2,f
	goto	nega1
	incf	REGA3,f
nega1
	incf	MTEMP,f		;flip sign flag
	addwf	REGA3,w		;Return carry set if -2147483648
	return


;Check sign of REGB and convert negative to positive
;Used by multiply, divide

absb	
	rlf	REGB3,w
	skpc
	return			;Positive

;Negate REGB
;Used by absb, subtract, multiply, divide

negateb	
	movf	REGB3,w		;Save sign in w
	andlw	0x80

	comf	REGB0,f		;2's complement
	comf	REGB1,f
	comf	REGB2,f
	comf	REGB3,f
	incfsz	REGB0,f
	goto	negb1
	incfsz	REGB1,f
	goto	negb1
	incfsz	REGB2,f
	goto	negb1
	incf	REGB3,f
negb1
	incf	MTEMP,f		;flip sign flag
	addwf	REGB3,w		;Return carry set if -2147483648
	return


;Shift left REGA and REGC
;Used by multiply, divide, round

slac	
	rlf	REGA0,f
	rlf	REGA1,f
	rlf	REGA2,f
	rlf	REGA3,f
slc	rlf	REGC0,f
	rlf	REGC1,f
	rlf	REGC2,f
	rlf	REGC3,f
	return

;Set all digits to 0
;Used by bin2dec

clrdig	
	clrf	DSIGN
	clrf	DIGIT1
	clrf	DIGIT2
	clrf	DIGIT3
	clrf	DIGIT4
	clrf	DIGIT5
	clrf	DIGIT6
	clrf	DIGIT7
	clrf	DIGIT8
	clrf	DIGIT9
	clrf	DIGIT10
	return
;}
;*** Keypad Subroutine ***
;{
CheckKeys
	bsf		Column1	
	bcf		Column4

	btfss	Row1						; Yes, check rows
	retlw	'A'							; if row is off, store 2 in work reg
	btfss	Row2						; Check which row was pressed and fill Temp with appropriate value
	retlw	'B'							;
	btfss	Row3						;
	retlw	'C'							;
	btfss	Row4						;
	retlw	'D'							;

COLUMN3	
	bsf		Column4	
	bcf		Column3

	btfss	Row1						; Yes, check rows
	retlw	'3'							; if row is off, store 2 in work reg
	btfss	Row2						; Check which row was pressed and fill Temp with appropriate value
	retlw	'6'						
	btfss	Row3						;
	retlw	'9'							;
	btfss	Row4						;
	retlw	'#'							;
	
COLUMN2
	bsf		Column3	
	bcf		Column2

	btfss	Row1						;
	retlw	'2'							;
	btfss	Row2						;
	retlw	'5'							;
	btfss	Row3						; 
	retlw	'8'							;
	btfss	Row4						;
	retlw	'0'							;

COLUMN1
	bsf		Column2
	bcf		Column1

	btfss	Row1						;
	retlw	'1'	
	btfss	Row2						;
	retlw	'4'							;
	btfss	Row3						;
	retlw	'7'							;
	btfss	Row4						;
	retlw	'*'

	goto	CheckKeys
;}
;*** LCD routines ***
;{
LCD_Init	
	movlw	0x20						; Set to 4 bit mode
	call	LCD_Cmd						;
	movlw	0x28						; Set display shift to 1
	call	LCD_Cmd						;
	movlw	0x06						; Set display move right after character sent
	call	LCD_Cmd						;
	movlw	0x0D						; Set display on, don't underline cursor but flash it
	call	LCD_Cmd						;
	call	LCD_Clr						; Clear display
	call	LCD_CurOff
	return

LCD_Cmd		
	movwf	TempLCD
	swapf	TempLCD,W					; Send upper nibble
	andlw	0x0F						; Clear upper 4 bits of W (Not to interfere with RS,RW and E)
	movwf	LCD_Port
	bcf		LCD_Port,RS					; RS line to 0		
	bsf		LCD_Port,E					; Pulse the E line high
	nop
	bcf		LCD_Port,E

	movf	TempLCD,W					; Send lower nibble
	andlw	0x0F						; Clear upper 4 bits of W
	movwf	LCD_Port
	bcf		LCD_Port,RS					; RS line to 0
	bsf		LCD_Port,E					; Pulse the E line high
	nop
	bcf		LCD_Port,E

	call 	Delay5
	return

LCD_CharD
	addlw	0x30						; Convert W to ASCII
LCD_Char
	movwf	TempLCD						;
	swapf	TempLCD,W					; Send upper nibble
	andlw	0x0F						; Clear upper 4 bits of W
	movwf	LCD_Port					;
	bsf		LCD_Port,RS					; RS line to 1
	bsf		LCD_Port,E					; Pulse the E line high
	nop
	bcf		LCD_Port,E

	movf	TempLCD,W					; Send lower nibble
	andlw	0x0F						; Clear upper 4 bits of W
	movwf	LCD_Port		
	bsf		LCD_Port,RS					; RS line to 1
	bsf		LCD_Port,E					; Pulse the E line high
	nop
	bcf		LCD_Port,E
	call 	Delay5
	return

LCD_Line1
	movlw	0x80						; Move to 1st row, first column
	call	LCD_Cmd
	return

LCD_Line2
	movlw	0xC0						; Move to 2nd row, first column
	call	LCD_Cmd
	return

LCD_Line1W
	addlw	0x80						; Move to 1st row, column W
	call	LCD_Cmd
	return

LCD_Line2W
	addlw	0xC0						; Move to 2nd row, column W
	call	LCD_Cmd
	return

LCD_CurOn
	movlw	0x0D						; Set display on/off and cursor command
	call	LCD_Cmd
	return

LCD_CurOff
	movlw	0x0C						; Set display on/off and cursor command
	call	LCD_Cmd
	return

LCD_Clr
	movlw	0x01						; Clear display
	call	LCD_Cmd
	return
;}
;*** Delay Routines ***
;{
Delay255
	movlw	d'255'						; Delay 255 mS
	goto	d0
Delay100	
	movlw	d'100'						; Delay 100mS
	goto	d0
Delay50	
	movlw	d'50'						; Delay 50mS
	goto	d0
Delay20
	movlw	d'20'						; Delay 20mS
	goto	d0	
Delay5		
	movlw	d'5'						; Delay 5.000 ms (4 MHz clock)
d0	
	movwf	Count1
d1
	movlw	0xC7						; Delay 1mS
	movwf	CountA
	movlw	0x01
	movwf	CountB
Delay_0
	decfsz	CountA,F
	goto	$+2
	decfsz	CountB,F
	goto	Delay_0
	decfsz	Count1,F
	goto	d1
	return
;}
;*** End ***

	END
 
Hi birdman_0,
I thought my project would be easier if I break it into 2 parts and I would like to start with the first part. I want to connect LCD to pic16f877a and then display the massege (Hello) on the LCD. I have already done that but there is no message displayed on the LCD. I dont know where the problem is. Here is my code
Code:
 list		p=16f877A	; list directive to define processor
	#include	<p16f877A.inc>	; processor specific variable definitions
	
	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _RC_OSC & _WRT_OFF & _LVP_ON & _CPD_OFF

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.


;***** VARIABLE DEFINITIONS
w_temp		EQU	0x7D		; variable used for context saving 
status_temp	EQU	0x7E		; variable used for context saving
pclath_temp	EQU	0x7F		; variable used for context saving			

 
  cblock	0x20
            count            ;used in loops
            count1			;used in delay routine
            counta			;used in delay routine
            countb			;used in delay routine

            templcd ;temp store for 4 bit mode
  endc 




;**********************************************************************
	ORG     0x000             ; processor reset vector

	nop			  ; nop required for icd
  	goto    Start             ; go to beginning of program


	ORG     0x004             ; interrupt vector location

	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	movwf	status_temp       ; save off contents of STATUS register
	movf	PCLATH,w	  ; move pclath register into w register
	movwf	pclath_temp	  ; save off contents of PCLATH register

; isr code can go here or be located as a call subroutine elsewhere

	movf	pclath_temp,w	  ; retrieve copy of PCLATH register
	movwf	PCLATH		  ; restore pre-isr PCLATH register contents
	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt


	

	
;Subroutines:

Init 
        clrw                    ; Zero.
        movwf   PORTB	    	;resets input/output ports
        bsf     STATUS,RP0      ; Select Bank 1
        movlw   b'00000000'    ; Set port B bits 0-3 as outputs b0-b3 connected to lcd  d4-d7 pins
                                ;and b5-b7 connected to RS,RW,E         
        movwf   TRISB        ; Set TRISB register 
        bcf     STATUS,RP0      ; Select Bank 0 
        call	Delay100		;wait for LCD to settle

        retlw 0
	
LCD_Init	
        movlw	0x20			;Set 4 bit mode
		call	LCD_Cmd

        movlw	0x28			;Set display shift
		call	LCD_Cmd

		movlw	0x06			;Set display character mode
		call	LCD_Cmd

		movlw	0x0d			;Set display on/off and cursor command
		call	LCD_Cmd

		call	LCD_Clr			;clear display

		retlw	0x00


LCD_Cmd		
        movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	PORTB
		bcf	    PORTB,6	;RS line to 0
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	PORTB
		bcf	    PORTB,6	;RS line to 0
		call	Pulse_e			;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_Char
     	movwf	templcd
		swapf	templcd,w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	PORTB
		bsf	    PORTB,6  	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	PORTB
		bsf	    PORTB,6  	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_Clr		
        movlw	0x01			;Clear display
		call	LCD_Cmd
		retlw	0x00

Delay255	
             movlw	0xff		;delay 255 mS
		goto	d0
Delay100
    	movlw	d'100'		;delay 100mS
		goto	d0
Delay50
	movlw	d'50'		;delay 50mS
		goto	d0
Delay20	
    	movlw	d'20'		;delay 20mS
		goto	d0
Delay5
	movlw	0x05		;delay 5.000 ms (4 MHz clock)
d0	movwf	count1
d1	movlw	0xC7			;delay 1mS
	movwf	counta
	movlw	0x01
	movwf	countb
Delay_0
		decfsz	counta, f
		goto	$+2
		decfsz	countb, f
		goto	Delay_0

		decfsz	count1	,f
		goto	d1
		retlw	0x00

Text
		addwf	PCL, f
		retlw	'H'
		retlw	'e'
		retlw	'l'
		retlw	'l'
		retlw	'o'
		retlw	0x00

Pulse_e		
        bsf	PORTB,7
		nop
		bcf	PORTB,7
		retlw	0x00




EndMessage	
		
Stop		goto	Stop			;endless loop




;Program Start:

Start
	call Init

Main
         clrf count   ;set counter register to zero
message
        movf	count, w		;put counter value in W
        call	Text			;get a character from the text table
        xorlw 0x00  ;is it a zero?
        btfsc STATUS,Z
        goto EndMessage
        call	LCD_Char
        incf  count, f
        goto message


        END

and on the attachment is my circuit diagram, lcd hex file and lcd design.
 

Attachments

Nigel Goodwin

Super Moderator
Most Helpful Member
As you don't have a contrast control it may well be working, but you can't see it - add a contrast control - as a minimum it will let you adjust it until it displays a single row of squares, this shows the LCD is functioning, but not been initialised.
 
As you don't have a contrast control it may well be working, but you can't see it - add a contrast control - as a minimum it will let you adjust it until it displays a single row of squares, this shows the LCD is functioning, but not been initialised
I have included contrast control (you can look at the circuit on the attachment) and adjusted it, but still the is no dispaly on the LCD, I would be glad if you can paste the circuit diagram of PIC Tutorial Three - LCD Modules
(Tutorial 3.1 ) I think it would be helpful since it will make me realise my problem, because I copied some of the routines from Tutorial 3.1.

Not sure if it matters for the SIM but you dont have an oscillator connected?
I have connected the crystal oscillator as shown in the circuit diagram on the attachment and I have also changed the configuration bits
to __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_ON & _CPD_OFF
still there is no display. Would you please paste your circuit diagram for pic calculator so I can see how you connected lcd to your microcontroller, I am
sure there is something wrong with my circuit
 

Attachments

Last edited:

Nigel Goodwin

Super Moderator
Most Helpful Member
I have included contrast control (you can look at the circuit on the attachment) and adjusted it, but still the is no dispaly on the LCD, I would be glad if you can paste the circuit diagram of PIC Tutorial Three - LCD Modules
(Tutorial 3.1 ) I think it would be helpful since it will make me realise my problem, because I copied some of the routines from Tutorial 3.1.
All the circuits are on the tutorial site, under Hardware.
 

MrAl

Well-Known Member
Most Helpful Member
Hello there,

Not to bust in on this topic but it reminded me of something somebody suggested i design. That is, a PIC calculator *with* a multimeter, all in one package. That suggestion came because the individual thought it would be a good idea to be able to make measurements with the 'meter' part and use the calculator part to figure Ohm's Law when needed. Sounds like a decent idea right?
So it would be a multimeter with a built in sci calculator.
 
Last edited:
All the circuits are on the tutorial site, under Hardware.
I constructed the circuit similar to that of PIC Tutorial - LCD Board
shown on the attachment But I have used pic16F628A because proteus I am using does not have PIC16F628 and loaded the code for Tutorial 3.1. But there is no display, may be the circuit I constracted does not match with the one of LCD Board. Could you please correct the circuit for me so that it looks exactly the same with the one on LCD Board.

Again
Code:
LCD_PORT	Equ	PORTA
LCD_TRIS	Equ	TRISA
LCD_RS		Equ	0x04			;LCD handshake lines
LCD_RW		Equ	0x06
LCD_E		Equ	0x07
I can see that LCD_PORT represent PORTA or is equivalent to it and LCD_TRIS is equivalent TRISA. I am confused with LCD_RS, LCD_RW and LCD_E. I interpreted it like this LCD_RS is equivalent to FSR because of the address 04 on DATA MEMORY MAP of PIC16F628 and LCD_RW is equivalent to PORTB because of address 06. Could you please expalain those 3 commands

the circuit and the hex file are on the attachment
 

Attachments

birdman0_o

Active Member
Those are EQU(AL) to 4,5,6. The pins 4 5 and 6. These are used in conjunction with LCD on PORTA. They tell the LCD if you are sending a data command, drawing a character or reading a character. The LCD is being used in 4 bit mode, the bottom 4 bits of PORTA are being used for this.
 

MrAl

Well-Known Member
Most Helpful Member
If you can measure V, A and ohms, why would you need a calculator?
Hello,

Same reason you might need one during various electrical tests when it isnt attached to the meter itself.
 

MrAl

Well-Known Member
Most Helpful Member
Hello again,


Oh ok cool. Would be nice to see some pics (pictures) when you get a chance too.
 
Hello guys can any one built a circuit on proteus of a LCD (16x2) that displays message HELLO, please use assembly language and any of PIC16F87x. The
reason is, I have been doing it for days and nights and I could not get it correct. May be from your circuit and your coe I can be able to see where I was getting it wrong. you can look at my earlier post and see my circuit and the code.
 

Latest threads

EE World Online Articles

Loading

 
Top