20
Interactive Beer Pong Table I decided to build this beer pong table since I think, as an electrical engineering student, I should have a table that stands out. On either end of the table, where the cups stand, are ten LED rings composed of eight LEDs each. In the middle of each ring resides a photocell. Each photocell is connected in series with a 1kΩ resistor from +5V to ground, creating a voltage divider. Since the photocell has a resistance depending on the amount of light it receives, the voltage across the photocell will vary. The voltage across each sensor is sent to an analog input on the pic16f887 MCU and into the ADC. The program polls each sensor, compares its ADC reading to a reference value, and decides if that particular ring should be turned on or off. So long as a ring stays lit, the software will “rotate” the LEDs, giving the illusion of a light spinning around the cup. Each ring of LEDs is driving by an 8-bit serial-in,parallel/serial-out shift register. The software will send out 10 bytes of information using 2-wire SPI. Each byte simply states which LED is on, if any, and the byte order specifies the rings. This particular table was built in two 2’x8’ sections connected by a hinge. This decision was made to allow easier transportation. This is not necessary, only a convenience for me. The LED rings have a diameter about ½ cm larger than that of the bottom side of a standard Solo cup. Using a compass, a ruler, and a bit of geometry, I arranged the rings into a triangle with a base of four rings and have the LEDs at the 45° marks of each ring. The power for the circuit comes from an AC/DC adapter purchased from Radioshack (SKU: 273-316). I placed a power connector on either end of the table which in turn are wired to one another by a power and ground wire running the length of the table. Doing so allows the table to be powered from either end. The reference value for the ADC readings was something that was found with a little math and a little trial-and-error. In some situations, the same ADC reference may not be suitable for all sensors (the photocells are not completely consistent relative to each other). Because of this, there are three lines in the function “Analyze ADC” that need to be uncommented. Doing this, along with setting individual reference values in the “Init” function for each sensor (register names are ADCReference- ADCReference+9), will allow the program to compare each ADC reading to a unique reference value. The software was written in MPLAB in conjunction with a PICkit 2 for programming the MCUs. Make sure to connect the sensors to the labeled pins (shown on the schematic) or to keep track of which ADC input each sensor is going to. Not doing so will end up in a sensor triggering the wrong ring. And, if you change which ADC inputs the sensors go to, remember that the bytes are sent out in reverse order of ring number. For example, the byte for ring 10 is sent out first, not last. Note: These instructions are for building one side of the table. Simply repeat these instructions to build the other side.

Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

  • Upload
    hathuan

  • View
    223

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

Interactive Beer Pong Table

I decided to build this beer pong table since I think, as an electrical engineering student, I should have a table that stands out. On either end of the table, where the cups stand, are ten LED rings composed of eight LEDs each. In the middle of each ring resides a photocell. Each photocell is connected in series with a 1kΩ resistor from +5V to ground, creating a voltage divider. Since the photocell has a resistance depending on the amount of light it receives, the voltage across the photocell will vary. The voltage across each sensor is sent to an analog input on the pic16f887 MCU and into the ADC. The program polls each sensor, compares its ADC reading to a reference value, and decides if that particular ring should be turned on or off. So long as a ring stays lit, the software will “rotate” the LEDs, giving the illusion of a light spinning around the cup.

Each ring of LEDs is driving by an 8-bit serial-in,parallel/serial-out shift register. The software will send out 10 bytes of information using 2-wire SPI. Each byte simply states which LED is on, if any, and the byte order specifies the rings.

This particular table was built in two 2’x8’ sections connected by a hinge. This decision was made to allow easier transportation. This is not necessary, only a convenience for me. The LED rings have a diameter about ½ cm larger than that of the bottom side of a standard Solo cup. Using a compass, a ruler, and a bit of geometry, I arranged the rings into a triangle with a base of four rings and have the LEDs at the 45° marks of each ring.

The power for the circuit comes from an AC/DC adapter purchased from Radioshack (SKU: 273-316). I placed a power connector on either end of the table which in turn are wired to one another by a power and ground wire running the length of the table. Doing so allows the table to be powered from either end.

The reference value for the ADC readings was something that was found with a little math and a little trial-and-error. In some situations, the same ADC reference may not be suitable for all sensors (the photocells are not completely consistent relative to each other). Because of this, there are three lines in the function “Analyze ADC” that need to be uncommented. Doing this, along with setting individual reference values in the “Init” function for each sensor (register names are ADCReference-ADCReference+9), will allow the program to compare each ADC reading to a unique reference value.

The software was written in MPLAB in conjunction with a PICkit 2 for programming the MCUs.

