;************************************************************************** ; FILE: whack-a-mole.asm * ; CONTENTS: "Whack-a-Mole" * ; COPYRIGHT: MadLab Ltd. 2005 * ; AUTHOR: James Hutchby * ; UPDATED: 28/03/05 * ;************************************************************************** list p=12F508 ; list p=12C508A ifdef __12F508 include "p12f508.inc" endif ifdef __12C508A include "p12c508a.inc" endif __config _IntRC_OSC & _WDT_ON & _MCLRE_OFF & _CP_ON __idlocs h'EF10' errorlevel -305 ;************************************************************************** ; * ; Specification * ; * ;************************************************************************** ; power-up self-test - all LEDs flash twice ; S1 (*) -> reaction game, single LED ; S2 (**) -> reaction game, double LED ; S3 (***) -> memory game, single LED ; S4 (****) -> memory game, double LED ; reaction game: ; single or double LED lit at random, ; player must press corresponding button(s) ; if wrong button pressed player loses ; LEDs flash alternately to signal player lost ; speed increases and time to react decreases as game progresses ; memory game: ; displays random sequence of single or double LED ; player must press corresponding buttons in same order ; double flash signals correct sequence entered ; if sequence entered incorrectly player loses ; LEDs flash alternately to signal player lost ; sequence length increases as game progresses (from 3 to 8) ; extra flash indicates increase in sequence length ; sleeps after ~1 minute of inactivity, hold down button to wake ;************************************************************************** ; * ; Port assignments * ; * ;************************************************************************** GPIO_IN equ b'111111' ; GPIO IN status GPIO_OUT equ b'001011' ; GPIO OUT status BUTTON1 equ 5 ; button 1 BUTTON2 equ 0 ; button 2 BUTTON3 equ 3 ; button 3 BUTTON4 equ 1 ; button 4 LED1 equ b'011011' ; LED1 LED2 equ b'001111' ; LED2 LED3 equ b'101111' ; LED3 LED4 equ b'111011' ; LED4 ;************************************************************************** ; * ; Constants and timings * ; * ;************************************************************************** CLOCK equ d'4000000' ; processor clock frequency in Hz POLL equ d'25' ; poll period in ms TIMEOUT1 equ d'50' ; reaction game timeout TIMEOUT2 equ d'100' ; memory game timeout STEPS1 equ d'3' ; memory game start steps STEPS2 equ d'8' ; memory game end steps ;************************************************************************** ; * ; File register usage * ; * ;************************************************************************** RAM equ h'07' MAX set h'20' cblock RAM flags ; various flags leds ; multiplexed LEDs buttons, buttons_ ; buttons pressed sequence:STEPS2 ; memory sequence steps ; memory steps off ; LED off timer rand:2 ; random number timeout ; timer count, repeat ; scratch counters work1, work2 ; work registers RAM_ endc if RAM_ > MAX error "File register usage overflow" endif ; flags RELEASE equ 0 ; set if waiting for button release DOUBLE equ 1 ; set if two LEDS on ;************************************************************************** ; * ; Macros * ; * ;************************************************************************** routine macro label ; routine label endm table macro label ; define lookup table label addwf PCL endm entry macro value ; define table entry retlw value endm index macro label ; index lookup table call label endm jump macro label ; jump through table goto label endm tstw macro ; test w register iorlw 0 endm movff macro f1,f2 ; move file to file movfw f1 movwf f2 endm movlf macro n,f ; move literal to file movlw n movwf f endm ;-------------------------------------------------------------------------- ; reset vector ;-------------------------------------------------------------------------- org 0 movwf OSCCAL goto main_entry ;************************************************************************** ; * ; Lookup tables * ; * ;************************************************************************** table masks entry b'0001' entry b'0010' entry b'0100' entry b'1000' ;************************************************************************** ; * ; Procedures * ; * ;************************************************************************** ;-------------------------------------------------------------------------- ; polls the pushbuttons, returns NZ flag set if any pushbutton pressed ;-------------------------------------------------------------------------- routine poll_buttons movlw GPIO_IN tris GPIO clrf buttons ; poll the buttons btfss GPIO,BUTTON1 bsf buttons,0 btfss GPIO,BUTTON2 bsf buttons,1 btfss GPIO,BUTTON3 bsf buttons,2 btfss GPIO,BUTTON4 bsf buttons,3 movlw GPIO_OUT ; re-initialise port tris GPIO movfw buttons retlw 0 ;-------------------------------------------------------------------------- ; waits, fed with the wait in ms in the w reg ;-------------------------------------------------------------------------- routine long_wait clrw routine wait_ms movwf work1 wait1 clrwdt led_ macro bit,LED local wait2 clrw btfsc leds,bit movlw LED movwf GPIO WAIT set CLOCK/(d'1000'*d'20'*d'4') movlf WAIT,work2 wait2 nop ; [4] nop ; [4] decfsz work2 ; [4] goto wait2 ; [8] endm led_ 0,LED1 led_ 1,LED2 led_ 2,LED3 led_ 3,LED4 decfsz work1 goto wait1 clrf GPIO retlw 0 ;-------------------------------------------------------------------------- ; generates a pseudo random number ;-------------------------------------------------------------------------- routine get_random movfw rand+0 iorwf rand+1,w bnz getr1 movfw TMR0 ; seed generator movwf rand+1 xorlw h'ff' movwf rand+0 getr1 rlf rand+0,w ; calculate next in sequence xorwf rand+0,w movwf work1 ; msb <= Q15 ^ Q14 swapf rand+1,w btfsc rand+0,4 xorlw h'80' ; msb <= Q12 ^ Q3 xorwf work1 rlf work1 rlf rand+1 rlf rand+0 ; << 1 + (Q15 ^ Q14 ^ Q12 ^ Q3) retlw 0 ;-------------------------------------------------------------------------- ; reaction game ;-------------------------------------------------------------------------- routine reaction_game clrf steps reac1 clrf leds bsf flags,RELEASE comf steps,w ; random delay andlw 3<<4 movwf count swapf count incf count reac2 call get_random movfw rand+0 call wait_ms decfsz count goto reac2 call get_random movfw rand+0 ; single LED xorwf TMR0,w andlw 3 index masks movwf 0 movfw rand+1 ; double LED andlw 3 index masks movwf work1 movlw h'ff'/3 subwf rand+0,w skpnc clrf work1 movfw work1 btfsc flags,DOUBLE iorwf 0 movff 0,leds movlf TIMEOUT1,timeout rrf steps,w andlw h'1f' subwf timeout reac3 movlw POLL call wait_ms call poll_buttons btfss flags,RELEASE goto reac4 skpnz bcf flags,RELEASE goto reac5 reac4 bz reac5 comf leds,w ; mis-match ? andwf buttons,w bnz lose ; lose if yes movfw leds ; match ? xorwf buttons,w bnz reac5 ; branch if not incf steps btfsc steps,6 decf steps goto reac1 reac5 decf timeout ; timeout ? bz lose ; lose if yes goto reac3 ;-------------------------------------------------------------------------- ; memory game ;-------------------------------------------------------------------------- routine memory_game movlf STEPS1<<4,steps memo1 movlf sequence,FSR ; generate and display random sequence swapf steps,w andlw h'0f' movwf count memo2 call get_random movfw rand+0 ; single LED xorwf TMR0,w andlw 3 index masks movwf 0 movfw rand+1 ; double LED andlw 3 index masks movwf work1 movlw h'ff'/3 subwf rand+0,w skpnc clrf work1 movfw work1 btfsc flags,DOUBLE iorwf 0 movff 0,leds decf count bz memo3 call long_wait call long_wait call long_wait clrf leds clrw call wait_ms incf FSR goto memo2 memo3 movlf sequence,FSR ; test entered sequence swapf steps,w andlw h'0f' movwf count memo4 movlf TIMEOUT2,timeout movlf d'20',off bsf flags,RELEASE memo5 movlw POLL call wait_ms call poll_buttons btfss flags,RELEASE goto memo6 skpnz bcf flags,RELEASE goto memo8 memo6 tstf off ; LEDs off after a short period skpz decf off tstf off skpnz clrf leds movfw buttons skpz movwf leds tstf buttons movlw d'20' skpz movwf off comf 0,w ; mis-match ? andwf buttons,w bnz lose ; lose if yes movfw 0 ; match ? xorwf buttons,w bnz memo8 ; branch if not incf FSR decfsz count goto memo4 call long_wait ; double flash movlf b'1111',leds movlw d'125' call wait_ms comf leds movlw d'100' call wait_ms comf leds movlw d'125' call wait_ms incf steps movfw steps ; next level ? andlw h'0f' xorlw d'5' bnz memo7 ; branch if not movlw h'f0' andwf steps movlw STEPS2<<4 xorwf steps,w bz memo7 movlw 1<<4 ; increase sequence length addwf steps comf leds ; extra flash movlw d'100' call wait_ms comf leds movlw d'125' call wait_ms comf leds movlw d'100' call wait_ms comf leds movlw d'125' call wait_ms memo7 clrf leds call long_wait call long_wait goto memo1 memo8 decf timeout ; timeout ? bz lose ; lose if yes goto memo5 ;-------------------------------------------------------------------------- ; power down ;-------------------------------------------------------------------------- routine power_down movlw b'00001100' ; prescale WDT 1:16, weak pull-ups option ; enabled, wake-up on pin change clrwdt movlw b'111111' ; read port tris GPIO movwf GPIO nop movfw GPIO sleep ; standby mode ;-------------------------------------------------------------------------- ; main entry point ;-------------------------------------------------------------------------- routine main_entry clrf GPIO ; initialise port movlw GPIO_OUT tris GPIO movlw b'00000000' ; prescale RTCC 1:2, weak pull-ups option ; enabled, wake on pin change btfsc STATUS,GPWUF ; wake-up on pin change ? goto main1 ; branch if yes movfw STATUS ; wake-up from sleep ? andlw (1<