;N.B. all sub routines must RETURN with memory BANK 0 selected ;N.B. lower and higher nibbles are LCD nibbles, but they are stored in two bytes ;because bytes also contain status of LCD_E and LCD_RS signals #include ; __CONFIG(_HS_OSC & _WDT_OFF & _MCLRE_OFF & _BOREN_OFF & _LVP_OFF & _CP_OFF); org 0x0000 goto MAIN_INIT org 0x0004 goto MY_INTERRUPT_HANDLER; ; ;--- MY_FLAGS --- #define NLT 7 ;not latch test #define LE2 6 ;7Seg nummer 2 #define LE1 5 ;7Seg nummer 1 #define LE0 4 ;7Seg nummer 0 #define STARTSTOP 0 ;STARTSTOP-trigger (both) ;-- MY_ERRORS bits -- #define OVERFLOW 0 ;Math overflow #define UNDERFLOW 1 ;Math negative value (underflow) #define DIV0 2 ;Division by zero #define BIGCAP 3 ;Capacitance overflow ; ; ;binary constants #define b00000000 0x00 #define b00000001 0x01 #define b00000010 0x02 #define b00000011 0x03 #define b00000100 0x04 #define b00000101 0x05 #define b00000110 0x06 #define b00000111 0x07 #define b00001000 0x08 #define b00001010 0x0A #define b00001111 0x0f #define b00010000 0x10 #define b00011000 0x18 #define b00011111 0x1F #define b00100000 0x20 #define b00100111 0x27 #define b00110000 0x30 #define b00110110 0x36 #define b00111011 0x3B #define b01000000 0x40 #define b01000010 0x42 #define b01010101 0x55 #define b01100000 0x60 #define b01100100 0x64 #define b01110000 0x70 #define b01111001 0x79 #define b01111111 0x7F #define b10000000 0x80 #define b10000110 0x86 #define b10010110 0x96 #define b10011000 0x98 #define b10011010 0x9A #define b10100000 0xA0 #define b10101010 0xAA #define b10110000 0xB0 #define b11000101 0xC5 #define b11001001 0xC9 #define b11001010 0xCA #define b11000000 0xC0 #define b11010000 0xD0 #define b11100001 0xE1 #define b11100000 0xE0 #define b11101000 0xE8 #define b11110000 0xF0 #define b11110101 0xF5 #define b11110110 0xF6 #define b11111001 0xF9 #define b11111111 0xFF; ; ;Timer constants #define TMR_DELTA 0xF0 ;start at: 255 - x, overflow on 255+1 #define SEC_CNT_OUTER_LOOP_CNT 0x20 #define BUZZER_LENGTH 0xF6 ; ; ;RAM data variables bank 0 cblock 0x20 ;bank 0x20, 80 bytes general purpose register LED7_0 LED7_1 LED7_2 W_TEMP STATUS_TEMP MY_ERRORS MY_FLAGS MY_MEASUREMENT CNT_VAR DLY_VAR CNT0 ;used by delay loops CNT1 ;used by delay loops CNT2 ;used by delay loops CNT3 ;used by delay loops TMR1IF_C1 ;TMR1IF_C1...0 16 bits unsigend int: number of timer1 time-outs TMR1IF_C0 CNT_RW ;number of items in LCD_BUF LCD_TMP ;buffer for tmp lcd data CAP_NR1 ;CAP_NR1...0 16 bit capture number CAP_NR0 MATH_BS ;number of bits shifted CNT_BUZZ ;buzzer counter endc; ; MAIN_INIT: ;--- select bank 0 --- BCF STATUS, RP0; BCF STATUS, RP1; BCF MY_ERRORS, UNDERFLOW CLRF PORTA ;Initialize PORTA by setting output data latches MOVLW 0x07 ;Turn comparators off and MOVWF CMCON ;enable pins for I/O ;functions CLRF PORTB; CLRF MY_FLAGS CLRF W_TEMP CLRF STATUS_TEMP CLRF CNT_RW CLRF LCD_TMP CLRF DLY_VAR CLRF CNT0 CLRF CNT1 CLRF CNT2 CLRF CNT3 ;--- select bank 1 --- BSF STATUS, RP0 CLRF INTCON ;GIE PEIE T0IE INTE RBIE T0IF INTF RBIF CLRF PIE1 ;EEIE CMIE RCIE TXIE xxx CCP1IE TMR2IE TMR1IE MOVLW b11001001 ;RA1, RA2,RA4 and RA5 as outputs, RA0 and RA3 as inputs MOVWF TRISA ;TRISA, bank 1 MOVLW b00000000 ;RB0...RB7 as outputs MOVWF TRISB ;TRISB, bank 1 ;--- select bank 0 --- BCF STATUS, RP0 ; CLRF PIR1 ;EEIF CMIF RCIF TXIF xxx CCP1IF TMR2IF TMR1IF MOVLW b01111111 MOVWF PORTB MOVLW 0x02 ;wait 2 seconds; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_sec MOVLW 0x00 MOVWF LED7_0 MOVWF LED7_1 MOVWF LED7_2 BCF MY_ERRORS, OVERFLOW MAIN_LOOP_FUN: call display_LEDS call increment_LEDS MOVLW 0x05 ;wait 5 msec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_msec BTFSS MY_ERRORS, OVERFLOW GOTO MAIN_LOOP_FUN BCF MY_ERRORS, OVERFLOW MAIN_LOOP_FUN10: call display_LEDS call increment_LEDS10 MOVLW 0x32 ;wait x msec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_msec BTFSS MY_ERRORS, OVERFLOW GOTO MAIN_LOOP_FUN10 BCF MY_ERRORS, OVERFLOW MAIN_LOOP_FUN100: call display_LEDS call increment_LEDS100 MOVLW 0xFF ;wait x msec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_msec BTFSS MY_ERRORS, OVERFLOW GOTO MAIN_LOOP_FUN100 ;BSF PORTA, RA1 MOVLW 0x01 ;wait 1 sec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_sec BCF PORTA, RA1 BCF MY_ERRORS, OVERFLOW game_init: call buzz_short BCF MY_FLAGS, STARTSTOP MOVLW 0x00 MOVWF LED7_0 MOVWF LED7_1 MOVWF LED7_2 ;; ; MAIN_LOOP: call display_LEDS BTFSC MY_FLAGS, STARTSTOP ; if not set? running GOTO wait_for_new_game_init call increment_LEDS MOVLW 0x01 ;wait 1 sec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_sec BTFSS MY_ERRORS, OVERFLOW GOTO MAIN_LOOP call buzz_short wait_for_new_game_init: call wait_short BCF MY_FLAGS, STARTSTOP ;clear startstop flag wait_for_new_game: BCF PORTA, RA1 MOVLW 0x01 ;wait 1 sec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_sec BTFSS MY_FLAGS, STARTSTOP GOTO wait_for_new_game GOTO game_init buzz_short: BSF PORTA, RA1 MOVLW 0xFF ;wait x msec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_msec BCF PORTA, RA1 RETURN wait_short: MOVLW 0xFF ;wait x msec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_msec MOVLW 0xFF ;wait x msec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_msec RETURN ;--- end MAIN_LOOP --- ; ; display_LEDS: display_7segment_0: MOVLW b11110000 IORWF LED7_0, 0 ;IORWF f,d ;Inclusive OR the W register with register ?f?. ;If ?d? is ?0?, the result is placed in the W register. ;If ?d? is ?1?, the result is placed back in register ?f?. MOVWF PORTB CALL wait_data_prepare_time BCF PORTB, LE0 ;Disable latch 0, data is now read by 4511 CALL wait_data_well_time BSF PORTB, LE0 ;Enable latch 0 CALL wait_data_hold_time display_7segment_1: MOVLW b11110000 IORWF LED7_1, 0 ;IORWF f,d MOVWF PORTB CALL wait_data_prepare_time BCF PORTB, LE1 ;Disable latch 1, data is now read by 4511 CALL wait_data_well_time BSF PORTB, LE1 ;Enable latch 1 CALL wait_data_hold_time display_7segment_2: MOVLW b11110000 IORWF LED7_2, 0 ;IORWF f,d MOVWF PORTB CALL wait_data_prepare_time BCF PORTB, LE2 ;Disable latch 2, data is now read by 4511 CALL wait_data_well_time BSF PORTB, LE2 ;Enable latch 2 CALL wait_data_hold_time RETURN; ; increment_LEDS: increment_LED7_0: INCF LED7_0, 1 ;INCF f,d ;The contents of register ?f? are incremented. ;If ?d? is ?0?, the result is placed in the W register. ;If ?d? is ?1?, the result is placed back in register ?f?. MOVF LED7_0, 0 MOVLW 0xF6 ADDWF LED7_0, 0 ;ADDWF f,d ;Add the contents of the W register with register ?f?. ;If ?d? is ?0?, the result is stored in the W register. ;If ?d? is ?1?, the result is stored back in register ?f?. BTFSS STATUS, C GOTO increment_LEDS_end MOVLW 0x00 MOVWF LED7_0 increment_LED7_1: INCF LED7_1, 1 ;INCF f,d MOVLW 0xFA ADDWF LED7_1, 0 ;ADDWF f,d BTFSS STATUS, C GOTO increment_LEDS_end MOVLW 0x00 MOVWF LED7_1 increment_LED7_2: INCF LED7_2, 1 MOVLW 0xF6 ADDWF LED7_2, 0 ;ADDWF f,d BTFSS STATUS, C GOTO increment_LEDS_end MOVLW 0x00 MOVWF LED7_2 BSF MY_ERRORS, OVERFLOW increment_LEDS_end: RETURN increment_LEDS100: call increment_LED7_2 RETURN increment_LEDS10: call increment_LED7_1 RETURN; ; wait_data_prepare_time: MOVLW 0x02 ;wait 2 usec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_usec return; ; wait_data_hold_time: MOVLW 0x5 ;wait 5 usec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_usec return; ; wait_data_well_time: MOVLW 0x03 ;wait 3 usec; MOVWF DLY_VAR ;DLY_VAR bank 0 CALL delay_usec return; ; delay_sec: ;20 Mhz MOVF DLY_VAR, 0 ;1 cycle, move content of DLY_VAR to W MOVWF CNT0 ;1 cycle delay_sec_cnt0: BCF PORTA, RA1 MOVLW SEC_CNT_OUTER_LOOP_CNT;1 cycle 32 MOVWF CNT1 ;1 cycle delay_sec_cnt1: MOVLW 0x64 ;1 cycle 100 MOVWF CNT2 ;1 cycle delay_sec_cnt2: MOVLW 0xC8 ;1 cycle 200 MOVWF CNT3 ;1 cycle delay_sec_cnt3: BTFSC PORTA, RA0 ;if 0, then switch 2 is closed, short cut to ground, alarm! GOTO delay_sec_check_switch3 BSF PORTA, RA1 MOVLW BUZZER_LENGTH MOVF CNT_BUZZ delay_sec_check_switch3: ;6 cycles for alarm handling: test bit (2), goto (2) (before or after) set bit (2) ; switch 3? BTFSC PORTA, RA3 ;if 0, then switch 3 is closed, start/stop is pressed GOTO delay_sec_after_startstop delay_sec_startstop: BSF MY_FLAGS, STARTSTOP delay_sec_after_startstop: ;6 cycles for alarm handling: test bit (2), goto (2) (before or after) set bit (2) nop ;1 cycle decfsz CNT3, 1 ;1 cycle goto delay_sec_cnt3 ;2 cycles decfsz CNT2, 1 ;1 cycle goto delay_sec_cnt2 ;2 cycles decfsz CNT1, 1 ;1 cycle goto delay_sec_cnt1 ;2 cycles decfsz CNT0, 1 ;2 cycles goto delay_sec_cnt0 ;1 cycle RETURN; ; delay_msec: ;20 Mhz MOVF DLY_VAR, 0 ;1 cycle, move content of DLY_VAR to W MOVWF CNT0 ;1 cycle delay_msec_cnt0: MOVLW 0x28 ;1 cycle 40 MOVWF CNT1 ;1 cycle delay_msec_cnt1: MOVLW 0x28 ;1 cycle 40 MOVWF CNT2 ;1 cycle delay_msec_cnt2: decfsz CNT2 ;1 cycle goto delay_msec_cnt2 ;2 cycles decfsz CNT1 ;1 cycle goto delay_msec_cnt1 ;2 cycles decfsz CNT0 ;2 cycles goto delay_msec_cnt0 ;1 cycle RETURN; ; delay_usec: ;20 Mhz MOVF DLY_VAR, 0 ;1 cycle, move content of DLY_VAR to W MOVWF CNT0 ;1 cycle delay_usec_cnt0: nop ;1 cycle nop ;1 cycle decfsz CNT0 ;2 cycles goto delay_usec_cnt0 ;1 cycle RETURN; ; comparator_interrupt: ;--- BANK 0 --- BCF STATUS, RP0 BCF STATUS, RP1 BCF PIR1, CMIF ;reset interrupt CMIF RETURN; ; timer0_overflow: ;--- BANK 0 --- BCF STATUS, RP0 ;select bank 0 BCF STATUS, RP1 ;select bank 0 BCF INTCON, T0IF ;reset interrupt T0IF RETURN; ; timer1_overflow: ;--- BANK 0 --- BCF STATUS, RP0 BCF STATUS, RP1 BCF PIR1, TMR1IF ;reset interrupt TMR1IF RETURN; ; capture_interrupt: ;--- BANK 0 --- BCF STATUS, RP0 BCF STATUS, RP1 BCF PIR1, CCP1IF ;bank 0, reset interrupt CCP1IF return; ; MY_INTERRUPT_HANDLER: MOVWF W_TEMP ;copy W to temp register, could be in any bank swapf STATUS,W ;swap status to be saved into W BCF STATUS,RP0 ;change to bank 0 regardless of current bank MOVWF STATUS_TEMP ;save status to bank 0 register ;--- ISR --- btfsc PIR1, CCP1IF CALL capture_interrupt ;A TMR1 register capture occurred (must be cleared in software) btfsc PIR1, CMIF CALL comparator_interrupt ;Comparator output has changed btfsc PIR1, TMR1IF CALL timer1_overflow ;TMR1 register overflowed (must be cleared in software) ;--- BANK 1 --- BSF STATUS, RP0 ;select bank 1 btfsc INTCON, T0IF ;timer0 overflow? skip if clear CALL timer0_overflow ; ;--- end ISR --- swapf STATUS_TEMP,W ;swap STATUS_TEMP register into W, sets bank to original state MOVWF STATUS ;move W into STATUS register swapf W_TEMP,F ;swap W_TEMP swapf W_TEMP,W ;swap W_TEMP into W retfie; end