;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; thegame2.asm ; ; By Adriaan Van Nuffel and Robin Reusens ; afvnuffe@vub.ac.be, rreusens@vub.ac.be ; ; 10 may 2005 ; ; This is the main program for the Saloon Shootout game, by Robin and Adriaan. ; To test the board, you can use three testing programs: ; - Digit_test ; - Relays_test ; - light_sensor_test ; This program uses the same subroutines, altough most have been changed a ; bit. ; ; The goal of the game is getting as many points as possible, by shooting ; the cowboys that appear behind the windows. ; ; These cowboys have to carry these LDRS: ; Mr.1: RB0 - RD2 ; Mr.2: RB1 - RD3 ; Mr.3: RB2 - RD4 ; Mr.4: RB3 - RD5 ; Mr.5: RB4 - RD6 ; Mr.6: RB5 - RD7 ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LIST P=PIC16F877A #INCLUDE P16F877A.INC __CONFIG _CP_OFF & _DEBUG_OFF & _LVP_OFF & _PWRTE_ON & _WDT_OFF & _BODEN_OFF & _XT_OSC ORG 0 ; *** Giving names to the used registers *** TIMER1 EQU H'20' ; For the Delay routine TIMER2 EQU H'21' SH_REG1 EQU H'22' ; Used for accessing the shift registers (SH_REG1 controls SH_REG2 EQU H'23' ; the left digit, SH_REG2 the right one) INSDIG_COUNTER EQU H'24' ; Used as counter in the INSERDIGITS subroutine SCORE_DEC1 EQU H'25' ; Used in main loop to test the binary to decimal conversion SCORE_DEC2 EQU H'26' A_SH_REG EQU H'27' ; Used for the conversion to a decimal number of the score A_DEC EQU H'28' ; Idem. RESET_BIT EQU H'29' ; To check if the game is ended. LDRS EQU H'2A' ; Used to check the status of the LDRs CLOCK EQU H'2B' COWBOY_STATS EQU H'2C' ; 1 = visible / 0 = withdrawn COWBOY_AGE EQU H'2D' ; 1 = time to go, 0 = he can stay a little longer... DA_CLOCK_NUMBAH EQU H'2E' ; The name says it all! RANDOM EQU H'30' ; For the random sequence generator DECIDE EQU H'31' ; To decide which cowboy should be triggered... BIT_0 EQU H'32' ; For the PRBS random method BIT_4 EQU H'33' DIG_0 EQU H'70' ; The digits DIG_1 EQU H'71' DIG_2 EQU H'72' DIG_3 EQU H'73' DIG_4 EQU H'74' DIG_5 EQU H'75' DIG_6 EQU H'76' DIG_7 EQU H'77' DIG_8 EQU H'78' DIG_9 EQU H'79' ; *** Configure all pins *** RESET ; Outputs: ; ; RB5-RB0 (Actuation of the relays) ; RA0 -> DS Shift Register 1 (Data Send) ; RA1 -> DS Sh Reg 2 ; RA2 -> OE Sh Reg 1&2 (Output Enable, active low) ; RA3 -> ST_CP Sh Reg 1&2 (Storage register clock pulse) ; RA4 -> SH_CP Sh Reg 1&2 (Shift register clock pulse) ; ; Inputs: ; ; RD2-RD7 (From comparators) ; RD1 -> start game button ; ; Not used: ; ; RA5, RE0-RE2, RC0-RC3, RC4-RC7, RD0 (= 13 pins) ; RB6 & RB7 are only connected to the programming pins ; BCF STATUS, RP0 ; Go to Bank 0 BCF STATUS, RP1 CLRF PORTA ; Initialize Port A (See example datasheet p 41) CLRF PORTB ; " " B CLRF PORTD ; " " D (I'm not sure if all this is necessary...) BSF STATUS, RP0 ; Go to Bank 1 MOVLW B'00000110' ; Adjust the settings in ADCON1, to make all the pins MOVWF ADCON1 ; of port A digital I/O. See datasheet p.128 MOVLW B'11000000' ; All pins of A are outputs, except RA7 and RA6, which MOVWF TRISA ; are non-existant CLRF TRISB ; All pins of port B are outputs. BCF TRISE, PSPMODE ; Port D pins are digital I/O. (datasheet p. 50) MOVLW B'11111111' ; And they are all inputs MOVWF TRISD ; *** Defining the digits *** BCF STATUS, RP0 ; Go to Bank 0 MOVLW B'01111011' MOVWF DIG_0 MOVLW B'01100000' MOVWF DIG_1 MOVLW B'00110111' MOVWF DIG_2 MOVLW B'01110110' MOVWF DIG_3 MOVLW B'01101100' MOVWF DIG_4 MOVLW B'01011110' MOVWF DIG_5 MOVLW B'01011111' MOVWF DIG_6 MOVLW B'01110000' MOVWF DIG_7 MOVLW B'01111111' MOVWF DIG_8 MOVLW B'01111110' MOVWF DIG_9 CLRF SCORE_DEC1 CLRF SCORE_DEC2 MOVLW B'10100111' ; The random start number... (arbitrary chosen) MOVWF RANDOM ; *** Main part *** MOVLW H'00' MOVWF RESET_BIT MOVLW H'FF' MOVWF CLOCK MOVWF DA_CLOCK_NUMBAH BTFSC RANDOM, H'0' ; The random routine gets 'warmed up' BSF BIT_0, H'0' BTFSC RANDOM, H'5' BSF BIT_4, H'0' MOVF BIT_0, 0 XORWF BIT_4, 1 BCF STATUS, C BTFSC BIT_4, H'0' BSF STATUS, C RRF RANDOM, 1 BCF BIT_0, H'0' BCF BIT_4, H'0' MOVLW B'01111101' ; = 'A' MOVWF SH_REG1 MOVF DIG_3, 0 ; = '3' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY BSF PORTA,H'2' ; Output disable: lettin' it blink a bit... CALL DELAY BCF PORTA,H'2' ; Output enable again... CALL DELAY CALL DELAY BSF PORTA,H'2' ; Output disable: lettin' it blink a bit... CALL DELAY BCF PORTA,H'2' ; Output enable again... MOVLW B'00000000' ; = '' MOVWF SH_REG1 MOVLW B'00000000' ; = '' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'00000000' ; = '' MOVWF SH_REG1 MOVLW B'00000101' ; = 'r' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'00000101' ; = 'r' MOVWF SH_REG1 MOVLW B'01000111' ; = 'o' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'01000111' ; = 'o' MOVWF SH_REG1 MOVLW B'01001111' ; = 'b' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'01001111' ; = 'b' MOVWF SH_REG1 MOVLW B'00000001' ; = 'i' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'00000001' ; = 'i' MOVWF SH_REG1 MOVLW B'01000101' ; = 'n' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'01000101' ; = 'n' MOVWF SH_REG1 MOVLW B'00000000' ; = '' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY MOVLW B'00000000' ; = '' MOVWF SH_REG1 MOVLW B'00000000' ; = '' MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY CALL DELAY mainloop DECFSZ CLOCK, 1 ; Decrease the clock, until it has reached 00000000 CALL TRIGGER_COWBOY ; which means that a certain amount of time has passed. Time for action! CALL REFRESH_COWBOYS GOTO mainloop ; *** TRIGGER_COWBOY ; This routine decides which cowboys have to appear, and which have to disseappear...! TRIGGER_COWBOY MOVF DA_CLOCK_NUMBAH, 0 ; reset the clock to the right time! MOVWF CLOCK BTFSC RANDOM, H'0' BSF BIT_0, H'0' BTFSC RANDOM, H'5' BSF BIT_4, H'0' MOVF BIT_0, 0 XORWF BIT_4, 1 BCF STATUS, C BTFSC BIT_4, H'0' BSF STATUS, C RRF RANDOM, 1 BCF BIT_0, H'0' BCF BIT_4, H'0' BTFSC RANDOM, H'0' BSF BIT_0, H'0' BTFSC RANDOM, H'5' BSF BIT_4, H'0' MOVF BIT_0, 0 XORWF BIT_4, 1 BCF STATUS, C BTFSC BIT_4, H'0' BSF STATUS, C RRF RANDOM, 1 BCF BIT_0, H'0' BCF BIT_4, H'0' BTFSC RANDOM, H'0' BSF BIT_0, H'0' BTFSC RANDOM, H'5' BSF BIT_4, H'0' MOVF BIT_0, 0 XORWF BIT_4, 1 BCF STATUS, C BTFSC BIT_4, H'0' BSF STATUS, C RRF RANDOM, 1 BCF BIT_0, H'0' BCF BIT_4, H'0' MOVF RANDOM, 0 MOVWF DECIDE MOVLW B'00000111' ANDWF DECIDE, 1 MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_7, 0 MOVWF SH_REG2 CALL INSERTDIGITS test_combination_0 MOVLW B'00000000' ; In case the last three bits of RANDOM are 000, SUBWF DECIDE, 0 ; cowboy 1 will become visible. BTFSS STATUS, Z GOTO test_combination_1 BSF COWBOY_STATS, H'00' MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_1, 0 MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY GOTO end_combinations_tests test_combination_1 MOVLW B'00000001' ; In case the last three bits of RANDOM are 001, SUBWF DECIDE, 0 ; cowboy 2 will become visible. BTFSS STATUS, Z GOTO test_combination_2 BSF COWBOY_STATS, H'01' MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_2, 0 MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY GOTO end_combinations_tests test_combination_2 MOVLW B'00000010' ; In case the last three bits of RANDOM are 010, SUBWF DECIDE, 0 ; cowboy 3 will become visible. BTFSS STATUS, Z GOTO test_combination_3 BSF COWBOY_STATS, H'02' MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_3, 0 MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY GOTO end_combinations_tests test_combination_3 MOVLW B'00000011' ; In case the last three bits of RANDOM are 011, SUBWF DECIDE, 0 ; cowboy 4 will become visible. BTFSS STATUS, Z GOTO test_combination_4 BSF COWBOY_STATS, H'03' MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_4, 0 MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY GOTO end_combinations_tests test_combination_4 MOVLW B'00000100' ; In case the last three bits of RANDOM are 100, SUBWF DECIDE, 0 ; cowboy 5 will become visible. BTFSS STATUS, Z GOTO test_combination_5 BSF COWBOY_STATS, H'04' MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_5, 0 MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY GOTO end_combinations_tests test_combination_5 MOVLW B'00000101' ; In case the last three bits of RANDOM are 101, SUBWF DECIDE, 0 ; cowboy 6 will become visible. BTFSS STATUS, Z GOTO end_combinations_tests ; !!! BSF COWBOY_STATS, H'05' MOVF DIG_0, 0 MOVWF SH_REG1 MOVF DIG_6, 0 MOVWF SH_REG2 CALL INSERTDIGITS CALL DELAY end_combinations_tests ; Indeed, in case the last three bits were 110 or 111, nothing is changed. CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY ; Now we're gonna check which cowboy's time has passed... ; The first time a cowboy is checked: he is not removed, but ; the second time, he'll be removed. To achieve this, the ; first time, his 'age' (COWBOY_AGE) bit is set. ; When he's removed, his age bit goes down again. ; check_mr1 BTFSS COWBOY_STATS, H'0' GOTO check_mr2 BTFSS COWBOY_AGE, H'0' GOTO its_time_to_go_1 BSF COWBOY_AGE, H'0' GOTO check_mr2 its_time_to_go_1 BCF COWBOY_STATS, H'0' BCF COWBOY_AGE, H'0' check_mr2 BTFSS COWBOY_STATS, H'1' GOTO check_mr3 BTFSS COWBOY_AGE, H'1' GOTO its_time_to_go_2 BSF COWBOY_AGE, H'1' GOTO check_mr3 its_time_to_go_2 BCF COWBOY_STATS, H'1' BCF COWBOY_AGE, H'1' check_mr3 BTFSS COWBOY_STATS, H'2' GOTO check_mr4 BTFSS COWBOY_AGE, H'2' GOTO its_time_to_go_3 BSF COWBOY_AGE, H'2' GOTO check_mr4 its_time_to_go_3 BCF COWBOY_STATS, H'2' BCF COWBOY_AGE, H'2' check_mr4 BTFSS COWBOY_STATS, H'3' GOTO check_mr5 BTFSS COWBOY_AGE, H'3' GOTO its_time_to_go_4 BSF COWBOY_AGE, H'3' GOTO check_mr5 its_time_to_go_4 BCF COWBOY_STATS, H'3' BCF COWBOY_AGE, H'3' check_mr5 BTFSS COWBOY_STATS, H'4' GOTO check_mr6 BTFSS COWBOY_AGE, H'4' GOTO its_time_to_go_5 BSF COWBOY_AGE, H'4' GOTO check_mr6 its_time_to_go_5 BCF COWBOY_STATS, H'4' BCF COWBOY_AGE, H'4' check_mr6 BTFSS COWBOY_STATS, H'5' GOTO end_agecheck BTFSS COWBOY_AGE, H'5' GOTO its_time_to_go_6 BSF COWBOY_AGE, H'5' GOTO end_agecheck its_time_to_go_6 BCF COWBOY_STATS, H'5' BCF COWBOY_AGE, H'5' end_agecheck RETURN ; End of TRIGGER_COWBOY subroutine ; *** REFRESH_COWBOYS REFRESH_COWBOYS MOVF COWBOY_STATS, 0 MOVWF PORTB RETURN ; *** INCSCORE: This subroutine increments the score. ; The two decimals of the score are calculated seperately, to make ; the conversion to decimal easier. SCORE_DEC1 is the right decimal, ; SCORE_DEC2 the left one. (This is the opposite of the SH_REG's, just ; to make it easier.) ; Each time you make a hit, the clock gets 'faster' INCSCORE MOVLW H'02' SUBWF DA_CLOCK_NUMBAH, 1 ; Tighten up the clock INCF SCORE_DEC1, 1 MOVF SCORE_DEC1, 0 SUBLW H'0A' ; When the first decimal of the score has become 10, BTFSS STATUS, Z ; the Z-bit will be set. GOTO ietsverder CLRF SCORE_DEC1 ; We have to put the first decimal then back to 0, INCF SCORE_DEC2, 1 ; and increment the second decimal. ietsverder RETURN ; *** SHOWSCORE: This subroutine calls CONVERTSCORE twice to check for each ; score_decimal which digit should be displayed. Finally, they get displayed ; by calling INSERTDIGITS (automatically) SHOWSCORE MOVF SCORE_DEC1,0 MOVWF A_DEC CALL CONVERTSCORE MOVF A_SH_REG, 0 MOVWF SH_REG2 MOVF SCORE_DEC2, 0 MOVWF A_DEC CALL CONVERTSCORE MOVF A_SH_REG, 0 MOVWF SH_REG1 CALL INSERTDIGITS RETURN ; *** CONVERTSCORE: This subroutine takes care of the conversion to decimal of the score. ; We simply check for both decimals with which DIG_... they correspond. CONVERTSCORE test_nul MOVLW H'00' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_een MOVF DIG_0, 0 MOVWF A_SH_REG GOTO einde_van_testen test_een MOVLW H'01' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_twee MOVF DIG_1, 0 MOVWF A_SH_REG GOTO einde_van_testen test_twee MOVLW H'02' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_drie MOVF DIG_2, 0 MOVWF A_SH_REG GOTO einde_van_testen test_drie MOVLW H'03' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_vier MOVF DIG_3, 0 MOVWF A_SH_REG GOTO einde_van_testen test_vier MOVLW H'04' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_vijf MOVF DIG_4, 0 MOVWF A_SH_REG GOTO einde_van_testen test_vijf MOVLW H'05' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_zes MOVF DIG_5, 0 MOVWF A_SH_REG GOTO einde_van_testen test_zes MOVLW H'06' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_zeven MOVF DIG_6, 0 MOVWF A_SH_REG GOTO einde_van_testen test_zeven MOVLW H'07' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_acht MOVF DIG_7, 0 MOVWF A_SH_REG GOTO einde_van_testen test_acht MOVLW H'08' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO test_negen MOVF DIG_8, 0 MOVWF A_SH_REG GOTO einde_van_testen test_negen MOVLW H'09' SUBWF A_DEC, 0 BTFSS STATUS, Z GOTO einde_van_testen MOVF DIG_9, 0 MOVWF A_SH_REG GOTO einde_van_testen einde_van_testen RETURN ; *** INSERTDIGITS: This subroutine 'inserts' the correct bits in the shift registers *** INSERTDIGITS BCF STATUS, RP0 ; Go to Bank 0 (in case we weren't there yet...) BCF STATUS, RP1 BSF INSDIG_COUNTER, H'3' ; 8 is the value, and we stick it in a counter! insdigloop CLRF PORTA ; (Remark: OE is active low, so clearing port A will enable the output) RLF SH_REG1,1 ; Check the next bit BTFSC STATUS, C ; and if it's set, then set the RA0 BSF PORTA, H'0' ; (which is connected to the DS of the first shift register). RLF SH_REG2,1 ; Now we do the same for the second shift register. BTFSC STATUS, C BSF PORTA, H'1' ; RA1 is connected to the DS of the second shift register. BSF PORTA, H'4' ; Then we give a pulse on the clock of the shift registers (SH_CP) DECFSZ INSDIG_COUNTER, 1 GOTO insdigloop BSF PORTA, H'3' ; Now we give a pulse on the clock of the storage registers (ST_CP) to show the result. RETURN ; End of subroutine ; *** Delay routine *** DELAY CLRWDT MOVLW D'255' MOVWF TIMER1 DELAY2 MOVLW D'255' MOVWF TIMER2 DECFSZ TIMER2,F GOTO $-1 DECFSZ TIMER1,F GOTO DELAY2 RETLW 0 END ; End of source code.