;************************************************************* ;ELECTRONIC PING-PONG! ;This program drives the electronic ping-pong game, ;fixed speed, single mode of play. ;adapted as necessary for 16LF87 ;TJW 21.6.01. Rev. 31.12.08 Tested 1.1.09 ;************************************************************* ; ;Clock freq 800kHz approx (RC osc.) ;Port A 4 right paddle (ip) ; 3 left paddle (ip) ; 2 "out of play" led (op) ; 1 "Score Left" led (op) ; 0 "Score Right" led (op) ;Port B 7-0 "play" leds (all op) ; include p16f87.inc ;(change from 'F84A) ;Config Word: RC oscillator, WDT off, ; power-up timer on, code protect off list p=16F87 __CONFIG _CONFIG1, _EXTRC_CLKOUT & _WDT_OFF & _PWRTE_ON & _BODEN_OFF & _LVP_OFF ;bits listed in ascending order. ;Brown out reset must be off, as we run below its threshold ;No Interrupts used ; ;specify SFRs (now duplicates include file**) status equ 03 porta equ 05 trisa equ 05 portb equ 06 trisb equ 06 ; ;specify a constant led_durn equ 20 ;no. of time inner loop is iterated, hence ;time duration each led is lit. ; ;specify RAM locations (change from 'F84A) delcntr1 equ 20 ;used in 5ms delay SR delcntr2 equ 21 ;used in 500ms delay SR led_posn equ 22 ;holds current ball led posn. loop_cntr equ 23 ;preloaded with value led_durn for every ;led illumination, and counts down to 0 before ;ball moves on ; org 00 goto start ; ; **“Initialise” State** ; Initialise org 0010 start bsf status,5 ;select memory bank 1 bcf status,6 movlw B'00011000' movwf trisa ;port A according to above pattern movlw 00 movwf trisb ;all port B bits op ; movwf ansel ;xtra for new version*** bcf status,5 ;select bank 0 ; ;**”Wait”** State ;set up initial led patterns wait movlw 04 movwf porta ;switch on "out of play" led movlw 00 movwf portb ;all play leds off ; ;check that both paddles are clear before allowing play to commence btfss porta,4 ;right paddle pressed? goto wait ;yes, so wait btfss porta,3 ;left paddle pressed? goto wait ;yes, so wait ; ;now ready for action, now wait until paddle pressed wait1 btfss porta,4 ;right paddle pressed? goto r_to_l ;yes, so start play btfss porta,3 ;left paddle pressed? goto l_to_r ;yes, so start play goto wait1 ; ;**”Right-to-Left” State** ;play has started r_to_l movlw 00 ;switch off "out of play" movwf porta movlw 80 ;define ball start posn. movwf led_posn ;loop to here every time led is to change rtl_0 movlw led_durn movwf loop_cntr ;preset length of led illumination movf led_posn,w ;output new ball posn movwf portb ;loop to here n times for every led, where n = led_durn. ;Check for rule violations. Special conditions apply if ;ball is at start or end. rtl_1 btfss led_posn,7 ;is ball at start (ie posn 7)? goto rtl_2 ;no, so move on ;yes, it’s OK if right paddle still pressed, so don't test btfss porta,3 ;left paddle pressed? goto rt_myscore ;yes, so score goto rtlend rtl_2 btfss led_posn,0 ;is ball at end (ie posn 0)? goto rtl_3 ;no, so move on ;here if ball at end, left paddle can force direction change btfss porta,3 ;left paddle pressed? goto l_to_r ;yes, so change direction - **state exit** btfss porta,4 ;right paddle pressed? goto rt_yrscore ;yes, so left scores goto rtlend ;here if neither start nor end posn. rtl_3 btfss porta,4 ;right paddle pressed? goto score_left ; yes, so score btfss porta,3 ;left paddle pressed? goto rt_myscore ;yes, so score ;at then end of each loop call a delay rtlend call delay5 decfsz loop_cntr ;decrement loop counter, check if led is to move goto rtl_1 ;here if ball moving on bcf status,0 rrf led_posn,1 btfsc status,0 ;ball off end? goto rt_myscore ;yes, right's point goto rtl_0 ;**state exit** rt_myscore goto score_right rt_yrscore goto score_left ; ;**”Left-to-Right” State** l_to_r movlw 00 ;switch off "out of play" movwf porta movlw 01 ;define ball start posn. movwf led_posn ltr_0 movlw led_durn movwf loop_cntr ;determine length of led illumination ;go round this loop “duration” times, for every ball position ltr_1 movf led_posn,w ;output new ball posn movwf portb btfss led_posn,0 ;is ball at start (ie posn 0)? goto ltr_2 ;no, so move on ;yes, OK if left paddle still pressed (so only test rt paddle) btfss porta,4 ;right paddle pressed? goto lft_myscore ;yes, so score goto ltrend ltr_2 btfss led_posn,7 ;is ball at end (ie posn 7)? goto ltr_3 ;no, so move on ;here if ball at end, right paddle will change dirn, score right if left paddle btfss porta,4 ;right paddle pressed? goto r_to_l ;yes, so change direction btfss porta,3 ;left paddle pressed? goto lft_yrscore ;yes, so right score goto ltrend ;here if neither start nor end posn. ltr_3 btfss porta,4 ;right paddle pressed? goto lft_myscore ;yes, so score btfss porta,3 ;left paddle pressed? goto lft_yrscore ;yes, so score ltrend call delay5 decfsz loop_cntr ;decrement loop counter, check if led is to move goto ltr_1 ;here if ball moving on bcf status,0 ;Clear Carry, as rlf rotates through it rlf led_posn,1 btfsc status,0 ;ball off end? goto lft_myscore ;yes, left's point goto ltr_0 ;**state exit** lft_myscore goto score_left lft_yrscore goto score_right ; ;**”Score” State** ;here if Left has scored score_left movlw 00 movwf portb ;all play leds off bsf porta,1 ;activate "score" led call delay500 bcf porta,1 ;clear "score" led goto wait ;here if Right has scored score_right movlw 00 movwf portb ;all play leds off bsf porta,0 ;activate "score" led call delay500 bcf porta,0 ;clear "score" led goto wait ; ;********************************************** ;SUBROUTINES ;********************************************** ; ;Delay of 5ms approx. Instruction cycle time is 5us. delay5 movlw D'200' ;200 cycles called, ;each taking 5x5=25us movwf delcntr1 del1 nop ;5 inst cycles in this loop nop decfsz delcntr1,1 goto del1 return ; ; Delay of 500ms (approx) - 100 calls to delay5 delay500 movlw D'100' movwf delcntr2 del2 call delay5 decfsz delcntr2,1 goto del2 return ; end