Control Board Finished
We just moved into a new office and since I didn’t have any real work to do I’ve been committing the control board that communicates with the coin hopper. Ironically I haven’t had the internet this whole time I’ve been working on it which makes it extremely frustrating trying to figure stuff out and now that I’ve got it working the internet has come back on!
I read the first couple of chapters of this book…
… which was extremely helpful for understanding how PIC’s work and how they need to be hooked up to a circuit board. Also the data sheet for the PIC16F84A (the chip i used) is pretty gnarly looking at first but after reading it like 50 times it proves pretty useful.
Heres a picture of the control board in its current state:
This is what it does:
- PIC16F84A manages the count of coins inside the machine
- Coin mech switch triggers the increment count function
- Inside the PIC the count is maintained in EEPROM and volatile RAM, this is because it’s easier to manipulate data in the RAM and then update the EEPROM.
- The increment function increments the RAM count then updates the count in the EEPROM to equal the RAM count.
- PIC16F84A have 8 bit registers which means that one register can only count up to 256, since we need to be able to count up to 800 (the amount the hopper holds) we need to use 2 registers, these are COUNT1 and COUNT2. The starting values for 0 coins should be 0 in COUNT1 and 1 in COUNT2. The reason for this is when we are decrementing the count using DECFSZ the program flow will branch depending if the result of the decrement is 0 or not 0. We can assume COUNT1 will always be at least one when it comes time to spit out the coins because the player could not have got to the end of the game without putting in any money, however COUNT2 must start at 1 so when the COUNT2 decrement occurs (ie after COUNT1 reaches 0) we get a 0 instead of a 255.
- The switch connected to RA1 is used to query the number of coins in the machine, this is only used for testing and i haven’t implemented logic to deal with counts over 256. When the switch is pressed the LED on RB0 will flash a number of times equal to the number of coins in the machine.
- The switch on RA2 resets the EEPROM (and the local count) by setting the local COUNT1 AND COUNT2 to 0 and 1 respectively and copying those values to EEPROM.
- The switch on RA3 initiates a payout, i still have to implement some kind of serial or parallel communication with the PC and MAME, currently its just a push button switch.
- The LED connected to RB1 lights up when the EEPROM is being written
- The LED connected to RB3 lights up when a coin is dispensed
- RB2 controls the hoppers motor, 5v for on, 0v for off
Here is a picture of the circuit diagram:

