; infoglobe.ASM source code ; Version 4.00 ; Created 6-01-05 ; Last modified 6-20-05 ; Text generator for Infoglobe clock/CID ; Scan and reminder modes added. ; Random number generator added. ; Written by: ; Andrew R. Morris ; 3531 Olympic Drive ; Green Cove Springs, FL 32043 ; Phone: 904.529.8357 ; Fax: 904.284.2655 ; Cell: 386.546.4468 ; This device sends pre-programmed messages to a modified Infoglobe clock/CID device. ; This is just a simple program to use as a starting point and to demonstrate a super-simple ; way of interfacing to the Infoglobe. ; When the message generator sends a pre-programmed message to the Infoglobe, it disables the ; data transfer from the base to the rotor. Pressing the button in browse mode switches to another ; pre-programmed message. Continued pressing of the button in browse mode cycles through all the ; messages until the "Off" message, where the Infoglobe immediately displays "off" until the the ; rotor is again updated by the base. ; The message generator switches between two modes by holding the button down for 2 seconds. The default mode ; (browse mode) cycles through the messages when the button is pushed (for less than 2 seconds), and the ; other mode (on/off mode) simply toggles on (displaying the selected message) and off when the button is ; briefly pushed. ; A new "scan" mode has been added to this version. ; In the browse mode there is a message ("Scan?") which puts the device in the "scan" mode when the button ; is held down. In this mode, the device cycles through all messages, except "Off", similar to the way ; the Infoglobe does normally. Another mode, called the "reminder" mode has been added. This mode is basically ; the same as the scan mode, except that specially tagged messages are transmitted repeatedly instead of ; sequentially. This allows one to turn the infoglobe off and have it come on, displaying the reminder message. ; Detailed operating instructions are provided in a seperate document. ; PORTA,0 (RA0) is DATA_LED_OUT ; PORTA,1 (RA1) is BASE_DISABLE ; PORTA,2 (RA2) is TP1 ; PORTA,3 (RA3) is not used ; PORTA,4 (RA4) is not used ; PORTB,0 (RB0) is not used ; PORTB,1 (RB1) is PUSHBUTTON_N ; PORTB,2 (RB2) is not used ; PORTB,3 (RB3) is not used ; PORTB,4 (RB4) is not used ; PORTB,5 (RB5) is not used ; PORTB,6 (RB6) is serial programming clock (if used) ; PORTB,7 (RB7) is Serial programming data (if used) ; This code was written for a PIC16F84 with 4.0 MHz resonator master oscillator. LIST P=16F84 include c:\progra~1\mplab\P16F84.inc __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ;Register equates LCVR1 EQU 0C ;Loop count variable register 1 LCVR2 EQU 0D ;Loop count variable register 2 LCVR3 EQU 0E ;Loop count variable register 3 LCVR4 EQU 0F ;Loop count variable register 4 DREG EQU 10 ;Data byte register MSG_CNTR EQU 11 ;Message counter - Determines which is the current message. STAT EQU 12 ;Status register LAST_MSG EQU 13 ;Determines which was the last message for on/off mode. RANDOM EQU 14 ;Random number for effects selection. TEMP EQU 15 ;Temporary register. ;Initialization equates INIT_A EQU B'00000000' ;Initialize PORTA INIT_B EQU B'00000010' ;Initialize PORTB CFG_A EQU B'00000000' ;Configure PORTA CFG_B EQU B'00000010' ;Configure PORTB OPTINI EQU B'00001000' ;Initialize option register ;Bit equates MSB EQU 7 ;STAT register equates ON_OFF_MODE EQU 0 SCAN_MODE EQU 1 SCAN_MSG EQU 2 REMINDER EQU 3 ;Current msg has reminder option available. REMINDER_MODE EQU 4 ;Reminder mode causes selected msg to continuously retransmit. ;Parameter equates Dbnce EQU D'40' ;Pushbutton debounce count (255 is 324mS) ZERO_TWEAK EQU D'3' ;Adjust TP1 for 8ms per byte sending all zeros. ONE_TWEAK EQU D'76' ;Adjust TP1 for 8ms per byte sending all ones. MSG_AVAIL EQU D'11' ;Number of messages available + 2. ;Number of messages displayed limited to 254 or by memory. PB_HLD_TIME EQU D'6' ;How long to hold button down to change modes (3 counts per second) DISPLAY_TIME EQU D'45' ;Message display time in scan mode (3 counts per second) ;The "TWEAK" parameters are adjusted by connecting a scope or counter to TP1 and ; adjusting these parameters for a pulse width as close as possible to 8mS per character, ; using all zeros (00h) and all ones (FFh), respectively. Use as many characters as ; possible for best accuracy. The infoglobe accepts 35 characters (plus 3 control ; characters) max. It reserves one of its 36 character slots for a space between the ; beginning and the end of the message. ;I/O pin equates ;PORTA DATA_LED_OUT EQU 0 ;Data LED output BASE_DISABLE EQU 1 ;Disables data to rotor from base TP1 EQU 2 ;Test point 1 ;PORTB PUSHBUTTON_N EQU 1 ;Pushbutton (active low) ; ----------------------------------------------------------------------------- ORG 0 ;reset vector rolls over to here CLRF PCLATH ;ensure page bits are cleared GOTO Boot ;go to beginning of program ; ----------------------------------------------------------------------------- ORG 4 RETFIE ;return from interrupt ; ----------------------------------------------------------------------------- ;Subroutines ; SEND - This routine tests the MSB of the data register (DREG) and ; sends the program to the appropriate LED output routine, depending whether ; the bit is high or low. Once the data LED is handled appropriately, the data ; register is shifted one bit to the left and the test is performed again until ; all 8 bits are tested. ; ZERO_OUT - This routine produces the 38KHz carrier signal needed by ; the IR detector in the rotor of the Infoglobe. This indicates a data ; bit low. Since the first 4 data bits of a message will always be zero, ; this is used by the rotor as a way to detect the presence of incoming data. ; This carrier must last exactly 1ms, or 38 cycles. The LED is turned on for 13uS ; and off for 13uS, which is a little higher frequency than 38KHz, (38.46KHz) but ; is acceptable to the IR detector and leaves a little time available for the ; clock cycles required to do the job and for timing tweaking. SEND ;Sends the character in DREG out to the LED. MOVLW D'8' ;8 bits per byte (character) MOVWF LCVR4 SHFT_LP BTFSC DREG,MSB ;Test MSB for one or zero GOTO ONE_OUT ZERO_OUT MOVLW D'38' MOVWF LCVR1 LP_CNT BSF PORTA,DATA_LED_OUT ;Turn on LED for 13mS. MOVLW D'3' MOVWF LCVR2 ON_LP DECFSZ LCVR2,F GOTO ON_LP NOP NOP BCF PORTA,DATA_LED_OUT ;Turn off LED for 13mS. MOVLW D'2' MOVWF LCVR2 OFF_LP DECFSZ LCVR2,F GOTO OFF_LP NOP NOP DECFSZ LCVR1,F GOTO LP_CNT MOVLW ZERO_TWEAK ;Tweak parameter for fine-tuning ZERO timing. Adds MOVWF LCVR3 ; a little time between bytes. LP3 DECFSZ LCVR3,F GOTO LP3 NXT_BIT RLF DREG,F ;Shift left, decrement loop count. DECFSZ LCVR4,F GOTO SHFT_LP RETLW 0 ;returns for the next character. ; ONE_OUT just turns off the LED and waits exactly 1mS, including the clock cycles ; required to do the job. ONE_OUT BCF PORTA,DATA_LED_OUT ;Turn off LED MOVLW D'255' MOVWF LCVR1 LP1 DECFSZ LCVR1,F GOTO LP1 MOVLW ONE_TWEAK ;Tweak parameter for fine-tuning ONE timing. Adds MOVWF LCVR1 ; a little time between bytes. LP2 DECFSZ LCVR1,F GOTO LP2 GOTO NXT_BIT TOGGLE_ON_OFF ;Toggles on/off mode. BTFSS STAT,ON_OFF_MODE GOTO SET_ON_OFF_MODE BCF STAT,ON_OFF_MODE RETLW 0 ;The on/off mode is used in the browse mode to turn a selected msg on and off. It's also used in ; the reminder mode, because when STAT,ON_OFF_MODE is set, the LAST_MSG register is not updated. This ; causes the same message always to be displayed. SET_ON_OFF_MODE ;Set on/off mode and reminder mode, if it's enabled. BSF STAT,ON_OFF_MODE BTFSS STAT,REMINDER ;Set reminder mode if reminder option is available for this msg. RETLW 0 BSF STAT,REMINDER_MODE RETLW 0 SCAN ;Asks if you want to go into scan mode. BTFSC STAT,SCAN_MODE ;Bypass msg if already in scan mode. GOTO BROWSE_MODE MOVLW H'01' ;No scroll MOVWF DREG CALL SEND MOVLW A'S' MOVWF DREG CALL SEND MOVLW A'c' MOVWF DREG CALL SEND MOVLW A'a' MOVWF DREG CALL SEND MOVLW A'n' MOVWF DREG CALL SEND MOVLW A'?' MOVWF DREG CALL SEND BSF STAT,SCAN_MSG ;Flag that scan message has been displayed. GOTO CONTINUE_FROM_SCAN DISPLAY_TIMER ;Sets interval between messages in scan mode MOVLW DISPLAY_TIME ; and retransmissions in reminder mode. MOVWF LCVR1 DT_LP1 MOVLW D'255' MOVWF LCVR2 DT_LP2 MOVLW D'255' MOVWF LCVR3 DT_LP3 BTFSS PORTB,PUSHBUTTON_N GOTO EXIT_TIMER DECFSZ LCVR3,F GOTO DT_LP3 DECFSZ LCVR2,F GOTO DT_LP2 DECFSZ LCVR1,F GOTO DT_LP1 BTFSS STAT,REMINDER_MODE GOTO BROWSE_MODE ;Transmit next message. GOTO RTX ;Retransmit current message. SCAN_ON BSF STAT,SCAN_MODE BCF STAT,SCAN_MSG GOTO BROWSE_MODE ;Transmit next message. EXIT_TIMER ;This debounce routine verifies you really MOVLW Dbnce ; intend to exit scan or reminder mode. MOVWF LCVR1 LP6 MOVLW D'255' MOVWF LCVR2 TST_PB2 BTFSC PORTB,PUSHBUTTON_N GOTO DISPLAY_TIMER DECFSZ LCVR2,F GOTO TST_PB2 DECFSZ LCVR1,F GOTO LP6 CALL DEBOUNCE_HI BCF STAT,ON_OFF_MODE BCF STAT,SCAN_MODE BCF STAT,REMINDER_MODE MOVLW MSG_AVAIL MOVWF MSG_CNTR GOTO OFF DEBOUNCE_LO ;Verify PB is reliably on (low). MOVLW Dbnce MOVWF LCVR1 LP4 MOVLW D'255' MOVWF LCVR2 TST_PB BTFSC PORTB,PUSHBUTTON_N GOTO DEBOUNCE_LO DECFSZ LCVR2,F GOTO TST_PB DECFSZ LCVR1,F GOTO LP4 RETLW 0 DEBOUNCE_HI ;Verify PB is reliably off (high). MOVLW Dbnce MOVWF LCVR1 LP5 MOVLW D'255' MOVWF LCVR2 TST_PB1 BTFSS PORTB,PUSHBUTTON_N GOTO DEBOUNCE_HI DECFSZ LCVR2,F GOTO TST_PB1 DECFSZ LCVR1,F GOTO LP5 RETLW 0 GET_RANDOM ;Pseudorandom number generator RLF RANDOM,W ;Shift RANDOM 3 times to left. MOVWF TEMP ;Result in W. RLF TEMP,F RLF TEMP,W XORWF RANDOM,W ;XOR RANDOM at bits 2 and 5 (3 shifts) MOVWF TEMP ;Result in TEMP bit 5. BTFSC TEMP,5 ;Copy XOR result into RANDOM bit 0. GOTO SETBIT BCF RANDOM,0 GOTO SHFT SETBIT BSF RANDOM,0 SHFT RLF RANDOM,F ;Shift RANDOM register. MOVF RANDOM,W ANDLW H'3F' ;We only need 6 of the 8 bits. MOVWF RANDOM ;Move W into RANDOM, just in case we can use it. SUBLW H'25' ;Is it between 00h and 25h? BTFSS STATUS,C GOTO GET_RANDOM ;If not, try again. RETLW 0 RANDOM_EFFECTS ;Selected message exits to here for random MOVF RANDOM,W ; transition effects. MOVWF DREG CALL SEND GOTO START Boot ; Initialize I/O ports BSF STATUS, RP0 ;Select bank 1 MOVLW CFG_A ;Select direction of PORTA bits MOVWF TRISA ;Write selection to PORTA data ;direction register MOVLW CFG_B ;Select direction of PORTB bits MOVWF TRISB ;Write selection to PORTB data ;direction register BCF STATUS, RP0 ;Select bank 0 MOVLW INIT_A ;Initialize PORT A MOVWF PORTA MOVLW INIT_B ;Initialize PORT B MOVWF PORTB CLRF STATUS CLRF TMR0 ;Reset TMR0 and prescaler CLRF INTCON BSF STATUS, RP0 ;Select bank 1 (Preselector is in ;bank 1) CLRWDT ;Reset watchdog timer MOVLW OPTINI ;Initialize option register MOVWF OPTION_REG ;Put selection in option register BCF STATUS, RP0 ;Select bank 0 MOVLW 1 MOVWF MSG_CNTR CLRF STAT MOVLW H'2A' ;Init for 6-bit random number generator MOVWF RANDOM Start ;The program actually starts here. CALL GET_RANDOM ;Trigger random number generator to create ; a new number. CALL DEBOUNCE_HI BTFSC STAT,REMINDER_MODE ;If in reminder mode, go to display timer. GOTO DISPLAY_TIMER BTFSC STAT,SCAN_MODE ;If in scan mode, go to display timer. GOTO DISPLAY_TIMER CONTINUE_FROM_SCAN CALL DEBOUNCE_LO MOVLW PB_HLD_TIME ;Verify PB is held down long enough MOVWF LCVR1 ; to change modes (3 counts per second) PB_LP1 MOVLW D'255' MOVWF LCVR2 PB_LP2 MOVLW D'255' MOVWF LCVR3 PB_LP3 BTFSC PORTB,PUSHBUTTON_N GOTO CONTINUE DECFSZ LCVR3,F GOTO PB_LP3 DECFSZ LCVR2,F GOTO PB_LP2 DECFSZ LCVR1,F GOTO PB_LP1 BTFSC STAT,SCAN_MSG ;Turn on scan mode if PB held down after GOTO SCAN_ON ; scan message was displayed. CALL TOGGLE_ON_OFF ;We're in browse mode at this point. BTFSC STAT,REMINDER_MODE ;Retransmit current msg only, if in reminder mode. GOTO RTX CONTINUE BCF STAT,REMINDER BCF STAT,SCAN_MSG BTFSS STAT,ON_OFF_MODE ;If not in on/off mode, send next msg. GOTO BROWSE_MODE BTFSC PORTA,BASE_DISABLE ;Disable line is used as an on/off flag. GOTO OFF RTX MOVF LAST_MSG,W ;Transmit or retransmit last selected message. GOTO MESSAGE_SELECT BROWSE_MODE MOVF MSG_CNTR,W ;Saves current msg in last msg for on/off mode. MOVWF LAST_MSG DECFSZ MSG_CNTR,F ;Changes count to select next message. GOTO MESSAGE_SELECT MOVLW MSG_AVAIL MOVWF MSG_CNTR BTFSS STAT,SCAN_MODE ;Don't go to "OFF" if in scan mode. GOTO OFF ;Turns off after last message if not scanning. MOVF MSG_CNTR,W MESSAGE_SELECT BSF PORTA,BASE_DISABLE ADDWF PCL,F ;Go to selected message or function. NOP NOP GOTO MSG9 GOTO MSG8 GOTO MSG7 GOTO MSG6 GOTO MSG5 GOTO MSG4 GOTO MSG3 GOTO MSG2 GOTO MSG1 GOTO SCAN OFF ;Turn off Infoglobe. MOVLW H'01' ;Centered, stationary display MOVWF DREG CALL SEND MOVLW A'O' MOVWF DREG CALL SEND MOVLW A'f' MOVWF DREG CALL SEND MOVLW A'f' MOVWF DREG CALL SEND BCF PORTA,BASE_DISABLE GOTO START ;MSG1 - This is the first actual message to be transmitted. Each character is loaded into ; the data register and then the SEND routine is called to send it. The first ; character is a control character that defines if and how the display will scroll. ; A control character can also be added to the end of the message to define an ; animated transition effect when the new message replaces the previous one. ; Scroll codes (byte 1): ;00 Load non-scroll msg into buffer for effects. ;01 Load and display non-scroll message. ;03 New msg scrolls or not, same as previous msg. ;04 Load and display scroll msg ;06 Start and stop scroll ; Note that I have the version that uses 3 AAA batteries. ; Transition codes: ; These determine what, if any animation is used in the InfoGlobe to ; transition from one message to the next. ; Byte 1 and 2 must be low (00 and 00) to enable ; transition effects. ;Last byte defines transition effect, and is ;anything from 00 to 25 (hex). ; My version of the Infoglobe supports all ASCII text codes except the following, which ; are displayed as spaces: % & + ; @ [ \ ] ^ _ ` { | } ~ MSG1 ;No effects, no scroll BSF PORTA,TP1 ;Where you would set TP1 for timing tweaking. MOVLW H'01' ;No scroll MOVWF DREG CALL SEND MOVLW A'M' ;Msg1 MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A'g' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'1' MOVWF DREG CALL SEND BCF PORTA,TP1 ;Where you would clear TP1 for timing tweaking. GOTO START MSG2 ;Specific effect MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW A'M' ;Msg2 MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A'g' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'2' MOVWF DREG CALL SEND MOVLW H'1A' MOVWF DREG CALL SEND GOTO START MSG3 ;Random effects MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW A'M' ;Msg3 MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A'g' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'3' MOVWF DREG CALL SEND GOTO RANDOM_EFFECTS MSG4 ;Reminder message, scrolling with no effects BTFSC STAT,SCAN_MODE ;Skip msg and timer if in scan mode GOTO BROWSE_MODE BSF STAT,REMINDER ;Set reminder flag MOVLW H'04' ;Scrolling enabled MOVWF DREG CALL SEND MOVLW A'M' ;Msg4 MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A'g' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'4' MOVWF DREG CALL SEND GOTO START MSG5 ;Reminder message with specific effect BTFSC STAT,SCAN_MODE ;Skip msg and timer if in scan mode GOTO BROWSE_MODE BSF STAT,REMINDER ;Set reminder flag MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW A'C' ;Call Mom MOVWF DREG CALL SEND MOVLW A'a' MOVWF DREG CALL SEND MOVLW A'l' MOVWF DREG CALL SEND MOVLW A'l' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'M' MOVWF DREG CALL SEND MOVLW A'o' MOVWF DREG CALL SEND MOVLW A'm' MOVWF DREG CALL SEND MOVLW H'18' MOVWF DREG CALL SEND GOTO START MSG6 ;Reminder message with random effects. BTFSC STAT,SCAN_MODE ;Skip msg and timer if in scan mode GOTO BROWSE_MODE BSF STAT,REMINDER ;Set reminder flag MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW H'00' ;Effects enable MOVWF DREG CALL SEND MOVLW A'P' ;Pay bills MOVWF DREG CALL SEND MOVLW A'a' MOVWF DREG CALL SEND MOVLW A'y' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'b' MOVWF DREG CALL SEND MOVLW A'i' MOVWF DREG CALL SEND MOVLW A'l' MOVWF DREG CALL SEND MOVLW A'l' MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND GOTO RANDOM_EFFECTS MSG7 MOVLW H'05' ;Function select. MOVWF DREG CALL SEND MOVLW A'T' ;This is a test, with "is" flashing. MOVWF DREG CALL SEND MOVLW A'h' MOVWF DREG CALL SEND MOVLW A'i' MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'i' MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'a' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'T' MOVWF DREG CALL SEND MOVLW A'e' MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A't' MOVWF DREG CALL SEND MOVLW D'5' ;Sets position of flash begin. MOVWF DREG CALL SEND MOVLW D'7' ;Sets position of flash end. MOVWF DREG CALL SEND MOVLW D'14' ;Sets position of message begin. Set to msg MOVWF DREG ; length for auto-center. CALL SEND GOTO START MSG8 MOVLW H'04' ;Scroll display. MOVWF DREG CALL SEND MOVLW A'T' ;The sale is Now on! with "Now" flashing MOVWF DREG CALL SEND MOVLW A'h' MOVWF DREG CALL SEND MOVLW A'e' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A'a' MOVWF DREG CALL SEND MOVLW A'l' MOVWF DREG CALL SEND MOVLW A'e' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'i' MOVWF DREG CALL SEND MOVLW A's' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'N' MOVWF DREG CALL SEND MOVLW A'o' MOVWF DREG CALL SEND MOVLW A'w' MOVWF DREG CALL SEND MOVLW A' ' MOVWF DREG CALL SEND MOVLW A'o' MOVWF DREG CALL SEND MOVLW A'n' MOVWF DREG CALL SEND MOVLW A'!' MOVWF DREG CALL SEND MOVLW H'FF' ;This seperates the main message from the flashing MOVWF DREG ; message. If transition effects are used, you must CALL SEND ; wait until transition is complete before sending ; flash message. MOVLW H'02' MOVWF DREG CALL SEND MOVLW D'12' MOVWF DREG CALL SEND MOVLW A'N' MOVWF DREG CALL SEND MOVLW A'o' MOVWF DREG CALL SEND MOVLW A'w' MOVWF DREG CALL SEND GOTO START ; Message 9 is a routine to enable the Infoglobe base for an additional 45 seconds, ; so that it can display date, time, and an additional message that it sometimes does, ; like "Good Morning" while in scan mode. MSG9 BTFSS STAT,SCAN_MODE ;Bypass if not in scan mode. GOTO BROWSE_MODE BCF PORTA,BASE_DISABLE ;Enable base IR LED. MOVLW D'135' ;Sets time base is enabled for time messages. MOVWF LCVR1 ;3 counts per second. BT_LP1 MOVLW D'255' MOVWF LCVR2 BT_LP2 MOVLW D'255' MOVWF LCVR3 BT_LP3 BTFSS PORTB,PUSHBUTTON_N GOTO EXIT_TIMER DECFSZ LCVR3,F GOTO BT_LP3 DECFSZ LCVR2,F GOTO BT_LP2 DECFSZ LCVR1,F GOTO BT_LP1 GOTO START END