Ping Pong Scoreboard
Updates
<section begin=updates />*New! Ping Pong Scoreboard! --Paul 13:16, 10 January 2008 (EST)<section end=updates /> <section begin=oldnews /> <section end=oldnews />
Abstract
This device is intended to make score keeping easier and more spectator friendly for the game of ping pong. It consists of 2 double digit 7-0segment displays, 1 display for each player. Each display has 5 LEDs that are used to indicate the player’s current serve. The device can operate in the old 21 point style game or the new 11 point style game. The game mode is selected using the Game Mode switch. After selecting the desired game mode the user should reset the board to register the change. The device has a cord that links 3 buttons to the main score board. The 3 buttons are intended to be taped to the underside of one of the player’s court. This allows 1 player to control the score without interfering with the playing field. The 3 buttons are P1 score, P2 Score and Undo. P1 and P2 score are used to give the respective player a point for winning a rally. The Undo button is to correct a miss used button. The undo is only 1 level deep, meaning it can only undo your last action. The scoreboard will automatically calculate whose serve it is and display it on the LEDs. The scoreboard even works when the game becomes Duce and a player must win by 2 and serve alternates every round. When a player reaches a winning condition the scoreboard will flash indicating the game is over. After a game is over the scoreboard should be reset to continue with a new game.
The PIC I used may seem like a strange selection but honestly the only reason I chose it was because I had extras lying around. Normally I wouldn't use an IC as expensive as the MAX7221 ($10!) but again I had one lying around.
Parts
| Part | QTY |
| NO momentary buttons | 4 |
| SPST switch | 5 |
| 10K resistors | 6 |
| 20MHZ Crystal | 1 |
| 27pF ceramic caps | 2 |
| 10uF cap | 1 |
| 1uF cap | 1 |
| double digit 7-segment displays | 2 |
| LEDs | 10 |
| PIC16F872 | 1 |
| MAX7221 | 1 |
| 6 pos male ICSP header | 1 |
| signal diode 1N4148 | 1 |
| 2n3904 npn | 2 |
| current limiting resistor dependent on your 7-segment displays | 1 |
Schematic
Code
Full MPLAB project here: [1]
Spelling not guaranteed in code. :-)
;********************************************************************** ; * ; Filename: main.asm * ; Date: 01/08/08 * ; File Version: 1.0 * ; * ; Author: Paul Mac * ; me@pauljmac.com * ; http://pauljmac.com * ; Copyright Paul Mac 2008. Some Rights Reserved. * ;********************************************************************** ; * ; Files required: P16872.INC * ; * ;********************************************************************** ; * ; Notes: This is a program used to keep score of a Ping-Pong game. * ; It uses a 16F872 and a MAX7221 7-segment driver with 4 displays. * ; The tracker also keeps score of whose serve it is and can even * ; commutate serve/score while in Duce. The Mode Switch is used to * ; tell the program weather to run an old style 21 point game or a * ; new 11 point style game. The game mode switch is read after a * ; reset. The "main controls" consists of 3 buttons: P1, P2 and Undo * ; P1 and P2 is used to increment the scores while undo is, well, * ; UNDO! The undo button is for if you just hit the wrong player * ; button and need to undo it. The undo is only 1 level deep. * ; Meaning you can only undo your last incorrect score increment. * ; There’s no 3 or 4 undo’s here, it’s not MS word. * ; When a player reaches the winning point the scoreboard * ; will flash indicating the games over. Score can continue after * ; a winning game condition, but the score board may do some funky * ; things, as its not intended to still be used after a winning game * ; condition. The Scoreboard should be reset after a winning game. * ; * ;********************************************************************** ; This work is licensed under the Creative Commons * ; Attribution-Noncommercial-Share Alike 3.0 United States License. * ; To view a copy of this license, visit * ; http://creativecommons.org/licenses/by-nc-sa/3.0/us/ or send a * ; letter to Creative Commons, 171 Second Street, Suite 300, * ; San Francisco, California, 94105, USA. * ;********************************************************************** list p=16f872 ; list directive to define processor #include <p16f872.inc> ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF ;***** VARIABLE DEFINITIONS cblock 0x20 p1s, p2s, serve, p1score, p2score, u1,u2, displaydelay, displaydelay1, toggle bin, hundreds, tens_and_ones p1button, p2button, undobutton, two, temp, gameover, gameovertoggle, gameovercounter d1,d2,d3 endc #define CS PORTC,7 #define SL1 PORTC,2 #define SL2 PORTA,5 #define P1B PORTA,0 #define P2B PORTA,1 #define UndoB PORTA,2 #define Mode PORTA,3 ;********************************************************************** ORG 0x000 ; processor reset vector clrf PCLATH ; ensure page bits are cleared goto main ; go to beginning of program ORG 0x020 ORG 0x020 main BANKSEL PORTA clrf PORTA clrf PORTB clrf PORTC BANKSEL TRISA clrf TRISA clrf TRISB clrf TRISC movlw b'00000110' ;turnning off analog inputs BANKSEL ADCON1 movwf ADCON1 movlw b'00001111' ;setting buttons to input BANKSEL TRISA movwf TRISA movlw b'11001000' ;the server indicator LEDs movwf TRISB movlw b'00010000' movwf TRISC BANKSEL p1score clrf p1score clrf p2score clrf p1s clrf p2s clrf serve clrf p1button clrf p2button clrf undobutton clrf gameover banksel displaydelay1 movlw 0xFF movwf displaydelay1 movwf displaydelay movlw 0x02 movwf two movlw 0x19 ;25 movwf gameovercounter banksel PORTC bsf CS ;the CS pin for the 7221 movlw 0xC0 banksel SSPSTAT movwf SSPSTAT movlw 0x20 ;setup SPI banksel SSPCON movwf SSPCON movlw 0x0F ;put the MAX7221 into normal mode BANKSEL PORTC bcf CS ;Chip Select the MAX call SendSPI movlw 0x00 ;normal mode call SendSPI BANKSEL PORTC bsf CS ;unchip select the MAX movlw 0x0C ;Shutdown register BANKSEL PORTC bcf CS ; call SendSPI movlw 0x01 ;normal operation call SendSPI BANKSEL PORTC bsf CS ; movlw 0x0A ;Intensity register BANKSEL PORTC bcf CS ; call SendSPI movlw 0x0F ;Max on call SendSPI BANKSEL PORTC bsf CS ; movlw 0x0B ;Scan-Limit register BANKSEL PORTC bcf CS ; call SendSPI movlw 0x03 ;4 digits call SendSPI BANKSEL PORTC bsf CS ; movlw 0x09 ;decode mode register BANKSEL PORTC bcf CS ; call SendSPI movlw 0xFF ;all decode call SendSPI BANKSEL PORTC bsf CS ; call ClearSegs btfss Mode ;test the mode switch. if its low its 21 point game, if high 11 point game goto new_type goto old_type old_type ;begin the 21 point style play. Waiting for the user to select who has first serve. movlw 1 BANKSEL serve movwf serve call PollButtons btfsc p1button,0 ;poll the player 1 button goto loadp1 btfsc p2button,0 ;poll the player 2 button goto loadp2 goto old_type ;loop, lol forgot this the first time PollButtons BANKSEL PORTA btfss P1B ;poll the player 1 button call Player1Button btfss P2B ;poll the player 2 button call Player2Button btfss UndoB call UndoButton return Player1Button btfss P1B bsf p1button,0 Player1Button_Test btfsc P1B goto Player1Button_Return goto Player1Button_Test Player1Button_Return call Twenty_mS_Delay return Player2Button btfss P2B bsf p2button,0 Player2Button_Test btfsc P2B goto Player2Button_Return goto Player2Button_Test Player2Button_Return call Twenty_mS_Delay return UndoButton btfss UndoB bsf undobutton,0 UndoButton_Test btfsc UndoB goto UndoButton_Return goto UndoButton_Test UndoButton_Return call Twenty_mS_Delay return loadp1 bsf p1s,0 ;set p1s bit 0 indicateing they are current server goto Startold loadp2 bsf p2s,0 ;set p2s bit 0 indicateing they are current server goto Startold ClearButtons bcf p1button,0 bcf p2button,0 bcf undobutton,0 return Startold call ClearButtons call DisplayRoutine call PollButtons movlw 0x15 subwf p1score,w btfsc STATUS,Z ;test the Zero flag. It will be set if the score is 21 bsf gameover,0 ;set game over mode movlw 0x15 subwf p2score,w btfsc STATUS,Z ;test the Zero flag. It will be set if the score is 21 bsf gameover,0 ;set game over mode btfsc p1button,0 ;test p1 button for a p1score++ call Addp1 btfsc p2button,0 ;test p2 button for a p2score++ call Addp2 btfsc undobutton,0 ;test undo button call Undo movlw 0x14 ;setup to see if the serve # is more than 20 subwf p1score,w ;subtract 20 btfss STATUS,Z ;test the Zero flag. It will be clear if the serve is less than 20 goto Startold movlw 0x14 ;setup to see if the serve # is more than 20 subwf p2score,w ;subtract 20 btfss STATUS,Z ;test the carry flag. It will be clear if the serve is less than 20 goto Startold goto Duce Duce call ClearButtons call PollButtons btfsc p1button,0 ;test p1 button for a p1score++ call Addp1Duce btfsc p2button,0 ;test p2 button for a p2score++ call Addp2Duce btfsc undobutton,0 ;test undo button call UndoDuce call DisplayRoutine call TestDuceGameOver goto Duce UndoDuce call GameOverOn movfw p1score ;add p1 and p2 score to see if its 20 addwf p2score,w banksel temp movwf temp movlw 0x28 subwf temp,w btfss STATUS,Z ;test the carry flag. It will be clear if the serve is less than 20 goto UndoDuce1 movlw 0x06 movwf serve banksel p1s comf p1s,f comf p2s,f goto UndoReturn UndoReturn call ResetToggler bcf toggle,0 btfsc u1,0 ;see if the last point awarded was to p1 call UndoP1Return ;if it was do this btfsc u2,0 ;see if the last point awarded was to p2 call UndoP2Return goto Startold UndoP1Return movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p1score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 5 call UndoServe bcf u1,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoP2Return movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p2score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 5 call UndoServe bcf u2,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoDuce1 call ResetToggler bcf toggle,0 btfsc u1,0 ;see if the last point awarded was to p1 call UndoP1Duce ;if it was do this btfsc u2,0 ;see if the last point awarded was to p2 call UndoP2Duce return UndoP1Duce movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p1score,f ;--p1score call UndoServeDuce bcf u1,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoP2Duce movlw b'11001000' banksel PORTB andwf PORTB,f banksel p2score decf p2score,f ;--p2score call UndoServeDuce bcf u2,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoServeDuce comf p1s,f comf p2s,f return TestDuceGameOver banksel p1score movfw p1score subwf p2score,w call TestTwo banksel p1score movfw p2score subwf p1score,w call TestTwo return TestTwo banksel two subwf two,w ;subtract 2 and test X flag btfsc STATUS,Z ;test the carry flag. It will be clear if the serve is less than 20 bsf gameover,0 return Addp1Duce call ResetToggler bcf toggle,0 bsf u1,0 ;set u1 indicateing that p1 was the last person to reviece a point (for undo button) bcf u2,0 ;clear u2 undo register sence u1 is being set now incf p1score,f ;incrament p1score comf p1s,f comf p2s,f bcf SL1 bcf SL2 return ;return to the main game loop Addp2Duce call ResetToggler bcf toggle,0 bsf u2,0 ;set u2 indicateing that p2 was the last person to reviece a point (for undo button) bcf u1,0 ;clear u1 undo register sence u2 is being set now incf p2score,f ;incrament p1score comf p1s,f comf p2s,f bcf SL1 bcf SL2 return Addp1 call ResetToggler bcf toggle,0 bsf u1,0 ;set u1 indicateing that p1 was the last person to reviece a point (for undo button) bcf u2,0 ;clear u2 undo register sence u1 is being set now incf p1score,f ;incrament p1score incf serve,f ;++ serve movlw 0x06 ;setup to see if the serve # is more than 5 subwf serve,w ;subtract 6 from Serve btfsc STATUS,C ;test the carry flag. It will be clear if Serve is less than 6 call SwitchServe return ;return to the main game loop. Addp2 call ResetToggler bcf toggle,0 bsf u2,0 ;set u2 indicateing that p2 was the last person to reviece a point (for undo button) bcf u1,0 ;clear u1 undo register sence u2 is being set now incf p2score,f ;incrament p1score incf serve,f movlw 0x06 ;setup to see if the serve # is more than 5 subwf serve,w ;subtract 6 from Serve btfsc STATUS,C ;test the carry flag. It will be clear if Serve is less than 6 call SwitchServe return ;return to the main game loop. Undo call GameOverOn call ResetToggler bcf toggle,0 btfsc u1,0 ;see if the last point awarded was to p1 call UndoP1 ;if it was do this btfsc u2,0 ;see if the last point awarded was to p2 call UndoP2 return UndoP1 movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p1score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 5 call UndoServe bcf u1,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoP2 movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p2score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 5 call UndoServe bcf u2,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoServe movlw 0x05 movwf serve comf p1s,f comf p2s,f return SwitchServe comf p1s,f ;compliment p1s comf p2s,f ;compliment p2s bcf SL1 ;turn OFF p1 server leds bcf SL2 ;turn OFF p2 server leds movlw 0x01 ;reset the serve register banksel serve movwf serve movlw b'11001000' banksel PORTB andwf PORTB,f return DisplayRoutine ;counter call Two_mS_Delay banksel displaydelay decfsz displaydelay,f ;dec the display delay counter goto Skip DisplayDelay1 decfsz displaydelay1,f goto DisplayDelay1 comf toggle,f goto Skip Skip btfss toggle,0 goto Normal_LED_Display goto Toggle_LED_Display ResetToggler banksel displaydelay1 movlw 0xFF movwf displaydelay1 movwf displaydelay bcf gameover,0 return Normal_LED_Display btfsc p1s,0 ;test the p1 serve register, if its clear skip next bsf SL1 ;turn on p1 server leds btfsc p2s,0 ;test p2 serve register, if its clear (it shouldnet be at this point) skip. bsf SL2 ;turn on p2 server leds movlw HIGH LookupServe ;got to preload the high bites into PCLATH for this lookup to work movwf PCLATH banksel serve movfw serve ;move the current serve # to W call LookupServe ;lookup the bit pattern banksel PORTB iorwf PORTB,f ;OR the bit pattern with PORTB to display the correct LEDS goto DisplayScores Toggle_LED_Display movlw b'11001000' ;clear portb before we start this banksel PORTB ; andwf PORTB,f ; btfsc p1s,0 ;test the p1 serve register, if its clear skip next bsf SL1 ;turn on p1 server leds btfsc p2s,0 ;test p2 serve register, if its clear (it shouldnet be at this point) skip. bsf SL2 ;turn on p2 server leds movlw HIGH LookupServe ;got to preload the high bites into PCLATH for this lookup to work movwf PCLATH banksel serve decf serve,w ;subtract 1 and put the result in W call LookupServe ;lookup the bit pattern banksel PORTB iorwf PORTB,f ;OR the bit pattern with PORTB to display the correct LEDS goto DisplayScores DisplayScores ;player 1 digits movf p1score,w ;move p1score to w movwf bin ;move the p1score to bin for BCD computation call binary_to_bcd movlw 0x01 ;select the first digit to display bcf CS call SendSPI movf tens_and_ones,w ;move tens_and_ones to W andlw b'00001111' ;mask the crap and now ones is in W call SendSPI bsf CS movlw 0x02 ;select the 2nd digit to display bcf CS call SendSPI swapf tens_and_ones,w ;swap the nibbles in tens_and_ones and put it in W andlw b'00001111' ;mask the crap and now tens is in W call SendSPI bsf CS ;Do it all again for player 2 digits movf p2score,w ;move p1score to w movwf bin ;move the p1score to bin for BCD computation call binary_to_bcd movlw 0x03 ;select the first digit to display bcf CS call SendSPI movf tens_and_ones,w ;move tens_and_ones to W andlw b'00001111' ;mask the crap and now ones is in W call SendSPI bsf CS movlw 0x04 ;select the 2nd digit to display bcf CS call SendSPI swapf tens_and_ones,w ;swap the nibbles in tens_and_ones and put it in W andlw b'00001111' ;mask the crap and now tens is in W call SendSPI bsf CS banksel gameover btfss gameover,0 return ;return the call if its not gameover mode call Twenty_mS_Delay banksel gameover decfsz gameovercounter,f return ;return the call after the dec above banksel gameovertoggle btfsc gameovertoggle,0 goto GameOverOn goto GameOverOff GameOverOff bsf gameovertoggle,0 movlw 0x0C ;Shutdown register BANKSEL PORTC bcf CS ; call SendSPI movlw 0x00 ;shutdown mode call SendSPI BANKSEL PORTC bsf CS ; movlw 0x19 ;25 movwf gameovercounter return GameOverOn bcf gameovertoggle,0 movlw 0x0C ;Shutdown register BANKSEL PORTC bcf CS ; call SendSPI movlw 0x01 ;normal mode call SendSPI BANKSEL PORTC bsf CS ; movlw 0x19 ;25 movwf gameovercounter return ClearSegs bcf CS movlw 0x01 ;initilize the 7segs by clearing all the digits call SendSPI movlw 0x00 call SendSPI bsf CS bcf CS movlw 0x02 call SendSPI movlw 0x00 call SendSPI bsf CS bcf CS movlw 0x03 call SendSPI movlw 0x00 call SendSPI bsf CS bcf CS movlw 0x04 call SendSPI movlw 0x00 call SendSPI bsf CS return SendSPI ;This rutine will hold the MCU untill transmission is over. BANKSEL SSPBUF ;If you want to load up the SSPBUF and GTFO dont use this. movwf SSPBUF wait1 BANKSEL SSPSTAT btfss SSPSTAT,BF ;test to make sure its set indicateing the transmission is over goto wait1 ;when its over continue bcf SSPSTAT,BF ;and clear the intrupt banksel PORTA ; just get back to bank 0 return ;================================================================== ; 11 point style game new_type ;begin the 11 point style play. Waiting for the user to select who has first serve. movlw 1 BANKSEL serve movwf serve call PollButtons btfsc p1button,0 ;poll the player 1 button goto loadp1_new btfsc p2button,0 ;poll the player 2 button goto loadp2_new goto new_type ;loop, lol forgot this the first time loadp1_new bsf p1s,0 ;set p1s bit 0 indicateing they are current server goto Startnew loadp2_new bsf p2s,0 ;set p2s bit 0 indicateing they are current server goto Startnew Startnew call ClearButtons call DisplayRoutine movlw 0x0B ;11 subwf p1score,w btfsc STATUS,Z ;test the Zero flag. It will be set if the score is 11 bsf gameover,0 movlw 0x0B ;11 subwf p2score,w btfsc STATUS,Z ;test the Zero flag. It will be set if the score is 11 bsf gameover,0 call PollButtons btfsc p1button,0 ;test p1 button for a p1score++ call Addp1_new btfsc p2button,0 ;test p2 button for a p2score++ call Addp2_new btfsc undobutton,0 ;test undo button call Undo_new movlw 0x0A ;setup to see if the serve # is more than 10 subwf p1score,w ;subtract 10 btfss STATUS,Z ;test the Zero flag. It will be clear if the serve is less than 10 goto Startnew movlw 0x0A ;setup to see if the serve # is more than 10 subwf p2score,w ;subtract 10 btfss STATUS,Z ;test the carry flag. It will be clear if the serve is less than 10 goto Startnew goto Duce_new Duce_new call ClearButtons call PollButtons btfsc p1button,0 ;test p1 button for a p1score++ call Addp1Duce_new btfsc p2button,0 ;test p2 button for a p2score++ call Addp2Duce_new btfsc undobutton,0 ;test undo button call UndoDuce_new call DisplayRoutine call TestDuceGameOver_new goto Duce_new UndoDuce_new call GameOverOn movfw p1score ;add p1 and p2 score to see if its 20 addwf p2score,w banksel temp movwf temp movlw 0x14 ;20 subwf temp,w btfss STATUS,Z ;test the carry flag. It will be clear if the serve is less than 20 goto UndoDuce1_new movlw 0x03 movwf serve banksel p1s comf p1s,f comf p2s,f goto UndoReturn_new UndoReturn_new call ResetToggler bcf toggle,0 btfsc u1,0 ;see if the last point awarded was to p1 call UndoP1Return_new ;if it was do this btfsc u2,0 ;see if the last point awarded was to p2 call UndoP2Return_new goto Startnew UndoP1Return_new movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p1score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 2 call UndoServe_new bcf u1,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoP2Return_new movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p2score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 5 call UndoServe_new bcf u2,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoDuce1_new call ResetToggler bcf toggle,0 btfsc u1,0 ;see if the last point awarded was to p1 call UndoP1Duce_new ;if it was do this btfsc u2,0 ;see if the last point awarded was to p2 call UndoP2Duce_new return UndoP1Duce_new movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p1score,f ;--p1score call UndoServeDuce_new bcf u1,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoP2Duce_new movlw b'11001000' banksel PORTB andwf PORTB,f banksel p2score decf p2score,f ;--p2score call UndoServeDuce_new bcf u2,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoServeDuce_new comf p1s,f comf p2s,f return TestDuceGameOver_new banksel p1score movfw p1score subwf p2score,w call TestTwo_new banksel p1score movfw p2score subwf p1score,w call TestTwo_new return TestTwo_new banksel two subwf two,w ;subtract 2 and test X flag btfsc STATUS,Z ;test the carry flag. It will be clear if the serve is less than 20 bsf gameover,0 return Addp1Duce_new call ResetToggler bcf toggle,0 bsf u1,0 ;set u1 indicateing that p1 was the last person to reviece a point (for undo button) bcf u2,0 ;clear u2 undo register sence u1 is being set now incf p1score,f ;incrament p1score comf p1s,f comf p2s,f bcf SL1 bcf SL2 return ;return to the main game loop Addp2Duce_new call ResetToggler bcf toggle,0 bsf u2,0 ;set u2 indicateing that p2 was the last person to reviece a point (for undo button) bcf u1,0 ;clear u1 undo register sence u2 is being set now incf p2score,f ;incrament p1score comf p1s,f comf p2s,f bcf SL1 bcf SL2 return Addp1_new call ResetToggler bcf toggle,0 bsf u1,0 ;set u1 indicateing that p1 was the last person to reviece a point (for undo button) bcf u2,0 ;clear u2 undo register sence u1 is being set now incf p1score,f ;incrament p1score incf serve,f ;++ serve movlw 0x03 ;setup to see if the serve # is more than 2 subwf serve,w ;subtract 3 from Serve btfsc STATUS,C ;test the carry flag. It will be clear if Serve is less than 3 call SwitchServe_new return ;return to the main game loop. Addp2_new call ResetToggler bcf toggle,0 bsf u2,0 ;set u2 indicateing that p2 was the last person to reviece a point (for undo button) bcf u1,0 ;clear u1 undo register sence u2 is being set now incf p2score,f ;incrament p1score incf serve,f movlw 0x03 ;setup to see if the serve # is more than 2 subwf serve,w ;subtract 3 from Serve btfsc STATUS,C ;test the carry flag. It will be clear if Serve is less than 3 call SwitchServe_new return ;return to the main game loop. Undo_new call GameOverOn call ResetToggler bcf toggle,0 btfsc u1,0 ;see if the last point awarded was to p1 call UndoP1_new ;if it was do this btfsc u2,0 ;see if the last point awarded was to p2 call UndoP2_new return UndoP1_new movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p1score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 2 call UndoServe_new bcf u1,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoP2_new movlw b'11001000' banksel PORTB andwf PORTB,f banksel p1score decf p2score,f ;--p1score decf serve,f ;--serve btfsc STATUS,Z ;if Z flag is set that means that serve was at 1 and needs to be reset to 2 call UndoServe_new bcf u2,0 ;clear the p1 undo register to prevent a loop bcf SL1 bcf SL2 return UndoServe_new movlw 0x02 movwf serve comf p1s,f comf p2s,f return SwitchServe_new comf p1s,f ;compliment p1s comf p2s,f ;compliment p2s bcf SL1 ;turn OFF p1 server leds bcf SL2 ;turn OFF p2 server leds movlw 0x01 ;reset the serve register banksel serve movwf serve movlw b'11001000' banksel PORTB andwf PORTB,f return ;---------------------------------------------------------------- ;end of the good stuff. everything else is routines binary_to_bcd CLRF hundreds SWAPF bin,w ;w = A0*16+A1 ADDWF bin,w ;w = A0+A1 ANDLW b'00001111' ;w = A0+A1 % 16 SKPNDC ;if A0+A1 > 16 ADDLW 0x16 ;w += 16 SKPNDC ;if w % 16 > 10 ADDLW 0x06 ;w += 6 ADDLW 0x06 ;w += 6 SKPDC ;if w < 10 ADDLW -0x06 ;w -= 6 BTFSC bin,4 ADDLW 0x16 - 1 + 0x6 SKPDC ADDLW -0x06 BTFSC bin,5 ADDLW 0x30 BTFSC bin,6 ADDLW 0x60 BTFSC bin,7 ADDLW 0x20 ADDLW 0x60 RLF hundreds,f BTFSS hundreds, 0 ADDLW -0x60 MOVWF tens_and_ones BTFSC bin,7 INCF hundreds,f return Half_Second_Delay ;2499992 cycles movlw 0x15 movwf d1 movlw 0x74 movwf d2 movlw 0x06 movwf d3 Half_Second_Delay_0 decfsz d1, f goto $+2 decfsz d2, f goto $+2 decfsz d3, f goto Half_Second_Delay_0 ;4 cycles goto $+1 goto $+1 ;4 cycles (including call) return Twenty_mS_Delay ;99993 cycles movlw 0x1E movwf d1 movlw 0x4F movwf d2 Twenty_mS_Delay_0 decfsz d1, f goto $+2 decfsz d2, f goto Twenty_mS_Delay_0 ;3 cycles goto $+1 nop ;4 cycles (including call) return Two_mS_Delay ;9993 cycles movlw 0xCE movwf d1 movlw 0x08 movwf d2 Two_mS_Delay_0 decfsz d1, f goto $+2 decfsz d2, f goto Two_mS_Delay_0 ;3 cycles goto $+1 nop ;4 cycles (including call) return LookupServe: addwf PCL,f ;add the offset in W to the PC retlw b'00000000' ;0 retlw b'00000001' ;1 retlw b'00000011' ;2 retlw b'00000111' ;3 retlw b'00010111' ;4 retlw b'00110111' ;5 END ; directive 'end of program'
Pictures
-
The prototype Ping Pong Scoreboard