Make sure to connect the sensors to the labeled pins (shown on the schematic) or to keep track of which ADC input each sensor is going to. Not doing so will end up in a sensor triggering the wrong ring. And, if you change which ADC inputs the sensors go to, remember that the bytes are sent out in reverse order of ring number. For example, the byte for ring 10 is sent out first, not last.

Note: These instructions are for building one side of the table. Simply repeat these instructions to build the other side.

Page 2: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table
Page 3: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table
Page 4: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table
Page 5: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table
Page 6: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

Allied Part Number Description Amount436-0217 3MM Red LED 160383-2187 Microchip PIC16f887 MCU 2296-4719 1 kΩ resistor, .1 watt, ±5% 20236-1860 8-bit SI-SO/PO Shift Register 20

Other partsPHOTOCELL1 5k-500k photocell/LDR 20

Page 7: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

Order from: http://www.futurlec.com/Photocells.shtml

Page 8: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table
Page 9: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

list p=16f887 ; list directive to define processor #include <p16f887.inc> ; processor specific variable definitions ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The labels following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. __CONFIG _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT __CONFIG _CONFIG2, _WRT_OFF & _BOR21V ;***** VARIABLE DEFINITIONS w_temp EQU 0x7D ; variable used for context saving status_temp EQU 0x7E ; variable used for context saving pclath_temp EQU 0x7F ; variable used for context saving cblock 0x20 Display ; register to hold the output Delay1 ; register to set debounce delay Delay2 ; register to set debounce delay SPIFlag ; flag to determine if data needs to be transmitted ; bit 1 notifies the program to start a new data transmit cycle RegisterNumber ; number used to determine how many bytes of data need to be sent ; out for each date retrieve cycle RegisterData:10 ; registers to hold the data from the external registers DataSent ; register to keep track of the number of bytes sent each SPI Cycle TimerCount ; register to count overflows of Timer0 DelayMark ; register to hold delay value for sending out data DisplayDelay ; flag to determine when the display delay has finished LEDDisplay ; register to hold the ADC output to be displayed on the LEDs ADCReference ; register to hold the reference value of the ADC output SPIOut:10 ; output registers for the LED rings

Page 10: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

ADCRead:10 ; voltage readings from the ring sensors RegisterTen ; holds the value of 10, used for SPI cycles and ADC read cycles CycleCount ; holds the current cycle number for various cycles ADCChannels:10 ; holds the channel numbers the for ADC ChannelCount ; moves pointer to appropriate register for the current cycle ReadCount ; moves pointer to appropriate register for the current cycle TempStore ; register to temporarily hold a value endc ;********************************************************************** ORG 0x000 ; processor reset vector nop goto Start ; go to beginning of program ORG 0x004 ; interrupt vector location StartISR: movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register btfsc PIR1,SSPIF ; has the SPI data finished transmission/reception? goto SPI_Interrupt ; yes, call interrupt routine btfsc INTCON,T0IF ; has the display delay finished? goto TimerInterrupt ; yes, call Timer0 interrupt routine goto ExitISR SPI_Interrupt: bcf PIR1,SSPIF ; clear interrupt flag clrf Display movf SSPBUF,w ; move data out of the buffer and into Display register incf DataSent,f ; update the number of bytes sent out for the current SPI cycle bsf SPIFlag,0 ; notify main program to send out another byte btfsc INTCON,T0IF ; is the Timer0 interrupt flag set? goto TimerInterrupt ; no, exit ISR goto ExitISR

Page 11: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

TimerInterrupt: bcf INTCON,T0IF ; clear interrupt flag incf TimerCount movf TimerCount,w ; when TimerCount is equal to DelayMark, the subwf DelayMark,w ; display delay has finished btfsc STATUS,Z ; is DelayMark = TimerCount? bsf SPIFlag,1 ; yes, set the delay flag goto ExitISR ExitISR: movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt ;********************************************************************** ;Subroutines Init: bcf STATUS,RP0 ; select register bank 0 bcf STATUS,RP1 bsf INTCON,GIE ; enable global interrupts bsf INTCON,PEIE ; enable peripheral interrupts bsf INTCON,T0IE ; enable Timer0 interrupts movlw b'00100000' ; set up SPI Master mode, SCK = Fosc/4 movwf SSPCON ; enable SPI communications ; set idle state for SCK low bsf STATUS,RP0 ; select register bank 1 movlw 0x05 movwf OPTION_REG ; 1:64 prescale for Timer0 movlw 0x00 ; Ports 1,2,3,4 and 5 used for LEDs movwf TRISD ; make PORTD all output

Page 12: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

