/*
Slot Machine
Ver. 2023.05.15
Management of slot machine operations.
Arduino Nano runs three stepper motors and a sound card.
https://www.arduino.cc/reference/en/
Electrical Components
Arduino NANO
https://store-usa.arduino.cc/products/arduino-nano?selectedStore=us
Three stepper motors, 4SHG-240A46S
Three stepper motor drivers, DRV8825
https://www.pololu.com/product/2133
DFPlayer Mini MP3 Player
https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299
Three Optic Sensors
Switch
Power Supply Arduino Stepper motor drivers Stepper motor Optic Sensors DFPlayer Start Switch
24VDC ----------------------> VIN (1,2,3) -------------> Pin 6 (1,2,3)
12VDC ----------> VIN
5 VDC ----------------------> V (1,2,3) --------------------------------> Pin 8 (1,2,3)---> VCC
|--> DIR
GND ------------> GND ------> GND, G (1,2,3) ---------------------------> Pin 10(1,2,3)---> GND --------> Pin
|--> EN
1A (1,2,3) ----------------> Pin 4 (1,2,3)
1B (1,2,3) ----------------> Pin 2 (1,2,3)
2A (1,2,3) ----------------> Pin 3 (1,2,3)
2B (1,2,3) ----------------> Pin 1 (1,2,3)
D2 -------> STEP (1)
D3 ---------------------------------------------------> Pin 9 (1)
D4 -------> STEP (2)
D5 ---------------------------------------------------> Pin 9 (2)
D6 -------> STEP (3)
D7 ---------------------------------------------------> Pin 9 (3)
D8 -----------------------------------------------------------------------------------> Pin
D9
D10 --------------------------------------------------------------------> TX
D11 --------------------- (R 10K) --------------------------------------> RX
D12
D13
# -------------------------- #
# Design by Ephraim Herman #
# -------------------------- #
*/
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
const int NUM_WHEEL_STEPS = 11;
const int STEPS_PER_REVOLUTION = 200;
const float WHEEL_ONE_STEP_INTERVAL = STEPS_PER_REVOLUTION / NUM_WHEEL_STEPS;
const int BONUS_JACKPOT = 5;
const int CHERRIES = 4;
const int DOUBLE_BAR = 1;
const int MYDFPLAYER_BUSY_PIN = 9;
const int NUM_OF_WHEELS = 3;
const int ONE_BAR = 0;
const int POSITION_PIN_1 = 3;
const int POSITION_PIN_2 = 5;
const int POSITION_PIN_3 = 7;
const int SEVEN = 3;
const int STEP_PIN_1 = 2;
const int STEP_PIN_2 = 4;
const int STEP_PIN_3 = 6;
const int SWITCH_PIN = 8;
const int TRIPLE_BAR = 2;
const int WHEEL_1 = 0;
const int WHEEL_2 = 1;
const int WHEEL_3 = 2;
const int WON_IN_THE_GAME_005 = 5;
const int LOST_IN_THE_GAME_004 = 4;
const int THE_GAME_STARTED_001 = 1;
const int THE_WHEELS_ARE_SPINNING_002 = 2;
const int THE_WHEEL_STOPPED_003 = 3;
/*
// DIR = HIGH; =====================================================
const int WHEEL_RESULTS[NUM_OF_WHEELS][NUM_WHEEL_STEPS] = {
{ONE_BAR, DOUBLE_BAR, SEVEN, ONE_BAR, BONUS_JACKPOT, TRIPLE_BAR,
CHERRIES, DOUBLE_BAR, SEVEN, TRIPLE_BAR, BONUS_JACKPOT},
{DOUBLE_BAR, ONE_BAR, SEVEN, DOUBLE_BAR, BONUS_JACKPOT, TRIPLE_BAR,
CHERRIES, ONE_BAR, SEVEN, TRIPLE_BAR, BONUS_JACKPOT},
{ONE_BAR, TRIPLE_BAR, SEVEN, ONE_BAR, BONUS_JACKPOT, DOUBLE_BAR,
CHERRIES, TRIPLE_BAR, SEVEN, DOUBLE_BAR, BONUS_JACKPOT}};
*/
// DIR = LOW; ======================================================
const int WHEEL_RESULTS[NUM_OF_WHEELS][NUM_WHEEL_STEPS] = {
{ONE_BAR, BONUS_JACKPOT, TRIPLE_BAR, SEVEN, DOUBLE_BAR, CHERRIES,
TRIPLE_BAR, BONUS_JACKPOT, ONE_BAR, SEVEN, DOUBLE_BAR},
{DOUBLE_BAR, BONUS_JACKPOT, TRIPLE_BAR, SEVEN, ONE_BAR, CHERRIES,
TRIPLE_BAR, BONUS_JACKPOT, DOUBLE_BAR, SEVEN, ONE_BAR},
{ONE_BAR, BONUS_JACKPOT, DOUBLE_BAR, SEVEN, TRIPLE_BAR, CHERRIES,
DOUBLE_BAR, BONUS_JACKPOT, ONE_BAR, SEVEN, TRIPLE_BAR}};
// DIR end. =======================================================
const int whellMaxDelayTime = 16;
const int whellMinDelayTime = 2;
boolean gameCycleHasBegun = false;
boolean firstRun = true;
boolean myDFPlayerOK = false;
boolean wheelActive[NUM_OF_WHEELS] = {false, false, false};
int wheelRandomPosition[NUM_OF_WHEELS] = {0, 0, 0};
int stopPosition[NUM_OF_WHEELS] = {0, 0, 0};
int wheelPosition[NUM_OF_WHEELS] = {0, 0, 0};
int presetMode = 0;
unsigned long blindTime = 0;
unsigned long buttonPressTime = 0;
unsigned long buttonReleaseTime = 0;
unsigned long minimuActicrTime[NUM_OF_WHEELS] = {0, 0, 0};
unsigned long nextPositionTime[NUM_OF_WHEELS] = {0, 0, 0};
unsigned long nextStepTime[NUM_OF_WHEELS] = {0, 0, 0};
unsigned long stepTime[NUM_OF_WHEELS] = {0, 0, 0};
void playMelody(int trackNum) {
if (!firstRun) {
myDFPlayer.volume(20);
myDFPlayer.play(trackNum);
}
}
boolean ifSwitchReleased(boolean currentSwitchStat) {
static boolean lastSwitchStat = HIGH;
if (gameCycleHasBegun) return false;
if (currentSwitchStat != lastSwitchStat) {
blindTime = millis() + 100;
lastSwitchStat = currentSwitchStat;
if (currentSwitchStat == HIGH) {
buttonReleaseTime = millis();
} else {
buttonPressTime = millis();
}
return currentSwitchStat;
} else {
return false;
}
}
void startWheelActuation(int wheelIndex) {
wheelActive[wheelIndex] = true;
stepTime[wheelIndex] = whellMaxDelayTime;
nextPositionTime[wheelIndex] = millis() + 1000;
wheelPosition[wheelIndex] = -1;
if (firstRun == true) {
minimuActicrTime[wheelIndex] = millis() + 2000;
if (myDFPlayerOK == true) {
wheelRandomPosition[wheelIndex] = 2;
} else {
wheelRandomPosition[wheelIndex] = 6;
}
} else {
minimuActicrTime[wheelIndex] = millis() + random(5000, 10000);
if (presetMode == -1) {
wheelRandomPosition[wheelIndex] = random(NUM_WHEEL_STEPS);
} else {
wheelRandomPosition[wheelIndex] = 0;
while (WHEEL_RESULTS[wheelIndex][wheelRandomPosition[wheelIndex]] != presetMode) wheelRandomPosition[wheelIndex]++;
}
}
stopPosition[wheelIndex] = int(WHEEL_ONE_STEP_INTERVAL * wheelRandomPosition[wheelIndex]);
}
void nextStep(int wheelIndex) {
if (millis() > nextStepTime[wheelIndex]) {
if (stepTime[wheelIndex] > whellMinDelayTime) stepTime[wheelIndex]--;
if (digitalRead(wheelIndex * 2 + 2) == LOW) {
digitalWrite(wheelIndex * 2 + 2, HIGH);
nextStepTime[wheelIndex] = millis() + whellMinDelayTime;
} else {
digitalWrite(wheelIndex * 2 + 2, LOW);
nextStepTime[wheelIndex] = millis() + stepTime[wheelIndex];
if (wheelPosition[wheelIndex] != -1) wheelPosition[wheelIndex] = (wheelPosition[wheelIndex] + 1) % STEPS_PER_REVOLUTION;
}
}
}
void checkWheelPosition(int wheelIndex) {
if (millis() > nextPositionTime[wheelIndex]) {
if (digitalRead((wheelIndex + 1) * 2 + 1) == LOW) {
wheelPosition[wheelIndex] = 0;
nextPositionTime[wheelIndex] = millis() + 1000;
}
}
}
void stopWheelIfReachedDestination(int wheelIndex) {
if (millis() > minimuActicrTime[wheelIndex]) {
if (wheelPosition[wheelIndex] == stopPosition[wheelIndex]) {
playMelody(THE_WHEEL_STOPPED_003);
wheelActive[wheelIndex] = false;
}
}
}
void setup() {
delay(1000);
mySoftwareSerial.begin(9600);
delay(1000);
randomSeed(analogRead(0));
myDFPlayerOK = myDFPlayer.begin(mySoftwareSerial);
if (myDFPlayerOK) myDFPlayer.setTimeOut(500);
pinMode(STEP_PIN_1, OUTPUT);
pinMode(POSITION_PIN_1, INPUT_PULLUP);
pinMode(STEP_PIN_2, OUTPUT);
pinMode(POSITION_PIN_2, INPUT_PULLUP);
pinMode(STEP_PIN_3, OUTPUT);
pinMode(POSITION_PIN_3, INPUT_PULLUP);
pinMode(SWITCH_PIN, INPUT_PULLUP);
pinMode(MYDFPLAYER_BUSY_PIN, INPUT_PULLUP);
firstRun = true;
gameCycleHasBegun = false;
}
void loop() {
if (millis() > blindTime || firstRun == true) {
if (ifSwitchReleased(digitalRead(SWITCH_PIN)) || firstRun == true) {
firstRun = false;
gameCycleHasBegun = true;
playMelody(THE_GAME_STARTED_001);
delay(3000);
playMelody(THE_WHEELS_ARE_SPINNING_002);
if (buttonReleaseTime - buttonPressTime > 3000 && buttonReleaseTime - buttonPressTime < 5000) {
presetMode = random(6);
} else {
presetMode = -1;
}
for (int wheelIndex = 0; wheelIndex < NUM_OF_WHEELS; wheelIndex++) if (!wheelActive[wheelIndex]) startWheelActuation(wheelIndex);
}
}
for (int wheelIndex = 0; wheelIndex < NUM_OF_WHEELS; wheelIndex++) {
if (wheelActive[wheelIndex]) {
nextStep(wheelIndex);
checkWheelPosition(wheelIndex);
stopWheelIfReachedDestination(wheelIndex);
}
}
if (gameCycleHasBegun) {
if (wheelActive[WHEEL_1] == false && wheelActive[WHEEL_2] == false && wheelActive[WHEEL_3] == false) {
if (WHEEL_RESULTS[WHEEL_1][wheelRandomPosition[WHEEL_1]] == WHEEL_RESULTS[WHEEL_2][wheelRandomPosition[WHEEL_2]] && WHEEL_RESULTS[WHEEL_1][wheelRandomPosition[WHEEL_1]] == WHEEL_RESULTS[WHEEL_3][wheelRandomPosition[WHEEL_3]]) {
playMelody(WON_IN_THE_GAME_005);
} else {
playMelody(LOST_IN_THE_GAME_004);
}
gameCycleHasBegun = false;
}
}
}