Here is my source code for the PIC so far also, I can’t really be bothered going over it right now, might do a better description later, right now i want to figure out the PC - PIC communication
;**************************************************************************
;* COIN COUNTER *
;**************************************************************************
;* (C) DIRK & DIRK,2009 All rights reserved *
;* Hardware & software by Dirk *
;**************************************************************************
;* Hardw. Rev: 1 Softw. Rev: 1.01 *
;* OSC.......: XT 4MHz Max. POWER.....: 5V DC *
;**************************************************************************
;==========================================================================
; Counts coins:
; - Each coin triggers an update to the EEPROM
; - Count is maintained in EEBYTE1 & EEBYTE2 and volatile
; variables COUNT1 & COUNT2
; - LED connected to RB0 flashes x times; where x is the coin
; count
; - NOTE: Querying the count when it's 0 or over 256 will produce
; odd effects
; - LED connected to RB1 is on when EEPROM is being written
; - RA0: Increment count
; - RA1: Query value of coin count
; - RA2: Reset EEPROM
;==========================================================================
;==========================================================================
;
; Configuration Bits
;
;==========================================================================
_CP_ON EQU H'000F'
_CP_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_PWRTE_OFF EQU H'3FFF'
_WDT_ON EQU H'3FFF'
_WDT_OFF EQU H'3FFB'
_LP_OSC EQU H'3FFC'
_XT_OSC EQU H'3FFD'
_HS_OSC EQU H'3FFE'
_RC_OSC EQU H'3FFF'
__CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
;==========================================================================
;
; Register Definitions
;
;==========================================================================
W EQU H'0000'
F EQU H'0001'
;----- Register Files------------------------------------------------------
INDF EQU H'0000'
TMR0 EQU H'0001'
PCL EQU H'0002'
STATUS EQU H'0003'
FSR EQU H'0004'
PORTA EQU H'0005'
PORTB EQU H'0006'
EEDATA EQU H'0008'
EEADR EQU H'0009'
PCLATH EQU H'000A'
INTCON EQU H'000B'
OPTION_REG EQU H'0081'
TRISA EQU H'0085'
TRISB EQU H'0086'
EECON1 EQU H'0088'
EECON2 EQU H'0089'
;----- STATUS Bits --------------------------------------------------------
IRP EQU H'0007'
RP1 EQU H'0006'
RP0 EQU H'0005'
NOT_TO EQU H'0004'
NOT_PD EQU H'0003'
Z EQU H'0002'
DC EQU H'0001'
C EQU H'0000'
;----- INTCON Bits --------------------------------------------------------
GIE EQU H'0007'
EEIE EQU H'0006'
T0IE EQU H'0005'
INTE EQU H'0004'
RBIE EQU H'0003'
T0IF EQU H'0002'
INTF EQU H'0001'
RBIF EQU H'0000'
;----- OPTION_REG Bits ----------------------------------------------------
NOT_RBPU EQU H'0007'
INTEDG EQU H'0006'
T0CS EQU H'0005'
T0SE EQU H'0004'
PSA EQU H'0003'
PS2 EQU H'0002'
PS1 EQU H'0001'
PS0 EQU H'0000'
;----- EECON1 Bits --------------------------------------------------------
EEIF EQU H'0004'
WRERR EQU H'0003'
WREN EQU H'0002'
WR EQU H'0001'
RD EQU H'0000'
;INPUTS
SW1 EQU H'00' ;SW1 is triggering RA0 (Increment)
SW2 EQU H'01' ;SW2 is triggering RA1 (Flash value of count times on RB0)
SW3 EQU H'02' ;SW3 is triggering RA2 (Reset EEPROM)
SW4 EQU H'03' ;SW4 is triggering RA3 (Signal payout)
SW5 EQU H'04' ;SW5 is triggering RB4 (decrement coin signal)
;OUTPUTS
PO EQU H'02' ;PO is triggering RA4 (switch on coin hopper motor)
;==========================================================================
;
; RAM Definition
;
;==========================================================================
__MAXRAM H'CF'
__BADRAM H'07', H'50'-H'7F', H'87'
;==========================================================================
;
; Variables
;
;==========================================================================
COUNT1 EQU H'0C' ;Local count byte 1
COUNT2 EQU H'0D' ;Local count byte 2
DECRM EQU H'0E' ;Stores temp value of count for flashing
TIMER1 EQU H'0F' ;Timer 1, Used for general delay
TIMER2 EQU H'10' ;Timer 2, used for delay !
FREQCOUNT EQU H'11' ;Frequency counter
;==========================================================================
;
; EEPROM Variables
;
;==========================================================================
EEBYTE1 EQU H'00' ;Stores the first byte of the count in the eeprom
EEBYTE2 EQU H'01' ;Stores the second byte of the count in the eeprom
ORG 0 ;Setting Reset vector, reset vector address is 000h in PIC16F84
GOTO RESET ;Jump to RESET procedure when boot-up PIC device.
;**************************
;* main routine: *
;**************************
RESET BSF STATUS,RP0 ;Jump to bank 1 of PIC16F84 to access special registers.
MOVLW B'00001111' ;Config Port A, Low nibble = Ra0 are inputs, high nibble not implemented.
MOVWF TRISA ;Set I/O configuration for PORTA
MOVLW B'00010000' ;Rb7...Rb0 are outputs.
MOVWF TRISB ;Set I/O configuration for PORTB
BCF STATUS,RP0 ;Jump back to bank 0 of PIC.
CLRF PORTA ;Clear all I/O's of PORTA
CLRF PORTB ;Clear all I/O's of PORTB
CALL FETCHEEPROM
;Loop starts here !!!
LOOP BTFSC PORTA,SW1 ;See if button 1 is on (increment button)
CALL INCREM ;Increment the count
BTFSC PORTA,SW2 ;See if button 2 is down (flash the number of the count)
CALL SHOWCOUNT ;Start flasher
BTFSC PORTA,SW3 ;See if button 3 is on (reset eeprom)
CALL RESETEEPROM ;Reset eeprom
BTFSC PORTA,SW4 ;See if button 4 is on (payout signal)
CALL PAYOUT ;Begin payout function
GOTO LOOP
;*******************
;* Payout function *
;*******************
PAYOUT CALL PAYON ;Switch hopper motor on
CALL DELAY
; Probably not the right way to do it but this part checks the switch 5 times to make
; sure it isn't that weird spiking thing.
P1 BTFSS PORTB,4 ;Is the coin decrement switch on?
GOTO P1 ;No
BTFSS PORTB,4 ;Is the coin decrement switch on?
GOTO P1 ;No
BTFSS PORTB,4 ;Is the coin decrement switch on?
GOTO P1 ;No
BTFSS PORTB,4 ;Is the coin decrement switch on?
GOTO P1 ;No
BTFSS PORTB,4 ;Is the coin decrement switch on?
GOTO P1 ;No
BSF PORTB,3 ;Real decr switch occurred, switch light on
P2 BTFSC PORTB,4 ;Is the coin decrement switch up?
GOTO P2 ;No
BCF PORTB,3 ;End of decr switch, turn off light
DEC1 DECFSZ COUNT1,1 ;Decrement first count byte
GOTO P1 ;COUNT1 != 0, so go back to P1
DECFSZ COUNT2,1 ;COUNT1 == 0, now check COUNT2
GOTO DEC2 ;COUNT2 != 0, so set COUNT1 = D'255' then go back to P1
GOTO DEC3 ;COUNT2 == 0, hopper is empty, go to DEC3 to halt and clean up
DEC2 MOVLW H'FF' ;
MOVWF COUNT1 ;Set count back to FF (256)
GOTO P1 ;Start checking for clicks again
DEC3 CALL PAYOFF ;Switch of the motor
CALL RESETEEPROM ;Reset count to 0 (count1:0, count2:1)
RETURN
; BCF PORTB,3 ;FOO: This is just to check if a switch signal is received from the hopper
;P2 BTFSC PORTB,SW5 ;Is the coin dec switch off?
; GOTO P2 ;No, go back
; Here one switch from the hopper has occurred, now decrement count
; and check to see if we are at 0
;DEC1 DECFSZ COUNT1,1 ;Decrement first count byte
; GOTO P1 ;COUNT1 != 0, so go back to P1
; DECFSZ COUNT2,1 ;COUNT1 == 0, now check COUNT2
; GOTO DEC2 ;COUNT2 != 0, so set COUNT1 = D'255' then go back to P1
; GOTO DEC3 ;COUNT2 == 0, hopper is empty, go to DEC3 to halt and clean up
;DEC2 MOVLW H'FF' ;
; MOVWF COUNT1 ;Set count back to FF (256)
; GOTO P1 ;Start checking for clicks again
;DEC3 CALL PAYOFF ;Switch of the motor
; CALL RESETEEPROM ;Reset count to 0 (count1:0, count2:1)
; RETURN
;TEMPTEMPTEMPTEMPTEMPTEMPTEMPTEMP
;LED4ON MOVLW H'01'
; MOVWF FREQCOUNT
;ITSON BTFSS PORTB,SW5
; GOTO STILLON
; GOTO GONEOFF
;STILLON DECFSZ FREQCOUNT,1
; GOTO ITSON
;LOOPER BSF PORTB,3
; GOTO LOOPER
;GONEOFF GOTO P1
;LED4OFF BCF PORTB,3
; GOTO P1
;PAYOUT BTFSC PORTA,SW4 ;Is button down?
; GOTO PAYON ;Yes
; GOTO PAYOFF ;No
;**********************
;* Payout on function *
;**********************
PAYON BSF PORTB,PO ;Set PO pin to high
RETURN
;***********************
;* Payout off function *
;***********************
PAYOFF BCF PORTB,PO ;Set PO pin to low
RETURN ;
;******************************
;* Count incrementer function *
;******************************
INCREM BTFSC PORTA,SW1 ;Make sure they aren't still holding down the button
GOTO INCREM ;
CALL DELAY ;Short delay for mechanical bouncing on the button
INCFSZ COUNT1,1 ;Increment COUNT1 register
GOTO WRTRET ;Go to write then return section if COUNT1 didn't click over to 0
INCFSZ COUNT2,1 ;Increment COUNT2 register if COUNT1 did click over to 0
WRTRET CALL SETEEPROM ;
RETURN ;
;********************
;* Flasher function *
;********************
;##############################################################################################################
;################ FOO: NEEDS TO BE UPDATED FOR 2 BYTE COUNT ###################################################
;##############################################################################################################
SHOWCOUNT BTFSC PORTA,SW2 ;Make sure they aren't still holding down the button
GOTO SHOWCOUNT ;
MOVF COUNT1,0 ;Move the count to W
MOVWF DECRM ;Move W to decrm register
MORECOUNT CALL LED1ON ;Switch LED on
CALL DELAY ;Wait
CALL LED1OFF ;Switch LED off
CALL DELAY ;Wait
DECFSZ DECRM,1 ;Decrement count
GOTO MORECOUNT
RETURN
;*******************************************************
;* Fetches count from EEPROM, moves to COUNT1 & COUNT2 *
;*******************************************************
FETCHEEPROM MOVLW EEBYTE1 ;Grab first byte
MOVWF EEADR ;Address to read
BSF STATUS,RP0 ;Bank 1
BSF EECON1,RD ;EE read
BCF STATUS,RP0 ;Bank 0
MOVF EEDATA,0 ;Copy EEDATA to W
MOVWF COUNT1 ;Copy EEDATA (from W) to COUNT1
MOVLW EEBYTE2 ;Grab second byte
MOVWF EEADR ;Address to read
BSF STATUS,RP0 ;Bank 1
BSF EECON1,RD ;EE read
BCF STATUS,RP0 ;Bank 0
MOVF EEDATA,0 ;Copy EEDATA to W
MOVWF COUNT2 ;Copy EEDATA (from W) to COUNT2
RETURN
;******************************
;* Reset EEPROM function *
;* - Sets COUNT1 & COUNT2 to *
; 0 then writes the EEPROM *
;******************************
RESETEEPROM MOVLW H'0' ;Move 0 into W
MOVWF COUNT1 ;Move W into COUNT1
MOVLW H'1' ;Move 0 into W
MOVWF COUNT2 ;Move 0 into COUNT2
CALL SETEEPROM ;Now set EEPROM since COUNT1 & COUNT2 are 0
RETURN ;Return from reset call
;**************************************
;* Set EEPROM function *
;* - Writes COUNT1 & COUNT2 to EEPROM *
;**************************************
; Write the first byte
SETEEPROM CALL LED2ON ;Turn on LED 2 to show it's writing
BCF STATUS,RP0 ;Bank 0
MOVF COUNT1,0 ;Move COUNT1 into EEDATA for writing
MOVWF EEDATA
MOVLW EEBYTE1 ;Address to read from (EEBYTE1)
MOVWF EEADR
BSF STATUS,RP0 ;Bank 1
BCF INTCON,GIE ;Disable interrupts
BSF EECON1,WREN ;Enable write
MOVLW H'55' ;Confirm write 1
MOVWF EECON2 ;
MOVLW H'AA' ;Confirm write 2
MOVWF EECON2 ;
BSF EECON1,WR ;Set WR bit, begin write
BSF INTCON,GIE ;Enable INT's
CALL WAITFOREE ;Wait for EE to be written
; Write the second byte
BCF STATUS,RP0 ;Bank 0
MOVF COUNT2,0 ;Move COUNT2 into EEDATA for writing
MOVWF EEDATA
MOVLW EEBYTE2 ;Address to read from (EEBYTE2)
MOVWF EEADR
BSF STATUS,RP0 ;Bank 1
BCF INTCON,GIE ;Disable interrupts
BSF EECON1,WREN ;Enable write
MOVLW H'55' ;Confirm write 1
MOVWF EECON2 ;
MOVLW H'AA' ;Confirm write 2
MOVWF EECON2 ;
BSF EECON1,WR ;Set WR bit, begin write
BSF INTCON,GIE ;Enable INT's
CALL WAITFOREE ;Wait for EE to be written
BCF STATUS,RP0 ;Bank 0
CALL LED2OFF ;Switch off LED to show stopped writing
RETURN ;End of reset EEPROM function
;**********************************
;* Waits for EEPROM to be written *
;**********************************
WAITFOREE BTFSC EECON1,WR ;Check if WR is still 1
GOTO WAITFOREE ;Yes, go back
RETURN ;No return
;*******************
;* LED 1 on function *
;*******************
LED1ON BSF PORTB,0
RETURN
;********************
;* LED 1 off function *
;*********************
LED1OFF BCF PORTB,0
RETURN
;*********************
;* LED 2 on function *
;*********************
LED2ON BSF PORTB,1
RETURN
;**********************
;* LED 2 off function *
;**********************
LED2OFF BCF PORTB,1
RETURN
;******************
;* Delay function *
;******************
DELAY MOVLW D'250' ;* ;Put 150 decimal in the 'TIMER1' register.
MOVWF TIMER1 ;*
;
DELAY2 MOVLW D'250' ;Put 150 decimal in the 'TIMER2' register.
MOVWF TIMER2
DECFSZ TIMER2,F ;* ;Timer2 = Timer2 -1, skip next instruction if Timer2 = 0.
GOTO $-1 ;* ;Jump back 1 instruction.
DECFSZ TIMER1,F ;Timer1 = Timer1 - 1, skip next instruction if Timer1 = 0
GOTO DELAY2 ;Jump to 'DELAY2' routine
RETLW 0 ;Return (jump back to main) and load W-reg with 0.
END ;End of source code.

Hi,
Interesting, I`ll quote it on my site later.
Thanks
Hobosic
Hi,
I have already seen it somethere…
Have a nice day
Dirnov
Dirnov: Where have you seen it? I would like see another one!
Hobosic: Thanks for the comments!
Greatings,
Amazing! Not clear for me, how offen you updating your http://www.dirkdirk.com.
Thank you
Tania
@tania: i admit the whole blog is pretty all over the place! once the project is finished i will try clean it up into a nice tutorial format. I’m not updating dirkdirk as much as i would like too as i am very busy with lab fiftyfive, i think theres a link to it somewhere on the front page
keep checking back though, i will finish this project one day!
wow, nice idea, also in the pic firmware, “checking the button 5 times to make sure its not the werid spiky thing” do you mean to debounce the circuit? a hardware built debounce circuit may be more reliable. nice overall though.
@ted: thanks! and yes, i just googled debounce and that was what i was trying to do. i’m completely new to electronics, i kind of just tried to figure out what i needed for each part without going too deep into any real theory, not for lack of interest, just lack of time. version 2 will be proper!