movlw 0xFF movwf TRISB ; make PORTB all input movlw 0x0F movwf TRISE ; make PORTE all input movlw 0xFF movwf TRISA ; make PORTA all input movlw b'00010000' ; Pins 5,6, and 7 used for LEDs movwf TRISC ; PORTC all output, except SDI bsf PIE1,SSPIE ; enable SPI interrupt bsf SSPSTAT,SMP ; sample data input at end of data output time bsf SSPSTAT,CKE ; transmit data on rising edge of clock movlw 0x00 ; Output of ADC is left justified movwf ADCON1 bsf STATUS,1 ; register bank 3 movlw 0x00 movwf ANSELH ; PORTB are all digital movlw b'11000111' ; configure Timer0, enable RB0 on rising edge movwf OPTION_REG ; 1:256 prescaling movlw b'00111110' ; Port A pins 1,2,3, and 5 are analog movwf ANSEL ; Port E pin 0 is analog movlw b'00011111' ; Port B pins 0,1,2,3, and 4 are analog movwf ANSELH bcf STATUS,RP0 ; back to register bank 0 bcf STATUS,RP1 clrf Delay1 ; ensure register is cleared movlw .248 ; to get a 5 ms delay, Delay2 has to increment a total of movwf Delay2 ; 7 times movlw 0x01 ; notify the program on start up that data needs movwf SPIFlag ; to be transmitted on the SPI line movlw 0x00 ; hold the shift bit low on the external register movwf PORTC ; until communication starts clrf Display ; ensure Display is cleared on startup movlw 0x0A ; two external registers hold the desired data, therefore

Page 13: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

movwf RegisterNumber ; RegisterNumber needs to be loaded with the number 10 clrf DataSent ; ensure register is cleared on startup clrf TimerCount ; ensure register is cleared on startup movlw 0x0F ; set display delay movlw 0x0A movwf RegisterTen ; set RegisterTen value to ten movlw 0xFA movwf ADCReference ; set ADC reference value movlw b'00000001' movwf DelayMark clrf CycleCount ; initialize cycle count to 1 clrf ChannelCount clrf ReadCount clrf Delay1 ; ensure register is cleared movlw .248 ; to get a 5 ms delay, Delay2 has to increment a total of movwf Delay2 ; 7 times movlw b'01101101' ; All set ADC to Fosc/8 movwf ADCChannels movlw b'01010001' movwf ADCChannels+1 movlw b'01001001' movwf ADCChannels+2 movlw b'01000101' movwf ADCChannels+3 movlw b'01101001' movwf ADCChannels+4 movlw b'01001101' movwf ADCChannels+5 movlw b'01010101' movwf ADCChannels+6 movlw b'01110001' movwf ADCChannels+7 movlw b'01100101' movwf ADCChannels+8 movlw b'01100001' movwf ADCChannels+9

Page 14: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

movlw 0x01 movwf SPIOut movlw 0x01 movwf SPIOut+1 movlw 0x01 movwf SPIOut+2 movlw 0x01 movwf SPIOut+3 movlw 0x01 movwf SPIOut+4 movlw 0x01 movwf SPIOut+5 movlw 0x01 movwf SPIOut+6 movlw 0x01 movwf SPIOut+7 movlw 0x01 movwf SPIOut+8 movlw 0x01 movwf SPIOut+9 movlw 0x00 movwf ADCRead movlw 0x00 movwf ADCRead+1 movlw 0x00 movwf ADCRead+2 movlw 0x00 movwf ADCRead+3 movlw 0x00 movwf ADCRead+4 movlw 0x00 movwf ADCRead+5 movlw 0x00 movwf ADCRead+6 movlw 0x00 movwf ADCRead+7 movlw 0x00 movwf ADCRead+8 movlw 0x00

Page 15: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

movwf ADCRead+9 retlw 0 Start: call Init ;goto ADCDebug call AcquireADC goto Main ADCDebug: movf ADCChannels,w ; configure ADC for Fosc/8, channel 8 movwf ADCON0 nop ; wait 5us for A2D amp to settle nop nop nop nop bsf ADCON0,GO_DONE ; Start conversion btfsc ADCON0,GO_DONE ; this bit will change to zero when conversion is complete goto $-1 ; Copy the result to the display LEDs btfsc ADRESH,0 bsf PORTD,1 btfsc ADRESH,1 bsf PORTD,2 btfsc ADRESH,2 bsf PORTD,3 btfsc ADRESH,3 bsf PORTC,5 btfsc ADRESH,4 bsf PORTC,6 btfsc ADRESH,5 bsf PORTC,7

Page 16: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

