The Sourcecode for the money checking unit is here. It's not too complex and written using the PIC-Wiz C compiler.
It's a nice tool that makes it easy to create coftware for PIC processors.
#pragma chip PIC16F73A
// The Play Game Button / Starts the Game Impulse
#pragma bit IN_PLAYBUTTON @ PORTB.7
// The Fregame Key Switch / Enables / Disables the Freegame mode
// if turned on longer then 5 secs,
// or simply gives a free game
#pragma bit IN_FREEGAMESWITCH @ PORTA.2
// The outputs from electronic money checking unit
#pragma bit IN_EMP0 @ PORTB.4 // 50 cent coin
#pragma bit IN_EMP1 @ PORTB.5 // 1 Euro coin
#pragma bit IN_EMP2 @ PORTB.6 // 2 Euro coin
// Locks the money checking unit
#pragma bit OUT_EMPLOCK @ PORTC.6
// Status LED output
#pragma bit OUT_STATUS @ PORTC.5
#pragma bit OUT_IMPULSE @ PORTC.4
#pragma bit OUT_LEDLATCH @ PORTC.7
#define FALSE 0
#define TRUE 1
#include "int16CXX.H"
// constants for impulse times
#define IMPULSE_ON_TIME 500
#define IMPULSE_OFF_TIME 10000
// constants for LED flash times
#define STATUS_FLASH_TIME_FAST 300
#define STATUS_FLASH_TIME_SLOW 700
#define WATCHDOG_COUNTER_SECS 160
// staus variables contrling the flow of operation
bit _EmpEnabled ;
// variable to remember the state of the LED
bit _StatusLightOn;
// Status values for programmflow
bit _Emp0Low;
bit _Emp1Low;
bit _Emp2Low;
bit _FreeGameSwitch0;
bit _FreeGameMode;
bit _PlayButton0;
// counts how long the freegameswitch was turned on
uns16 _FreeGameSwitchCounter;
// a counter used for status flashing
uns16 _FlashTime;
// how many credits where inserted
uns8 _Credits ;
uns8 _GamesPerCredit;
// how many games does teh user have ?
uns8 _Games;
// variables used for timing
uns16 _Timer0;
uns16 _Timer1;
uns16 _Timer2;
// variable used to indicate games / credits
uns8 _LedValue;
// the no one does anything time counter
uns16 _WatchDogCounter;
uns16 _WatchDogCounterSecs;
// a state variable indicating, that a game is currently running
bit _IsPlayingGame;
uns16 _ImpulseOnTime;
uns16 _ImpulseOffTime;
// here starts the interrupt service handler
#pragma origin 4
// the ISR
interrupt InterruptService( void)
{
int_save_registers // W, STATUS (and PCLATH)
if ( T0IF) {
/* TMR0 overflow interrupt */
TMR0 = -45;
T0IF = 0; /* reset flag */
}
if ( INTF) {
/* INT interrupt */
INTF = 0; /* reset flag */
}
if ( RBIF) {
/* RB port change interrupt */
W = PORTB; /* clear mismatch */
RBIF = 0; /* reset flag */
}
if ( TMR1IF == 1 ) {
TMR1IF = 0;
}
/*
NOTE: GIE is AUTOMATICALLY cleared on interrupt entry and set
to 1 on exit (by RETFIE). Setting GIE to 1 inside the
interrupt service routine will cause nested interrupts
if an interrupt is pending. Too deep nesting may crash
the program !
*/
int_restore_registers // W, STATUS (and PCLATH)
}
// this method can be used to delay n milliseconds
void Delay1ms( uns16 millisec)
// Delays a multiple of 1 milliseconds at 4 MHz
// using the TMR0 timer
{
char next = 0;
OPTION = 2; // prescaler divide TMR0 rate by 8
TMR0 = 2; // deduct 2*8 fixed instruction cycles delay
do {
next += 125;
clrwdt(); // needed only if watchdog is enabled
while (TMR0 != next) // 125 * 8 = 1000 (= 1 ms)
;
} while ( -- millisec != 0);
}
// reset the watchdog values
void ResetWatchDog(void)
{
_WatchDogCounter = 0;
_WatchDogCounterSecs = 0;
}
void Initialize(void){
INTCON = 0;
OPTION = 0; /* prescaler divide by 2 */
TMR0 = -45; /* 45 * 2 = 90 periods */
T0IE = 0; /* enabledisable TMR0 interrupt */
TMR1IE = 0; /* enable / disable 16bit timer 1 interrupt */
ADCON1 = 0x8E; /* set PORTA analog / digital input */
PORTA = 0;
TRISA = 0x4F; /* Set PORTA input / output Mode */
PORTB = 0xFF;
TRISB = 0xFF; /* Set PORTB in input mode */
PORTC = 0;
TRISC = 0x00; /* Set PORTC in output mode */
GIE = 0; /* interrupts enabled / disabled */
}
// enables / disables the emp lock
void EnableEmp( bit enabled )
{
// remember status
_EmpEnabled = enabled;
// set hardware
if (enabled)
{
OUT_EMPLOCK = FALSE;
}
else
{
OUT_EMPLOCK = TRUE;
}
}
/// displays a value from 0 - 9 on LED Display
void DisplayValue(int value){
OUT_LEDLATCH = TRUE;
// get the upper bits from port C into a temp value
int tempPortC = PORTC & 0xF0;
// get lower 4 bits from value
int tempValue = value & 0x0F;
// display the value
PORTC = tempPortC | tempValue;
OUT_LEDLATCH = FALSE;
}
// adds credit for the user
void AddCredits(uns8 credits){
ResetWatchDog();
do {
// increase _Credits value
_Credits ++;
// how many credits for coin
// -> read bcd value from port b
_GamesPerCredit = PORTB & 0x0F;
// set a minimumvalue for the user
if (_GamesPerCredit < 1){
_GamesPerCredit = 1;
}
// add value to credits
_Games += _GamesPerCredit;
}
while (--credits != 0);
DisplayValue(_Games);
EnableEmp(FALSE);
}
// reads the number of games per credit from PORTB
void GetGamesPerCredit(){
// how many credits for coin
// -> read bcd value from port b
_GamesPerCredit = PORTB & 0x0F;
// set a minimumvalue for the user
if (_GamesPerCredit < 1) {
_GamesPerCredit = 1;
}
}
// checks - if a coin was inserted and adds credits if so
void CheckEmpInput( void ) {
// we check for money input only if EMP is enabled
if (_EmpEnabled){
// check for 50 Cent
if (IN_EMP0 == FALSE){
// set state flag
_Emp0Low = TRUE;
} else {
if (_Emp0Low == TRUE){
// after low impulse we add a credit
_Emp0Low = FALSE;
AddCredits(1);
}
}
// check for 1 Euro coin
if (IN_EMP1 == FALSE){
// set state flag
_Emp1Low = TRUE;
} else {
if (_Emp1Low == TRUE) {
// after low impulse we add a credit
_Emp1Low = FALSE;
AddCredits(2);
}
}
// check for 2 Euro coin
if (IN_EMP2 == FALSE){
// set state flag
_Emp2Low = TRUE;
} else {
if (_Emp2Low == TRUE){
// after low impulse we add a credit
_Emp2Low = FALSE;
AddCredits(4);
}
}
}
}
// Enables a game impulse
void PlayGame() {
// set current state to playing
if (!_IsPlayingGame) {
_IsPlayingGame = TRUE;
_ImpulseOnTime = 0;
_ImpulseOffTime = 0;
// reset watchdog counter
ResetWatchDog();
}
}
// checks the state of the user play button
void CheckPlayButtonInput() {
// if the user hasn't Games -> exit
if (_Games < 1 ) return;
// if already playing game, wait until finished
if (_IsPlayingGame) return;
// check button state
if(IN_PLAYBUTTON == FALSE) {
// remember state
_PlayButton0 = TRUE;
} else {
// check if button was released
if (_PlayButton0) {
_PlayButton0 = FALSE;
PlayGame();
}
}
}
// checks, if game impulse is enabled and pulses output
void CheckGameImpulse() {
// when game is running
if (_IsPlayingGame) {
if (_ImpulseOnTime < IMPULSE_ON_TIME) {
_ImpulseOnTime ++;
OUT_IMPULSE = TRUE;
} else {
OUT_IMPULSE = FALSE;
if (_ImpulseOffTime < IMPULSE_OFF_TIME) {
_ImpulseOffTime ++;
} else {
// decrease gamecount
if (_Games > 0) {
_Games --;
DisplayValue(_Games);
}
_IsPlayingGame = FALSE;
}
}
} else {
// disable impulse output
OUT_IMPULSE = FALSE;
}
}
// resets the application values and hardware to defaults
void SoftReset(void) {
// disable impulse output
OUT_IMPULSE = FALSE;
// reset its state variables
_IsPlayingGame = FALSE;
_ImpulseOnTime = 0;
_ImpulseOffTime = 0;
// reset FreeGame modus
_FreeGameMode = FALSE;
// reset the watchdog
_WatchDogCounter = 0;
_WatchDogCounterSecs = 0;
// reset credits and game values
_Credits = 0;
_Games = 0;
// reset LED counter on PCB
_LedValue = 0;
// Inserting money is possible now
EnableEmp(TRUE);
// display number of credits on LED
DisplayValue(_Credits);
}
// checks the state of the freegame switch
void CheckFreeGameInputSwitch() {
// check the input state
// off state means high
if ( IN_FREEGAMESWITCH == 0) {
// is it first time check ?
if (_FreeGameSwitch0) {
// we count the time the switch was turned on
_FreeGameSwitchCounter ++;
} else {
// remember state
_FreeGameSwitch0 = TRUE;
// reset counter
_FreeGameSwitchCounter = 0;
}
} else {
// check if switch was turned off
if (_FreeGameSwitch0) {
// reset flag
_FreeGameSwitch0 = FALSE;
// if we where in free game mode -> reset
// check the time how long the switch was turned on
if (_FreeGameSwitchCounter < 5000) {
if (_Games > 0) {
_FreeGameMode = FALSE;
SoftReset();
} else {
AddCredits(1);
}
} else {
_FreeGameMode = TRUE;
AddCredits(2000);
}
}
}
}
// enables / disables statuslight
void SetStatusLight(bit enabled) {
_StatusLightOn = enabled;
OUT_STATUS = enabled;
}
// enables / disables the led status light, depending on programmstate
void CheckStatusLight(void) {
// when playimpulse is active, flash LED fast
if (_IsPlayingGame) {
if(_FlashTime < STATUS_FLASH_TIME_FAST) {
_FlashTime ++;
} else {
// Toggle the state of the LED
SetStatusLight(!_StatusLightOn);
// reset counter
_FlashTime = 0;
}
} else {
// when Games -> LED On
if (_Games > 0) {
SetStatusLight(TRUE);
} else {
// No Games, waiting for money or freegame
if(_FlashTime < STATUS_FLASH_TIME_SLOW) {
_FlashTime ++;
} else {
// Toggle the state of the LED
SetStatusLight(!_StatusLightOn);
// reset counter
_FlashTime = 0;
}
}
}
}
// check the WatchdogCOunter value,
// if nothing has happened for a long time
// automatically play a game
void CheckWatchdogCounter(void) {
if (_WatchDogCounter < 1000) {
_WatchDogCounter ++;
return;
}
_WatchDogCounter = 0;
if (_WatchDogCounterSecs < WATCHDOG_COUNTER_SECS) {
_WatchDogCounterSecs ++;
return;
}
_WatchDogCounterSecs = 0;
if (!_FreeGameMode) {
_Games = 1;
}
PlayGame();
}
// the main application loop
void main(void) {
// initialising the ports, setting defaults and enables interrupts, etc.
Initialize();
// reset to default software state
SoftReset();
while(1) {
// check, if someone has inserted money,
// pressed the playbutton,
// or enabled / disabled freegame mode
CheckFreeGameInputSwitch();
// check, in what state we are
if (_FreeGameMode == FALSE) {
CheckEmpInput();
}
// Disable / Enable Emp
if (_Games > 0) {
EnableEmp(FALSE);
CheckPlayButtonInput();
} else {
EnableEmp(TRUE);
}
// check if game is in playing state
CheckGameImpulse();
// set statuslights
CheckStatusLight();
// check watchdog, if we play a game automatically
CheckWatchdogCounter();
// delay 1 millisecond
Delay1ms(1);
}
}