;CODE FOR PIC CONTROLLED DTMF DECODER WITH 512 BYTE EEPROM USING A ;HITACHI CONTROLLED 2X16 LCD DISPLAY ;======== DTMF DECODER ======== ;-------------------------------------------- ; list p=16c84 radix hex ;---------------------------------------------- ; CPU REGISTER EQUATES (memory map) ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tmr0 EQU 0x01 pc EQU 0x02 status EQU 0x03 porta EQU 0x05 portb EQU 0x06 intcon EQU 0x0B opt_reg EQU 0x81 trisa EQU 0x85 trisb EQU 0x86 eecon1 EQU 0x88 eecon2 EQU 0x89 char EQU 0x0C AD_CTR EQU 0x0D scr_ctr EQU 0x0E save EQU 0x0F spctr1 EQU 0x10 spctr2 EQU 0x11 spctr3 EQU 0x12 flags EQU 0x13 ;BIT 0 CONTROLS WEATHER TO WRITE A SPACE ;BIT 1 SET MEANS SPACE WAS LAST CHARACTER ;WRITTEN TO LCD ;BIT 2 SET MEANS WE'RE IGNORING 1+AREA CODE ;BIT 3 is a "first time" flag for the ;ee_addr_hi function to facilitate ;9-bit eeprom addressing EE_ADDR EQU 0x14 RD_CTR EQU 0x15 EE_CTR EQU 0x16 txbuf EQU 0x17 bits EQU 0x18 eedat EQU 0x19 ; loopCtr0 EQU 0x1A loopCtr1 EQU 0x1B loopCtr2 EQU 0x1C ;OUR OWN HOMEMADE OPTION REGISTER OPTS EQU 0x1D ;OPTS ; BITS ; XXXXXXXX ; 00 NO GAP ; 01 SHORT GAP TIME ~ 4 SECONDS ; 10 LONG GAP TIME ~ 7 SECONDS ; 11 EXTRA LONG GAP TIME ~ 1 MINUTE ; 00XX IGNORE '1' WHEN DIALED FIRST ; 01XX ; 10XX ; 11XX ; OPTSTEST EQU 0x1E GAP EQU 0x1F ;interdigit gap IGNORE_CTR EQU 0x20 EE_ADDR_HI EQU 0x21 ;---------------------------------------------- ; ALIASES ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ rd EQU 0 wr EQU 1 wren EQU 2 rp0 EQU 5 gie EQU 7 C EQU 0 Z EQU 2 USER_ctrl EQU porta USER EQU porta LCD_ctrl EQU porta LCD_data EQU portb Playback EQU 4 bPress EQU 4 DV EQU 0 RS EQU 2 E EQU 3 PWDN EQU 1 CS EQU 3 ;SERIAL EEPROM CS TIED TO PORT B, PIN 3 CK EQU 2 ;SERIAL EEPROM CK TIED TO PORT B, PIN 2 DI EQU 1 ;SERIAL EEPROM DI TIED TO PORT B, PIN 1 DO EQU 0 ;SERIAL EEPROM DO TIED TO PORT B, PIN 0 EEPROM EQU portb ;EEPROM TIED TO LOW NIBBLE OF PORTB ERRORLEVEL -302 ;---------------------------------------------- org 0 ; ;--------------------------------------------------------------------------- ; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ start clrwdt ;prep for assign prescaler bsf status,rp0 movlw b'11010111' ;assign prescaler (divide by 256) ;internal portb pull-ups disabled movwf opt_reg movlw b'00000000' ;load w with $00 movwf trisb movlw b'00010001' ;Three output, two inputs movwf trisa bcf status,rp0 clrf porta ;all lines low clrf portb ;all lines low clrf flags ;all flags low BSF flags, 1 ;set for ignore routine ;--------------------------------------------------------------------------- ; LCD INIT ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ lcd_init ; movlw b'00110000' ;Function Set, 8-bit interface movwf portb ;Put it on portb call lcd_e call lcd_e call lcd_e movlw b'00101000' ;Function Set, 4-bit interface, 4th bit = DUAL LINE DISP ok? movwf portb ;put it on portb call lcd_e ; movlw b'00101000' ;4-bit interface, Single line display, font call lcd_cmd ; movlw b'00001111' ;DISP,BLINK ON/OFF,CURS (not respectivly:) call lcd_cmd ; movlw b'00000110' ;Entry mode set. What the hell does this do? call lcd_cmd ; movlw b'00000001' call lcd_cmd ;--------------------------------------------------------------------------- ; | END LCD INIT | ; | | ;--------------------------------------------------------------------------- ; call init_counters ;initialize all counters CALL EWEN ;SERIAL EEPROM ERASE/WRITE ENABLE ;--------------------------------------------------------------------------- ; LOADOPTS ; Load the previously saved options from last eeprom memory space ;--------------------------------------------------------------------------- CALL ST_BIT ;Set a start bit MOVLW D'2' ;Prep two bits for op-code MOVWF bits MOVLW B'10000000' ;SET OPCODE MOVWF txbuf ;prep to send CALL TX ;send op code CALL SEND_OPT_ADDR ;send address of our homemade option register CALL RX ;READ THE BYTE BCF EEPROM, CS ;LOW CHIP SELECT MOVF char, W ;RX read the byte into char MOVWF OPTS ;Get the byte into our OPTIONS register for use throughout the ;program execution MOVWF OPTSTEST clrf GAP ;DEFAULT VALUE FOR GAP MOVLW b'00110011' ANDWF OPTSTEST, F ;strip IGNORE bits for GAP tests CHK_NO_GAP bcf status, Z ;Clear Zero flag for test movlw b'00000011' andwf OPTSTEST, W btfsc status, Z ;Z flag raised? goto moveon CHK_SHRT_GAP bcf status, Z ;clear zero flag for test movlw b'00110001' subwf OPTSTEST, W btfss status, Z ;Zero flag raised? goto CHK_LONG_GAP BSF GAP, 3 ;set GAP to Equal THREE iterations if OPTS=1 (approx 4 sec.) goto moveon CHK_LONG_GAP bcf status, Z ;clear zero flag for test movlw b'00110010' ;LSB's at 10 = long gap subwf OPTSTEST, W btfss status, Z ;Zero flag raised? goto CHK_XLONG_GAP BSF GAP, 4 ;set GAP to Equal FOUR iterations if OPTS=2 (approx 14 sec.) goto moveon CHK_XLONG_GAP bcf status, Z ;clear zero flag for test movlw b'00110011' ;LSB's at 11 = long gap subwf OPTSTEST, W btfss status, Z ;Zero flag raised? goto moveon BSF GAP, 7 ;set GAP to Equal SEVEN iterations if OPTS=2 (approx 1 min.) ;***************************** FALL THROUGH TO MOVEON ********************* moveon ;--------------------------------------------------------------------------- ; MONITOR DTMF DATA BUS ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ call b_inputs ;change b3-7 to inputs bcf flags, 0 btfsc USER_ctrl,Playback ;SEE IF USER WANTS TO CLEAR LOG OR SETUP OPTIONS call OPTIONS call init_counters ;re-initialize after setting options dtmf btfss LCD_ctrl,DV ;DV high? goto polluser ;no, see if user wants anything bsf flags,0 ;Set the space flag clrf spctr1 ;Clear all space counters clrf spctr2 ;so interdigit pause times will not be added clrf spctr3 ;together loop btfsc LCD_ctrl,DV ;DV low? goto loop ;wait for DV to go low to prevent errors movf portb,w ;ready to decode & write tone andlw b'11110000' ;mask off low nibble noise call get_tone call lcd_write call WR_EEPROM ;Write char to eeprom goto dtmf ;--------------------------------------------------------------------------- ; POLL USER ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ polluser ;***** BEGIN INTERDIGIT AND IGNORE GAP COUNTER LOOP incf spctr1,f ;increment space counter each time btfsc spctr1,7 ;we at 128 yet? incf spctr2,f btfsc spctr1,7 ;if we're at 128 then . . . clrf spctr1 ;clear spctr1 and restart btfsc spctr2,7 ;space counter 2 at 128 yet? incf spctr3,f ;yes, increment space counter 3 btfsc spctr2,7 ;no, check again for clear clrf spctr2 ;clear spctr2 if 128 bcf status, Z ;clear Zero flag for test incf GAP decfsz GAP goto nonzerogap movlw d'4' ;default gap time for timing ;ignore routines when no gap goto zerogap ;SKIP AHEAD AND SET IT IF GAP=0 nonzerogap ;USE USER SETTINGS FOR IGNORE IF GAP>0 movf GAP, W ;Load GAP time into W zerogap subwf spctr3, W ;Subtract GAP time from spctr3 btfsc status, Z ;Result Zero? call wr_space ;Yes, call write space ;No, keep counting ;***** END INTERDIGIT & IGNORE GAP COUNTER LOOP btfss USER_ctrl,Playback ;Port A, Bit 4 Set? goto dtmf ;no debounc btfsc USER_ctrl,Playback ;yes, wait till no for debounce goto debounc goto RD_EEPROM ;yes, playback eeprom goto dtmf ;--------------------------------------------------------------------------- ; WRITE SPACE ; Writes a space to the LCD after a pre-specified inter-digit pause ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ wr_space BTFSS flags, 0 goto skipit ;CLEAR? Then only update counters & timer-dependent flags incf GAP, F ;increment GAP for test decfsz GAP ;GAP tested Zero? goto dontskip ;NO, so continue on to write space goto skipit ;YES, so skip over writing the space dontskip movlw a' ' ;load a space call lcd_write ;write a space call WR_EEPROM ;write it to the eeprom too skipit bcf flags,0 ;SO SPACES WON'T KEEP WRITING clrf spctr1 ;clear all counters clrf spctr2 clrf spctr3 BSF flags,1 ;Set this bit to indicate last thing ;written to LCD was a space ;used to decide whether to ignore '1' when ;dialed first BCF flags, 2 ;WHEN SET, WE'RE IGNORING 1+AREA CODE ;CLEAR IT TO SHOW A SPACE HAS BEEN WRITTEN ;IN CASE LESS THAN THREE DIGITS FOLLOW THE ;INITIAL '1'. PREVENTS ERRORS. clrf IGNORE_CTR ;reset ignore counter once gap time expires return ;--------------------------------------------------------------------------- ; GET_TONE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ get_tone movwf char ;Do this here to free up W register BTFSS OPTS, 3 ;1+AREA IGNORE OPTION SET? goto continue ;NO ;YES BTFSS flags, 2 ;Have we already ignored a '1' this round? goto continue ;No, continue bcf flags, 0 ;YES, clear the space flag so space won't write ;after ignored digits incf IGNORE_CTR ;increment the ignore counter btfss IGNORE_CTR, 2 ;Have we ignored 4 digits yet? goto NOnext ;NO, keep flag set and keep counting bcf flags, 2 ;YES, clear the multi-ignore flag clrf IGNORE_CTR ;YES, clear the ignore counter NOnext goto dtmf continue btfss flags,1 ;Is this the first digit in the series? goto dontignore ;NO bcf flags, 1 ;show that last thing written to LCD was ;NOT a space btfss OPTS, 2 ;ignore 1 set in OPTS? goto dontignore ;NO bcf status, Z ;clear Z flag for test movlw b'10000000' ;DTMF '1' IN HIGH NIBBLE RIGHT NOW subwf char, W btfss status, Z ;Zero flag set? goto dontignore ;NO, move on BSF flags, 2 ;SHOW THAT WE'VE IGNORED A 1 incf IGNORE_CTR ;increment the ignore counter bcf flags,0 ;YES, Clear the space flag so space won't write goto dtmf ;after '1' ignored; then return to dtmf dontignore ;JUMP HERE IF NOTHING TO IGNORE swapf char,W ;PUT NIBBLE IN CORRECT POSITION addwf pc,f ;Add offset to program counter retlw 0x44 ;D ;RETURN CORRESPONDING DTMF CHARACTER retlw 0x38 ;8 retlw 0x34 ;4 retlw 0x23 ;# retlw 0x32 ;2 retlw 0x30 ;0 retlw 0x36 ;6 retlw 0x42 ;B retlw 0x31 ;1 retlw 0x39 ;9 retlw 0x35 ;5 retlw 0x41 ;A retlw 0x33 ;3 retlw 0x2a ;* retlw 0x37 ;7 retlw 0x43 ;C ;--------------------------------------------------------------------------- ; 4 LCD ENABLE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ lcd_e bsf LCD_ctrl,E ;LCD Enable on call delay ;for higher clock speed bcf LCD_ctrl,E ;LCD Enable off return ;go back ; ;--------------------------------------------------------------------------- ; 36 LCD COMMAND ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ lcd_cmd call b_outputs ;MAKE HIGH NIBBLE BPORT OUTPUTS bcf LCD_ctrl,RS ;LOW RS for command movwf char ;Place W in char for manipulation. Code saved by kyle! movwf portb ;Place W (character) in PORTB call lcd_e ;strobe the enable line swapf char,0 ;Place low nibble at high nibble (data port) movwf portb ;put it on port b call lcd_e ;strobe LCD enable line bsf LCD_ctrl,RS ;HIGH RS back to "write mode" call b_inputs ;MAKE HIGH NIBBLE BPORT INPUTS return ;--------------------------------------------------------------------------- ; 149 max LCD WRITE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ lcd_write btfsc AD_CTR,4 ;address counter 16? call jump ;yes, jump to next screen address call b_outputs ;MAKE HIGH NIBBLE BPORT OUTPUTS movwf char ;Place W in char for manipulation movwf portb ;Place W (character) in PORTB call lcd_e ;strobe the LCD enable line swapf char,W ;Place low nibble at high nibble (data port) movwf portb ;Put it on port b call lcd_e ;Strobe LCD enable line swapf char,W ;put it back in prep for WR_EEPROM incf AD_CTR,f ;KEEP TRACK OF LCD ADDRESS call b_inputs ;MAKE HIGH NIBBLE BPORT INPUTS return ;--------------------------------------------------------------------------- ; 91 JUMP ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jump movwf save ;save w pin state movlw b'11000000' call lcd_cmd clrf AD_CTR incf scr_ctr,f btfsc scr_ctr,1 call clr_scr movf save,w ;return w pin state return ;--------------------------------------------------------------------------- ; 42 ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ clr_scr movlw b'00000001' call lcd_cmd clrf AD_CTR ;zero address counter clrf scr_ctr ;zero screen counter return ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; DELAY SUBROUTINE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ delay ;IFDEF PROD clrf tmr0 ;clear TMR0, start counting again btfss tmr0,5 ;bit 5 set ? goto again ;no, clear, again ;ENDIF return ;yes, end delay ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ init_counters movlw b'00000001' ;Clear LCD Screen call lcd_cmd clrf AD_CTR ;zero address counter clrf scr_ctr ;zero screen counter clrf EE_ADDR movlw B'01111111' ;set ee_addr_hi to 127, when incremented movwf EE_ADDR_HI ;bit 7 will rollover to 1 for easy feed ;into txbuf & tx routine to send a 1 clrf EE_CTR clrf RD_CTR clrf IGNORE_CTR return ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; 6 ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ b_inputs bsf status,rp0 movlw b'11110001' ;load w with $ff movwf trisb bcf status,rp0 return ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; 8 ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ b_outputs bsf status,rp0 movwf char ;save w pin state movlw b'00000001' ;load w with $00 movwf trisb movf char,W ;return w pin state bcf status,rp0 return ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; EEPROM FULL ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ eefull call clr_scr movlw a'M' call lcd_write movlw a'e' call lcd_write movlw a'm' call lcd_write movlw a'o' call lcd_write movlw a'r' call lcd_write movlw a'y' call lcd_write movlw a' ' call lcd_write movlw a'F' call lcd_write movlw a'u' call lcd_write movlw a'l' call lcd_write movlw a'l' call lcd_write bsf USER_ctrl,PWDN ;put 8870 to sleep sleep ;put PIC to sleep ;wakeup via reset ;No need for return statements ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; GET KEY ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ get_key btfss USER_ctrl,Playback ;Port A, Bit 2 Set? goto get_key keywait btfsc USER_ctrl,Playback ;Port A, Bit 2 Clear? goto keywait return ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ERASE/WRITE ENABLE SUBROUTINE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EWEN CALL ST_BIT MOVLW D'2' ;SET # BITS TO 2 MOVWF bits MOVLW B'00000000' ;GET THE OPCODE (00) MOVWF txbuf ;INTO THE TX BUFFER CALL TX MOVLW D'9' ;SET # BITS TO 9 MOVWF bits MOVLW B'11000000' ;GET OPCODE AND ADDRESS INTO OUTPUT BUFFER MOVWF txbuf CALL TX BCF EEPROM,CS ;LOW CHIP SELECT NOP ;ERASE/WRITE NOW ENABLED RETURN ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; SERIAL EEPROM WRITE SUBROUTINE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_EEPROM CALL ST_BIT MOVLW D'2' ;SET # BITS TO 2 MOVWF bits MOVLW B'01000000' ;GET THE OPCODE (00) MOVWF txbuf ;INTO THE TX BUFFER CALL TX CALL SET_ADDRESS ;SEND DATA BITS MOVLW D'8' ;SET # BITS TO 8 MOVWF bits MOVF char, W ;PUT CHAR IN WORKING REGISTER MOVWF txbuf CALL TX BCF EEPROM, CS ;LOW CHIP SELECT NOP ;250nS delay BSF EEPROM, CS hold btfss EEPROM, DO goto hold ;wait for eeprom to do internal write BCF EEPROM, CS NOP NOP BCF status, Z ;CLEAR Z FLAG FOR TEST INCFSZ EE_ADDR ;INCREMENT ADDRESS COUNTER goto upupup INCF EE_ADDR_HI ;If ee_addr is at 0, ee_addr_hi will go to 1 upupup btfss EE_ADDR_HI, 7 ;See if we're in the 2nd go-'round goto jmp_ret ;no ;yes, start counting to end BCF status, Z ;CLEAR ZERO FLAG FOR TEST MOVLW D'255' ;LOAD W WITH 255 SUBWF EE_ADDR, W ;SUBTRACT W FROM ADDRESS BTFSC status, Z ;IS IT 0? CALL eefull ;YES ;NO, CONTINUE jmp_ret RETURN ;RETURN FROM WR_EEPROM SUBROUTINE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; SERIAL EEPROM READ SUBROUTINE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RD_EEPROM CALL init_counters ;INITIALIZE ALL COUNTERS MOVLW d'32' MOVWF RD_CTR ;LOAD READ COUNTER WITH 32 RDLOOP CALL ST_BIT MOVLW D'2' MOVWF bits MOVLW B'10000000' ;SET OPCODE MOVWF txbuf CALL TX CALL SET_ADDRESS INCFSZ EE_ADDR, F ;INCREMENT EE_ADDR goto upup ;GETS HERE AFTER 16TH SCREEN btfss flags, 3 ;been here before? goto jmpfirsttime ;no CALL RX ;yes, READ THE last BYTE BCF EEPROM, CS ;LOW CHIP SELECT MOVF char, W ;put char in W to send to lcd CALL lcd_write ;WRITE THE character call get_key goto start jmpfirsttime INCF EE_ADDR_HI ;If ee_addr is at 0, ee_addr_hi will go to 1 bsf flags, 3 upup CALL RX ;READ THE BYTE BCF EEPROM, CS ;LOW CHIP SELECT MOVF char, W ;put char in W to send to lcd CALL lcd_write ;WRITE THE character DECFSZ RD_CTR ;DECREMENT RD_CTR, SKIP NEXT LINE IF ZERO GOTO RDLOOP MOVLW d'32' MOVWF RD_CTR ;LOAD READ COUNTER WITH 32 call get_key ;PAUSE AFTER 1 SCRN SO USER CAN VIEW OUTPUT GOTO RDLOOP ;NOT ZERO. HAVEN'T DONE 32 SCREENS YET. ;ZERO. WE'VE OUTPUT 32 SCREENS. WRAP IT UP. ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; START BIT SUBROUTINE ; CLEARS, DI, SC, & CK THEN SETS CS HIGH, THEN SETS DI HIGH FOR ; START BIT ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ST_BIT BCF EEPROM, DI ;DATA IN LOW BCF EEPROM, CS ;CHIP SELECT LOW BCF EEPROM, CK ;CLOCK LOW TO START NOP BSF EEPROM, CS ;CHIP SELECT HIGH BSF EEPROM, DI ;SET START BIT NOP BSF EEPROM, CK ;SET CLOCK LINE HIGH TO GENERATE START BIT NOP NOP BCF EEPROM, CK ;CLOCK LOW RETURN SET_ADDRESS MOVLW D'1' ;SET # BITS TO 8 MOVWF bits MOVF EE_ADDR_HI, W ;SET ADDRESS MOVWF txbuf ;INTO XMIT BUFFER CALL TX NOP NOP MOVLW D'8' ;SET # BITS TO 8 MOVWF bits MOVF EE_ADDR, W ;SET ADDRESS MOVWF txbuf ;INTO XMIT BUFFER CALL TX NOP NOP RETURN ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; TRANSMIT SERIAL DATA TO THE EEPROM ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TX movf bits, w movwf EE_CTR TXLP bcf eedat, 7 ;assume bit 7 is low btfsc txbuf, 7 ;is bit 7 clear? bsf eedat, 7 ;no, set to 1 call BITOUT ;transmit to serial eeprom rlf txbuf ;rotate txbuf left decfsz EE_CTR ;all bits done? goto TXLP ;no, do another return ;yes, jump out ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; BITOUT ; SEND A BIT TO THE EEPROM ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BITOUT btfss eedat, 7 ;check state of data bit goto bitlow ;low, goto bitlow bsf EEPROM, DI ;high, set DI high goto clkout ;clock it bitlow bcf EEPROM, DI ;output a logic low clkout bsf EEPROM, CK ;set CK high nop bcf EEPROM, CK ;return CK low return ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; RECEIVE DATA FROM THE SERIAL EEPROM ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RX CLRF char MOVLW D'8' ;SET # BITS TO 8 MOVWF EE_CTR BCF status, 0 ;MAKE SURE CARRY FLAG IS LOW RXLP CALL BITIN ;READ 1 BIT BCF char, 7 ;ASSUME BIT WAS LOW BTFSC eedat, 7 ;CHECK THE BIT BSF char, 7 ;SET HIGH IF NECESSARY RLF char DECFSZ EE_CTR ;8 BITS DONE? GOTO RXLP ;NO, DO ANOTHER RLF char ;Rotate char through carry flag RETURN ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; BITIN ; GET A BIT FROM THE SERIAL EEPROM ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BITIN BSF eedat, 7 ;ASSUME BIT HIGH BSF EEPROM, CK ;CLOCK HIGH NOP BTFSS EEPROM, DO ;READ THE BIT AT THE PORT BCF eedat, 7 ;BIT WAS LOW BCF EEPROM, CK ;CLOCK LOW RETURN ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; OPTIONS ; This is where user can clear log, set interdigit gap time, set ; option to Ignore digits such as 1, 1xxx, 1010, etc. ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OPTIONS btfsc USER, bPress ;wait for button up goto OPTIONS movlw a'C' call lcd_write movlw a'l' call lcd_write movlw a'e' call lcd_write movlw a'a' call lcd_write movlw a'r' call lcd_write movlw a' ' call lcd_write movlw a'L' call lcd_write movlw a'o' call lcd_write movlw a'g' call lcd_write movlw a'?' call lcd_write movlw a' ' call lcd_write ;***** Counter loop ********************************** ; Seconds? YES movlw a'Y' call lcd_write movlw a'e' call lcd_write movlw a's' call lcd_write movlw a' ' call lcd_write movlw a' ' call lcd_write CALL INITLOOP YESLP btfsc USER, bPress ;User pressed a button? goto WRAL ;yes, clear the log CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto NOGAP ;7-seconds up, goto next option goto YESLP ;Not 7s yet, go to YES WRAL btfss USER, bPress ;Wait for button up goto WRAL CALL ST_BIT MOVLW D'2' ;SET # BITS TO 2 MOVWF bits MOVLW B'00000000' ;GET THE OPCODE (00) MOVWF txbuf ;INTO THE TX BUFFER CALL TX MOVLW D'9' ;SET # BITS TO 9 MOVWF bits MOVLW B'01000000' ;GET OPCODE AND ADDRESS INTO OUTPUT BUFFER MOVWF txbuf CALL TX ;SEND DATA BITS MOVLW D'8' ;SET # BITS TO 8 MOVWF bits MOVLW b'11110100' ;Omega Symbol ; MOVLW b'00000000' ;Zero out 255. Once only, then comment out this line. MOVWF txbuf CALL TX BCF EEPROM,CS ;LOW CHIP SELECT NOP ;250nS delay BSF EEPROM, CS ewenhold btfss EEPROM, DO goto ewenhold ;wait for eeprom to do internal write BCF EEPROM, CS CALL WR_OPT ;Put Options back at ee address 255 ;************************ FALL THROUGH TO INTERDIGIT GAP SELCTION ROUTINES ********************** NOGAP CLRF AD_CTR ;ADDRESS COUNTER BACK TO ZERO MOVLW b'10000000' ;CURSOR BACK CALL lcd_cmd btfsc USER, bPress ;Wait for button up goto NOGAP movlw a'S' call lcd_write movlw a'e' call lcd_write movlw a't' call lcd_write movlw a' ' call lcd_write movlw a'G' call lcd_write movlw a'a' call lcd_write movlw a'p' call lcd_write movlw a':' call lcd_write movlw a' ' call lcd_write movlw a'N' call lcd_write movlw a'o' call lcd_write movlw a' ' call lcd_write movlw a'G' call lcd_write movlw a'a' call lcd_write movlw a'p' call lcd_write movlw a'.' call lcd_write CALL INITLOOP ;NO GAP SELECTION LOOP NOGAP_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_NOGAP_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto SHORTGAP ;YES, DELAY TIME EXPIRED GO TO NEXT USER OPTION goto NOGAP_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES ;------------------------------------------------------------------------------------------------ ; WRITE NO GAP OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_NOGAP_OPT btfsc USER, bPress ;Wait for button up goto WR_NOGAP_OPT movlw b'00001100' ;Prepare strip mask andwf OPTS, F ;strip off 2 lsb's in prep for rewrite of interdigit gap time opt movlw b'00110000' ;NO GAP xorwf OPTS, F ;XOR toggles only one bit CALL WR_OPT goto IGNORE1 ;------------------------------------------------------------------------------------------------ ; SHORT GAP ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SHORTGAP btfsc USER, bPress ;Wait for button up goto SHORTGAP ;BACK UP LCD, OVERWRITE ONLY CHARACTERS THAT NEED OVERWRITING TO ;SAVE PROGRAM MEMORY MOVLW d'7' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR ; decf scr_ctr, f MOVLW b'10000111' ;move cursor to end of first lcd screen CALL lcd_cmd movlw a' ' call lcd_write movlw a'T' call lcd_write movlw a'i' call lcd_write movlw a'm' call lcd_write movlw a'e' call lcd_write movlw a' ' call lcd_write movlw a'S' call lcd_write movlw a'h' call lcd_write movlw a't' call lcd_write CALL INITLOOP ;SHORT GAP SELECTION LOOP SHGAP_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_SHGAP_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto LONG_GAP ;YES, DELAY TIME EXPIRED GO TO NEXT USER OPTION goto SHGAP_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES ;------------------------------------------------------------------------------------------------ ; WRITE SHORT GAP OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_SHGAP_OPT btfsc USER, bPress ;Wait for button up goto WR_SHGAP_OPT movlw b'00001100' ;Prepare strip mask andwf OPTS, F ;strip off 2 lsb's in prep for rewrite of interdigit gap time opt movlw b'00110001' ;8 seconds (high bits protect other options from overwrite xorwf OPTS, F ;XOR toggles only one bit CALL WR_OPT goto IGNORE1 ;************************* FALL THROUGH TO LONG GAP ********************************************* LONG_GAP btfsc USER, bPress ;Wait for button up goto LONG_GAP MOVLW d'13' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR MOVLW b'10001101' ;CURSOR BACK THREE SPACES CALL lcd_cmd movlw a'L' call lcd_write movlw a'n' call lcd_write movlw a'g' call lcd_write CALL INITLOOP ;LONG GAP SELECTION LOOP LGAP_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_LGAP_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto XLONG_GAP ;YES, DELAY TIME EXPIRED. GO TO NEXT OPTION. goto LGAP_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES. ;------------------------------------------------------------------------------------------------ ; WRITE LONG GAP OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_LGAP_OPT btfsc USER, bPress ;Wait for button up goto WR_LGAP_OPT movlw b'00001100' ;Prepare strip mask andwf OPTS, F ;strip off 2 lsb's in prep for rewrite of interdigit gap time opt movlw b'00110010' ;16 seconds (high bits protect other options from overwrite xorwf OPTS, F ;XOR toggles only one bit CALL WR_OPT goto IGNORE1 ;************************ FALL THROUGH TO EXTRA LONG GAP OPTION ********************************* XLONG_GAP btfsc USER, bPress ;Wait for button up goto XLONG_GAP MOVLW d'13' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR MOVLW b'10001101' ;CURSOR BACK THREE SPACES CALL lcd_cmd movlw a'X' call lcd_write movlw a'l' call lcd_write movlw a'g' call lcd_write CALL INITLOOP XLGAP_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_XLGAP_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto IGNORE1 ;YES, DELAY TIME EXPIRED. GO TO NEXT OPTION. goto XLGAP_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES. ;------------------------------------------------------------------------------------------------ ; WRITE LONG GAP OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_XLGAP_OPT btfsc USER, bPress ;Wait for button up goto WR_XLGAP_OPT movlw b'00001100' ;Prepare strip mask andwf OPTS, F ;strip off 2 lsb's in prep for rewrite of interdigit gap time opt movlw b'00110011' ;SET TO 3 FOR EXTRA LONG GAP TIME xorwf OPTS, F CALL WR_OPT ;************ FALL THROUGH TO IGNORE 1 ROUTINE *********** ;------------------------------------------------------------------------------------------------ ; IGNORE 1 WHEN DIALED FIRST ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IGNORE1 btfsc USER, bPress ;Wait for button up goto IGNORE1 MOVLW d'4' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR ; decf scr_ctr, f MOVLW b'10000100' ;CURSOR BACK TO DD RAM 4 (fifth block) CALL lcd_cmd movlw a'I' call lcd_write movlw a'g' call lcd_write movlw a'n' call lcd_write movlw a'o' call lcd_write movlw a'r' call lcd_write movlw a'e' call lcd_write movlw a' ' call lcd_write movlw a'1' call lcd_write movlw a'?' call lcd_write movlw a' ' call lcd_write movlw a' ' call lcd_write movlw a' ' call lcd_write CALL INITLOOP IGNORE1_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_IGNORE1_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto IGNORE1AREA ;YES, DELAY TIME EXPIRED. GO TO NEXT OPTION. goto IGNORE1_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES. ;------------------------------------------------------------------------------------------------ ; WRITE IGNORE1 OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_IGNORE1_OPT btfsc USER, bPress ;Wait for button up goto WR_IGNORE1_OPT movlw b'00000011' ;Prepare strip mask andwf OPTS, F ;strip off high nible MSBs in prep for rewrite of interdigit gap time opt movlw b'00110100' ;SET TO IGNORE 1 xorwf OPTS, F CALL WR_OPT goto PROGEND ;------------------------------------------------------------------------------------------------ ; IGNORE 1+AREA CODE WHEN DIALED FIRST ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IGNORE1AREA btfsc USER, bPress ;Wait for button up goto IGNORE1AREA MOVLW d'12' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR MOVLW b'10001100' ;CURSOR BACK TO DD RAM 4 (fifth block) CALL lcd_cmd movlw a'A' call lcd_write movlw a'R' call lcd_write movlw a'E' call lcd_write movlw a'A' call lcd_write CALL INITLOOP IGNORE1AREA_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_IGNORE1AREA_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto IGNORENONE ;YES, DELAY TIME EXPIRED. GO TO NEXT OPTION. goto IGNORE1AREA_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES. ;------------------------------------------------------------------------------------------------ ; WRITE IGNORE 1+AREA CODE OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_IGNORE1AREA_OPT btfsc USER, bPress ;Wait for button up goto WR_IGNORE1AREA_OPT movlw b'00000011' ;Prepare strip mask andwf OPTS, F ;strip off high nibble MSBs in prep for rewrite of interdigit gap time opt movlw b'00111100' ;SET TO IGNORE 1+AREA CODE xorwf OPTS, F CALL WR_OPT goto PROGEND ;------------------------------------------------------------------------------------------------ ; IGNORE NONE ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IGNORENONE btfsc USER, bPress ;Wait for button up goto IGNORENONE MOVLW d'10' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR MOVLW b'10001010' ;CURSOR BACK CALL lcd_cmd movlw a' ' call lcd_write movlw a'N' call lcd_write movlw a'O' call lcd_write movlw a'N' call lcd_write movlw a'E' call lcd_write movlw a'?' call lcd_write CALL INITLOOP IGNORENONE_SEL_LP btfsc USER, bPress ;User pressed a button? goto WR_IGNORENONE_OPT ;yes, CALL LOOPIT btfsc loopCtr2,4 ;LC2 at 16 yet? goto PROGEND ;YES, DELAY TIME EXPIRED. GO TO NEXT OPTION. goto IGNORENONE_SEL_LP ;NO, KEEP COUNTING DELAY CYCLES. ;------------------------------------------------------------------------------------------------ ; WRITE IGNORE NONE OPTION ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_IGNORENONE_OPT btfsc USER, bPress ;Wait for button up goto WR_IGNORENONE_OPT movlw b'00000011' ;Prepare strip mask andwf OPTS, F ;strip off high nibble MSBs in prep for rewrite of interdigit gap time opt movlw b'00110000' ;SET TO IGNORE NONE xorwf OPTS, F CALL WR_OPT goto PROGEND ;------------------------------------------------------------------------------------------------ ; WR_OPT ; WRITE TO OUR HOMEMADE OPTION REGISTER ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WR_OPT CALL ST_BIT MOVLW D'2' ;SET # BITS TO 2 MOVWF bits MOVLW B'01000000' ;GET THE OPCODE (00) MOVWF txbuf ;INTO THE TX BUFFER CALL TX CALL SEND_OPT_ADDR ;SEND DATA BITS MOVLW D'8' ;SET # BITS TO 8 MOVWF bits MOVF OPTS, W ;Put current option values into W register MOVWF txbuf CALL TX BCF EEPROM, CS ;LOW CHIP SELECT NOP ;250nS delay BSF EEPROM, CS opthold btfss EEPROM, DO goto opthold ;wait for eeprom to do internal write BCF EEPROM, CS NOP NOP RETURN SEND_OPT_ADDR MOVLW D'1' ;SET # BITS TO 1 MOVWF bits MOVLW b'11111111' ;SET ADDRESS, 511 (of 0-511), homemade option register MOVWF txbuf ;INTO XMIT BUFFER CALL TX NOP NOP MOVLW D'8' ;SET # BITS TO 8 MOVWF bits MOVLW b'11111111' ;SET ADDRESS, 511 (of 0-511), homemade option register MOVWF txbuf ;INTO XMIT BUFFER CALL TX NOP NOP RETURN ;--------------------------------------------------------------------------- ; INIT LOOP ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INITLOOP clrf loopCtr0 clrf loopCtr1 clrf loopCtr2 RETURN PROGEND MOVLW d'0' ;UPDATE COUNTERS TO REFLECT ADDRESS CHANGE MOVWF AD_CTR movlw b'00000001' ;Clear LCD Screen call lcd_cmd ; MOVLW b'10000000' ;CURSOR BACK ; CALL lcd_cmd movlw a'P' call lcd_write movlw a'R' call lcd_write movlw a'E' call lcd_write movlw a'S' call lcd_write movlw a'S' call lcd_write movlw a' ' call lcd_write movlw a'K' call lcd_write movlw a'E' call lcd_write movlw a'Y' call lcd_write ENDLP BTFSS USER, bPress ;PAUSE ON THIS SCREEN GOTO ENDLP ENDLP2 BTFSC USER, bPress ;WAIT FOR BUTTON UP GOTO ENDLP2 GOTO start LOOPIT incf loopCtr0,f ;increment counter each time btfsc loopCtr0,7 ;we at 128 yet? incf loopCtr1,f btfsc loopCtr0,7 ;if we're at 128 then . . . clrf loopCtr0 ;clear spctr1 and restart btfsc loopCtr1,7 ;LC1 at 128 yet? incf loopCtr2,f ;yes, increment LC2 btfsc loopCtr1,7 ;no, check again for clear clrf loopCtr1 ;clear LC1 if 128 RETURN END