btfsc ADRESH,6 bsf PORTD,4 btfsc ADRESH,7 bsf PORTD,5 btfss ADRESH,0 bcf PORTD,1 btfss ADRESH,1 bcf PORTD,2 btfss ADRESH,2 bcf PORTD,3 btfss ADRESH,3 bcf PORTC,5 btfss ADRESH,4 bcf PORTC,6 btfss ADRESH,5 bcf PORTC,7 btfss ADRESH,6 bcf PORTD,4 btfss ADRESH,7 bcf PORTD,5 goto ADCDebug Main: movf DataSent,w ; has the number of SPI transmissions for this cycle subwf RegisterNumber,w ; reached to total number of registers to which it is transmitting? btfsc STATUS,Z goto $+3 ; yes, do not start another transmission for this cycle btfsc SPIFlag,0 ; start a new SPI data transmit? call SendSPI ; yes btfsc SPIFlag,1 ; start a new cycle? call ResetSPI ; yes, reset the appropriate values goto Main SendSPI: movlw SPIOut addwf DataSent,w

Page 17: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

movwf FSR movf INDF,w movwf SSPBUF bcf SPIFlag,0 return ResetSPI: bsf PORTD,0 ; latch the inputs to the registers nop bcf PORTD,0 clrf DataSent clrf TimerCount ; reset the delay call AcquireADC bsf SPIFlag,0 ; notify the program to start SPI transmission bcf SPIFlag,1 goto RotateLEDs RotateLEDs: movf CycleCount,w ; if ten cycles have passed, return from this function subwf RegisterTen,w btfss STATUS,Z goto $+.6 clrf CycleCount clrf ReadCount clrf TempStore bcf STATUS,C ; ensure carry bit is clear return movlw SPIOut ; set pointer to first of ADC read registers addwf ReadCount,w ; move pointer to next channel movwf FSR bcf STATUS,C ; ensure the carry bit is clear rrf INDF,f ; shift the contents of the register to "rotate" the LED btfsc STATUS,C ; was there a carry?

Page 18: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

bsf INDF,7 ; yes, set bit 7 ;clrf DataSent ; register has to be cleared in order to keep an accurate count incf ReadCount,f ; increment and start new cycle incf CycleCount,f goto RotateLEDs AcquireADC: movf RegisterTen,w ; if ten cycles have passed, return from this function subwf CycleCount,w btfss STATUS,Z goto $+.6 clrf ChannelCount clrf ReadCount bcf STATUS,C ; ensure carry bit is clear clrf CycleCount goto AnalyzeADC movlw ADCChannels ; set pointer to read from ADC channel addwf ChannelCount,w ; move pointer to next channel movwf FSR movf INDF,w movwf ADCON0 incf ChannelCount,f ;call FiveMSDelay movlw ADCRead ; set pointer to first of ADC read registers addwf CycleCount,w ;bcf STATUS,C ; ensure carry bit is clear movwf FSR incf ReadCount,f nop ; wait 5us for A2D amp to settle nop nop nop nop bsf ADCON0,GO_DONE ; Start conversion btfsc ADCON0,GO_DONE ; this bit will change to zero when conversion is complete

Page 19: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

goto $-.1 movf ADRESH,w movwf INDF ; store reading into ADCRead incf CycleCount,f goto AcquireADC ; go to beginning o floop AnalyzeADC movf CycleCount,w ; if ten cycles have passed, return from this function subwf RegisterTen,w btfss STATUS,Z goto $+.6 clrf CycleCount clrf ReadCount clrf TempStore bcf STATUS,C ; ensure carry bit is clear return movlw ADCRead ; set pointer to first of ADC read registers addwf CycleCount,w ; move pointer to next channel movwf FSR movf INDF,w ; pull stored ADC reading movwf TempStore ; store the value so the pointer location can be changed movlw SPIOut ; move pointer to output registers addwf ReadCount,w ; move pointer to appropriate registers movwf FSR bcf STATUS,C movf ADCReference,w ; is the ADC reading greater than ADCReference? subwf TempStore,w btfsc STATUS,C goto $+3 movlw 0x00 ; yes, turn off LEDs for corresponding ring movwf INDF btfss STATUS,C goto $+.6

Page 20: Interactive Beer Pong Table table that stands out. On …downloads.deusm.com/designnews/25934-Gadget_Freak_Case...Interactive Beer Pong Table I decided to build this beer pong table

bcf STATUS,C movf INDF,w ; if no, is there a value currently in the register? sublw 0x00 btfsc STATUS,C bsf INDF,0 ; yes, do nothing incf ReadCount,f ; increment and start new cycle incf CycleCount,f goto AnalyzeADC FiveMSDelay: incfsz Delay1,f ; this cycle takes 3*256 = 768 cycles goto FiveMSDelay incfsz Delay2,f ; this cycle takes (3+768)*7 = 5,397 cycles = 5,397 microseconds goto FiveMSDelay ; resulting in a delay of 5.397 milliseconds clrf Delay1 ; ensure register is cleared for next debounce cycle movlw .248 ; reset Delay2 to its required value movwf Delay2 return end