LIST P=PIC16F84 ; ; LCDLEN EQU 0x000F ;LCD first line length set at {lcdlen} 07h for 1*16 char disp ;0Fh for 2*16 char disp DSPLEN EQU 0x001F ;LCD length set at {dsplen} 0Fh for 1*16 01Fh for 2*16 ; RAM Page 0 Registers ; INDF EQU 0x0000 TMR0 EQU 0x0001 PCL EQU 0x0002 STATUS EQU 0x0003 FSR EQU 0x0004 PORTA EQU 0x0005 PORTB EQU 0x0006 EEDATA EQU 0x0008 EEADR EQU 0x0009 PCLATH EQU 0x000A INTCON EQU 0x000B ; ; RAM Page 1 Registers ; OPTION_REG EQU 0x0081 TRISA EQU 0x0085 TRISB EQU 0x0086 EECON1 EQU 0x0088 EECON2 EQU 0x0089 ; ; STATUS bits ; C EQU 00h DC EQU 01h Z EQU 02h PD EQU 03h TO EQU 04h RP0 EQU 05h RP1 EQU 06h IRP EQU 07h ; ; INTCON bits ; RBIF EQU 00h INTF EQU 01h T0IF EQU 02h RBIE EQU 03h INTE EQU 04h T0IE EQU 05h EEIE EQU 06h GIE EQU 07h ; ; OPTION_REG bits ; PS0 EQU 00h PS1 EQU 01h PS2 EQU 02h PSA EQU 03h T0SE EQU 04h T0CS EQU 05h INTEDG EQU 06h RBPU EQU 07h ; ; EECON1 bits ; RD EQU 00h WR EQU 01h WREN EQU 02h WRERR EQU 03h EEIF EQU 04h ; ; SPCE EQU 0Ch ;Space insert Timer - cleared when DAV =1 PBAFLAG EQU 0Dh ;Push button Flags ;D0 PBA Flag ;D1 PBA debounce Flag ;D2 ;D3 ;D4 ;D5 ;D6 PBD Flag ;D7 PBD debounce Flag PBATIM EQU 00Eh ;PBA Timer for debounce and Autorepeat PBBTIM EQU 00Fh ;PBB Timer -- Not used in this code PBCTIM EQU 010h ;PBC Timer -- Not used in this code PBDTIM EQU 011h ;PBD Timer for debounce and Autorepeat TICK EQU 012h ;Tick counter used for Timing DSPPNTR EQU 013h ;Display Pointer points to the current Display Starting point DATPNTR EQU 0x14 ;Data Pointer points to the next available memory Location XREG EQU 0x15 ;General purpose Register YREG EQU 0x16 ;General purpose Register WREGINT EQU 0x17 ;Working register storage during interrupts SREGINT EQU 0x18 ;Status register storage during interrupts FLAGA EQU 0x19 ;General Flags used by the program ;D0 Rotate - indicates the buffer has rotated ;D1 DAV - DAV from the 145436 has been processed ;D2 Hold Flag ;D3 ;D4 ;D5 ;D6 ;D7 FLAGTMP EQU 0x1A ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Buffer data BUFSTRT EQU 0x1C ;Buffer Start location BUFLEN EQU 0x34 ;Buffer Length BUFEND EQU 0x4F ;Buffer end BUFFEND1 EQU 0x50 ;Buffer end +1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ORG 0000h ; GOTO INIT ;Jump past Interrupt ; NOP NOP NOP GOTO INTHAN ;Interrupt Handler ; INIT ;Initialise CLRF PORTA ; PORTA CLRF PORTB ; PORTB BSF STATUS,RP0 ;Switch bank MOVLW 0x02 MOVWF PORTA ;TRISA MOVLW 0xFF MOVWF PORTB ;TRISB MOVLW 0xA0 MOVWF INTCON ;Set up Interrupt control Register MOVLW 0x81 ;Set up option register - assign 1:4 prescaler MOVWF TMR0 ;to timer 0, int from clock b, pullups disabled BCF STATUS,RP0 ; go back to page 0 CLRF DSPPNTR MOVLW PBBTIM ADDWF TICK,w MOVWF XREG ;LCD initialise Routine - 8 bit operation with Auto increment LCDINIT MOVF XREG,w SUBWF 0x12,w BTFSS STATUS,Z ;wait for 12 ticks - give LCD time to Initialise GOTO LCDINIT ;After Power up ; MOVLW 0x30 CALL WRLCD ;Write 030h to LCD ; CALL DELAY ; CALL DELAY ; CALL DELAY ; MOVLW 0x30 CALL WRLCD ;Write 030h to LCD ; CALL DELAY ; MOVLW 0x30 ;Wriet 030h to LCD CALL WRLCD ; CALL DELAY ; MOVLW 0x38 ;Write 038h to LCD CALL WRLCD ; CALL DELAY ; MOVLW 0x01 CALL WRLCD ;Write 01h to LCD ; CALL DELAY ; MOVLW 0x0C CALL WRLCD ;Write 0ch to LCD ; CALL DELAY ; MOVLW 0x06 ;Write 06h to LCD CALL WRLCD ; CALL DELAY ; MOVLW 0x1C ;Write 01Ch to LCD MOVWF FSR BANNER ;LCD should now be initialised CLRF INDF INCF FSR,f MOVF FSR,w SUBLW 0x50 BTFSS STATUS,Z GOTO BANNER ;Short Delay ; MOVLW 0x44 ;D CALL WRBUFF ; MOVLW 0x54 ;T CALL WRBUFF ; MOVLW 0x4D ;M CALL WRBUFF ; MOVLW 0x46 ;F CALL WRBUFF ; MOVLW 0x20 ;space CALL WRBUFF ; MOVLW 0x44 ;D CALL WRBUFF ; MOVLW 0x65 ;E CALL WRBUFF ; MOVLW 0x63 ;C CALL WRBUFF ; MOVLW 0x6F ;O CALL WRBUFF ; MOVLW 0x64 ;D CALL WRBUFF ; MOVLW 0x65 ;E CALL WRBUFF ; MOVLW 0x20 ;space CALL WRBUFF ; MOVLW 0x56 ;V CALL WRBUFF ; MOVLW 0x2D ;- CALL WRBUFF ; MOVLW 0x31 ;1 CALL WRBUFF ; MOVLW 0x41 ;A CALL WRBUFF ; CALL DISPLAY ;Display contents of Buffer ; CLRF FLAGA ;Clear Flags CLRF DSPPNTR ;Clear Pointers CLRF DATPNTR MOVLW 0x20 ;Insert Space CALL WRBUFF ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; START ;Start Program core CALL INPUTB ;Ensure data bus HIz ; BCF PORTA,4 ;Deselect LCD BSF PORTA,0 ;select P.B and 145436 BTFSS PORTA,1 ;check DAV from 145436 GOTO NODAV ;If no DAV ; CLRF SPCE ;Clear Space Counter BSF FLAGA,3 ;Set Space Flag BTFSC FLAGA,1 ;Check if DAV already serviced GOTO PBA ;If DAV already serviced BSF FLAGA,1 ;set DAV service flag SWAPF PORTB,w ;read data from 145436 CALL ASCII ;Call ASCII translation routine CALL WRBUFF ;Write result to buffer BTFSC FLAGA,4 ;check flag GOTO EOB ;if set ; MOVF DSPPNTR,w ;check if data pointer has reached SUBWF DATPNTR,w ;the end of the buffer SUBLW 0x11 BTFSS STATUS,Z GOTO UPDD ;If not ; BSF FLAGA,4 ;If so set the flag EOB BTFSS FLAGA,2 ;check FLAG,2 CALL DISPINC ;increment the display pointer ; UPDD CALL DISPLAY ;Update display GOTO PBA NODAV BCF FLAGA,1 ;ensure DAV flag is clear ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PBA ;BACK Space button CALL INPUTB ;Set data bus to HIz ; MOVLW 0x01 ;enable PB buffer and 145436 MOVWF PORTA BTFSS PORTB,0 ;Check if PBA pressed GOTO PBAdbce ;if not pressed BTFSC PBAFLAG,1 ;check PBA debounce flag GOTO PBB ;If set BTFSC PBAFLAG,0 ;check PBA flag GOTO PBAauto ;if set BSF PBAFLAG,0 ;set PBA flag MOVLW 0xFF ;load PBA autorepeat timer MOVWF PBATIM ;with 0FFh CALL DISPDEC ;scroll back 1 Character CALL DISPLAY ;Then update Display GOTO PBB ;Goto PB B ; PBAauto MOVF PBATIM,f ;Check if Autorepeat Timer BTFSS STATUS,Z ;has timed out GOTO PBB ;If not MOVLW 0x5F ;Reload MOVWF PBATIM ;Autorepeat Timer CALL DISPDEC ;Go back 1 character CALL DISPLAY ;Update Display GOTO PBB ;Process next key ; PBAdbce ;PBA Debounce BTFSS PBAFLAG,0 ;check PBA flag GOTO PBB ;If not set MOVLW 0x0A ;load debounce timer MOVWF PBATIM BCF PBAFLAG,0 ;Clear PBA flag BSF PBAFLAG,1 ;Set debounce timer PBB ;HOLD button CALL INPUTB ;Set data bus to HIz ; MOVLW 0x01 ;enable PB buffer and 145436 MOVWF PORTA BTFSS PORTB,1 ;Check if PBB pressed GOTO PBBCLR ;If not pressed ; BSF FLAGA,2 ;set hold (PBB) flag GOTO PBC ;then goto ; PBBCLR BCF FLAGA,2 PBC ;CLEAR button CALL INPUTB ;data bus to HIz ; MOVLW 0x01 ;Read PB buffer and 145436 MOVWF PORTA BTFSC PORTB,2 ;Check if PBC pressed GOTO CLRBUF ;If pressed PBD ;FORWARD button CALL INPUTB ; MOVLW 0x01 ;Read PB buffer and 145436 MOVWF PORTA BTFSS PORTB,3 ;check PBD GOTO PBDdbnce ;If not pressed BTFSC PBAFLAG,7 ;Check PBD Debounce flag GOTO PBDend ;If set ; BTFSC PBAFLAG,6 ;check PBD flag GOTO PBDauto ;If set ; BSF PBAFLAG,6 ;Set PBD flag MOVLW 0xFF ;Load autorepeat Timer MOVWF PBDTIM ; CALL DISPINC ;Move display one step forward CALL DISPLAY ;Update Display GOTO PBDend PBDauto MOVF PBDTIM,f ;check Autorepeat Timer BTFSS STATUS,Z GOTO PBDend ;If not zero ; MOVLW 0x5F MOVWF PBDTIM CALL DISPINC ; CALL DISPLAY ; GOTO PBDend ; PBDdbnce BTFSS PBAFLAG,6 ;Check PBD flag GOTO PBDend ;If not set MOVLW 0x0A ;Load PBD debounce timer MOVWF PBDTIM BCF PBAFLAG,6 ;clear PBD flag BSF PBAFLAG,7 ;Set PBD debounce flag PBDend GOTO START ;end of core code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Clears Buffer then clears Display ;Calls WRBUFF,DISPLAY ;Uses DSPPNTR,DATPNTR,FLAGA CLRBUF CLRF FLAGA ;Clear Flags CLRF DSPPNTR ;and Display Pointer CLRF DATPNTR ;and Data Pointer MOVLW 0x20 CALL WRBUFF ;Write blank into Data location ; CALL DISPLAY ;And update (clear) the Display ; GOTO START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Interrupt Handler ;Calls DISPINC,WRBUFF, ;Uses WREGINT,SREGINT,TICK,PBATIM,PBBTIM,PBCTIM,PBDTIM,PBAFLAG,FLAGA,SPCE INTHAN MOVWF WREGINT ;Save W register SWAPF STATUS,w ;stash Ststus in W BCF STATUS,RP0 ;change Pages MOVWF SREGINT ;Stash Status (from W) into SREGINT MOVLW 0xE8 MOVWF TMR0 ;Reload Timer BCF INTCON,T0IF ;Re enable Interrupt INCF TICK,f ;Increment the Tick Register BTFSS TICK,0 ;check if bits 0 and 1 of the Tick BTFSC TICK,1 ;counter are clear (ie every 4th Interrupt) GOTO EXINT ;if not DECF PBATIM,f ;Decrement PBA Timer BTFSC STATUS,Z BCF PBAFLAG,1 ;If PBATIM=0 clear the debounce bit DECF PBBTIM,f ;Decrement PBB Timer BTFSC STATUS,Z BCF PBAFLAG,3 ;Clear PBB Debounce bit if 0 DECF PBCTIM,f ;Decrement PBC Timer BTFSC STATUS,Z BCF PBAFLAG,5 ;Clear PBC Debounce bit if zero DECF PBDTIM,f ;Decrement PBD timer BTFSC STATUS,Z BCF PBAFLAG,7 ;clear PBD Debounce bit if zero BTFSC TICK,2 ;ie Every Eigth interrupt GOTO EXINT ; BTFSS FLAGA,3 GOTO EXINT DECF SPCE,f BTFSS STATUS,Z GOTO EXINT BCF FLAGA,3 MOVLW 0x20 CALL WRBUFF BTFSS FLAGA,2 CALL DISPINC EXINT SWAPF SREGINT,w MOVWF STATUS SWAPF WREGINT,f SWAPF WREGINT,w RETFIE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Delay routine - waits for 1-2 'Ticks' - note changes Tick counter ;Calls nil ;Uses TICK DELAY MOVLW 0xFE MOVWF TICK ;Load Tick counter with 0FEh DEL1 MOVF TICK,f BTFSS STATUS,Z ;Check if Tick counter =0 GOTO DEL1 ;If not loop back ; RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Write data to Buffer - update display and data pointers ;Calls DISPINC ;Uses XREG,DATPNTR,BUFSTRT,FLAGA,DSPPNTR WRBUFF MOVWF XREG MOVF DATPNTR,w ;Load the Data pointer ADDLW BUFSTRT ;and add the memory offset MOVWF FSR ;Move the result to the FSR MOVF XREG,w ;Move Data to the W register MOVWF INDF ;then write it to the INDF register INCF DATPNTR,f ;Increment the data pointer MOVLW BUFLEN ;load the buffer length SUBWF DATPNTR,w ;subtract from the data pointer BTFSS STATUS,Z ;check if 0 (ie end of buffer GOTO ad0128 ;if not CLRF DATPNTR ;clear the Data pointer (rotate the buffer) BSF FLAGA,0 ;Set the Rotate flag ad0128 MOVF DSPPNTR,w ; SUBWF DATPNTR,w ;check if the Data pointer and the Display BTFSS STATUS,Z ;pointer are the same GOTO ad012E ;If not CALL DISPINC ;If so Increment the Display pointer BSF FLAGA,2 ;and Set the ~~ Flag ad012E RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Increments the Display Pointer ;Calls Nils ;Uses DATPNTR,DSPPNTR,FLAGA DISPINC DECF DATPNTR,w SUBWF DSPPNTR,w ;Compare DATPNTR-1 with DSPPNTR BTFSC STATUS,Z RETURN ;If equal (end of Display) INCF DSPPNTR,f ;Increment Display Pointer MOVLW BUFLEN ;Check if the Display buffer needs to SUBWF DSPPNTR,w ;Rotate BTFSS STATUS,Z RETURN ;If not Return MOVF DATPNTR,f BTFSS STATUS,Z ;Check if Data Pointer is Zero GOTO DISPROT ;If not DECF DSPPNTR,f ;If so back off the display pointer RETURN ;And return DISPROT CLRF DSPPNTR ;Rotate the Display pointer RETURN ;And return ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ;Calls :Nil ;Uses ;DSPPNTR,DATPNTR,FLAGA DISPDEC MOVF DSPPNTR,f ;Load the Display pointer BTFSS STATUS,Z ;check if zero GOTO BACK1 ;If not BTFSS FLAGA,0 ;Check rotate Flag RETURN ;If the buffer has not rotated ; MOVF DATPNTR,w ;Load the Data pointer SUBLW BUFLEN ;check if it is at the end of the BTFSC STATUS,Z ;buffer RETURN ;If so (Display pointer cannot = datapointer) ; MOVLW BUFLEN ;If not rotate the Display pointer MOVWF DSPPNTR RETURN ;Then Return BACK1 INCF DATPNTR,w ;Check if Datapointer = Display pointer-1 SUBWF DSPPNTR,w BTFSC STATUS,Z ;If so do not allow the Display pointer to equal RETURN ;the data pointer ; DECF DSPPNTR,f ;Decrement the Display pointer and Return RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;sets the data bus to high impedance ;Calls Nil ;Uses Nil INPUTB BSF STATUS,RP0 ;change to page 1 MOVLW 0xFF ;set all the bits for TRISB MOVWF PORTB ; BCF STATUS,RP0 ;Return to page 0 RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Outputs Data to the Data bus ;Calls Nil ;Uses Nil OUTPUT BSF STATUS,RP0 ;go to page 1 CLRF PORTB ;clear all the TRISB bits BCF STATUS,RP0 ;go back to page 0 RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Hex to ASCII Translational Routine - Translates lower nibble in W register ;into an ASCII Value in the W register according to the results from the ;DTMF decoder ;Calls Nil ;Uses XREG ASCII ANDLW 00Fh MOVWF XREG MOVF XREG,f BTFSC STATUS,Z RETLW 0x44 ;if 0 then = 044h 'D' DECF XREG,f BTFSC STATUS,Z RETLW 0x31 ;if 1 then = 031h '1' DECF XREG,f BTFSC STATUS,Z RETLW 0x32 ;if 2 then = 032h '2' DECF XREG,f BTFSC STATUS,Z RETLW 0x33 ;if 3 then = 033h '3' DECF XREG,f BTFSC STATUS,Z RETLW 0x34 ;if 4 then = 034h '4' DECF XREG,f BTFSC STATUS,Z RETLW 0x35 ;if 5 then = 035h '5' DECF XREG,f BTFSC STATUS,Z RETLW 0x36 ;if 6 then = 036h '6' DECF XREG,f BTFSC STATUS,Z RETLW 0x37 ;if 7 then = 037h '7' DECF XREG,f BTFSC STATUS,Z RETLW 0x38 ;if 8 then = 038h '8' DECF XREG,f BTFSC STATUS,Z RETLW 0x39 ;if 9 then = 039h '9' DECF XREG,f BTFSC STATUS,Z RETLW 0x30 ;if 10 then = 030h '0' DECF XREG,f BTFSC STATUS,Z RETLW 0x2A ;if 11 then = 02Ah '*' DECF XREG,f BTFSC STATUS,Z RETLW 0x23 ;if 12 then = 023h '#' DECF XREG,f BTFSC STATUS,Z RETLW 0x41 ;if 13 then = 041h 'A' DECF XREG,f BTFSC STATUS,Z RETLW 0x42 ;if 14 then = 042h 'B' RETLW 0x43 ;if 15 then = 043h 'C' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Display Routine - Displays data in the buffer ;Calls INPUTB,LCDWAIT,OUTPUT ;Uses FLAGA,FLAGTMP,DATPNTR,BUFSTRT,DSPPNTR,YREG DISPLAY CLRF PORTA CLRF YREG MOVF FLAGA,w MOVWF FLAGTMP ;Temporarily store the Flags BCF FLAGTMP,7 MOVLW 0x80 MOVWF PORTB ;goto DD Ram Address 00h CALL OUTPUT ; BCF PORTA,3 BCF PORTA,2 BSF PORTA,4 ;Write to LCD NOP NOP BCF PORTA,4 BCF PORTA,2 CALL LCDWAIT ;Wait until LCD ready MOVF DATPNTR,w ADDLW BUFSTRT ;Add data Pointer to Buffer start MOVWF XREG ;And stash in Xreg MOVF DSPPNTR,w ADDLW BUFSTRT MOVWF FSR ;Move Dsplay pointer + Buffer start to FSR DISP1 MOVF XREG,w SUBWF FSR,w ;Check if equal to Data pointer + buffer offset BTFSC STATUS,Z BSF FLAGTMP,7 ;If so set end of Valid data flag BTFSC FLAGTMP,7 ;check if end of Valid data flag set GOTO DISP2 ;If so goto Insert Space MOVF INDF,w ;read data from INDF MOVWF PORTB ;Move to Data bus CLRF PORTA ; BSF PORTA,2 CALL OUTPUT ;Output data bus BSF PORTA,4 NOP NOP CLRF PORTA ;write to LCD CALL LCDWAIT ;wait for LCD CALL INPUTB ;Return bus to High impedance INCF FSR,f ;Increment FSR MOVLW BUFFEND1 ;Check if SUBWF FSR,w ;Past the BTFSS STATUS,Z ;End of the buffer GOTO DISP3 ;If not MOVLW BUFSTRT ;If so reload the MOVWF FSR ;FSR with the buffer start location GOTO DISP3 ;and go to ~~ DISP2 ; write spaces to LCD - over write any exsisting data MOVLW 0x20 MOVWF PORTB ;Output ASCII Space to the Data bus CLRF PORTA BSF PORTA,2 CALL OUTPUT BSF PORTA,4 ; Write to LCD NOP NOP CLRF PORTA CALL LCDWAIT ;Wait for LCD DISP3 CLRF PORTA ; INCF YREG,f ;Increment Yreg (Display character counter) MOVLW LCDLEN ;Check of Display is up to the SUBWF YREG,w ;16th character {lcdlen} BTFSS STATUS,Z GOTO DISP4 ;If not MOVLW 0xC0 ;If so jump to MOVWF PORTB ;DD Ram location CALL OUTPUT ;0C0h BSF PORTA,4 NOP NOP BCF PORTA,4 CALL LCDWAIT ;Wait for the LCD GOTO DISP1 ;Then go on to next character DISP4 MOVLW DSPLEN ;Check if at the end of the display ~~ 010h (17d) {dsplen} SUBWF YREG,w BTFSC STATUS,Z RETURN ;If so end Call GOTO DISP1 ;If not get the next Character ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Writes data in W register to LCD ;Calls OUTPUT,INPUTB ;Uses PBCTIM, WRLCD MOVWF PORTB CALL OUTPUT MOVLW 0x10 MOVWF PORTA NOP NOP CLRF PORTA CALL INPUTB RETURN ;Wait for LCD LCDWAIT CALL INPUTB ; Set Data bus to input BSF PORTA,3 BCF PORTA,2 BSF PORTA,4 BTFSS PORTB,7 ;Check Bit 7 of data from LCD GOTO ENDWAIT ; ; BCF PORTA,4 GOTO LCDWAIT ENDWAIT BCF PORTA,4 BCF PORTA,3 BSF PORTA,2 CALL OUTPUT RETURN end