//template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
/***************************************************************
// Project Title: Counter from 0 to 9 with 7-Segments Display
// Date: 07.03.2024
// Last Update: 30.05.2024
// Author: Jose Baptista
// Parts List:
// - ESP32
//
//
//
// Descrition:
*/
#include "esp_timer.h"
//#include "UIDs.h"
//#include <SPI.h> // Library SPI
//#include <MFRC522.h> // Library MFRC522
//for the ServoMotor
#include <ESP32Servo.h>
//for the DFMiniplayer
//#include <DFRobotDFPlayerMini.h>
//#include <SoftwareSerial.h>
//*******************************************************
//
// Set global parameters for the program
//
//*******************************************************
// 75HC595 **********************************************
#define Clock_PIN 0 // pin 11 (SHCP) on shift register
#define Data_PIN 15 // pin 14 (DS) on shift register
#define Latch_PIN 2 // pin 12 (STCP) on shift register
//*******************************************************
// RFID RC522 *******************************************
#define Sda_PIN 5 // pin *
#define Sck_PIN 18 // pin *
#define Mosi_PIN 23 // pin *
#define Rst_PIN 13 // pin
#define Miso_PIN 19 // pin *
//*******************************************************
// Lights ***********************************************
//*******************************************************
// Buttons-Servo-LED ************************************
#define CoinRLED_PIN 4 // pin Red Led - System activated
#define CoinGLED_PIN 14 // pin Green Led - Game activated
#define Servo_PIN 12 // pin 12 como salida para el relay Release Ball
#define RedButton_PIN 21 // pin 2 como entrada para el home_sensor
#define BlueButton_PIN 17 // pin 3 como entrada para el visitor_sensor
#define ResetButton_PIN 22 // Reset the game
#define CoinButton_PIN 16 // pin 4 como entrada para el coin
//*******************************************************
//*******************************************************
//
// Init global variables
//
//*******************************************************
// Variables Constant ***********************************
const unsigned short BlueTeamWS = 1; // Blue Team Winning Sound
const unsigned short RedTeamWS = 2; // Red Team Winning Sound
const unsigned short GameResetS = 3; // Game Reset Sound
const unsigned short BallReleaS = 4; // Ball Released Sound
const unsigned short AccessDenS = 5; // Access Denied Sound
const unsigned short xVolume = 15; // Set volume value (0~30)
const unsigned short MinPulse = 600;
const unsigned short MaxPulse = 2400;
const unsigned short Interval1 = 50; // Variable Size From 0 to 65,535
const unsigned short Interval2 = 100;
const unsigned short Interval3 = 200;
const unsigned short Interval4 = 1000;
const unsigned int IntervalTime1 = 2000000; //
const unsigned int IntervalTime2 = 5000000;
//*******************************************************
// Variables Integer - Boolean **************************
byte ReadUID[4]; // Array to store the read UID - MFRC522
unsigned short mesarray;
unsigned short RedScore = 0, BlueScore = 0;
uint32_t PlayTrack;
unsigned long CurrentTime;
unsigned long PreviousTime = 0;
bool CoinDetected = false, ResetPressed = false;
bool CoinButtonState, ResetButtonState;
bool RedButtonState, BlueButtonState;
enum TrackType { BlueTeamScore, RedTeamScore, B_RTeamHot, GameOver, CrowdIsBored, SystemStart, SystemReset, SoundEffect };
template <class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
//*******************************************************
String Message [5]= {
"BlueTeamWS",
"RedTeamWS",
"GameResetS",
"BallReleaS",
"AccessDenS"};
/*
// Create valid UIDs Library ****************************
// Create card access data to activate the game *********
byte validUIDs[][4] = {
{0x8A, 0x5E, 0xB8, 0x89}, // UID of Player
{0x53, 0x15, 0x57, 0xC8}, // UID of Player
{0x12, 0x34, 0x56, 0x78}, // UID of Player
{0xAB, 0xCD, 0xEF, 0x12}, // UID of Player
};
//*******************************************************
*/
// Array Will display numbers from 0-9 ******************
// byte number[10] = { 63, 6, 91, 79, 102, 109, 125, 7, 127, 111 }; // 7-Segments Cathode - Decimal
byte number[10] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; // 7-Segments Cathode - Hexadecimal
// byte number[10] = { 192, 249, 164, 176, 153, 146, 130, 248, 128, 144 }; // 7-Segments Anode - Decimal
// byte number[10] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90 }; // 7-Segments Anode - Hexadecimal
//*******************************************************
// Numbers from 0-9 in Binary - 7-Segments Cathode ******
/*
AAAAA
F B
F B
F B
GGGGG
E D
E D
E D
CCCCC X
*/
// X = Decimal Point
// XGFEDCBA
// 11111111 = 8.
/*
byte number[10]= {
//Binary HEX Decimal Number
0b00111111, // 0X3F = 192 = 0
0b00000110, // 0x06 = 249 = 1
0b01011011, // 0x5B = 164 = 2
0b01001111, // 0x4F = 176 = 3
0b01100110, // 0x66 = 153 = 4
0b01101101, // 0x6D = 146 = 5
0b01111101, // 0x7D = 130 = 6
0b00000111, // 0x07 = 248 = 7
0b01111111, // 0x7F = 128 = 8
0b01101111}; // 0x6F = 144 = 9
*/
//*******************************************************
// Numbers from 0-9 in Binary - 7 segments Anode ********
/*
AAAAA
F B
F B
F B
GGGGG
E D
E D
E D
CCCCC X
*/
// X = Decimal Point
// XGFEDCBA
// 00000000 = 8.
/*
byte number[10]= {
//Binary HEX Decimal Number
0b11000000, // 0XC0 = 63 = 0
0b11111001, // 0xF9 = 6 = 1
0b10100100, // 0xA4 = 91 = 2
0b10110000, // 0xB0 = 79 = 3
0b10011001, // 0x99 = 102 = 4
0b10010010, // 0x92 = 109 = 5
0b10000010, // 0x82 = 125 = 6
0b11111000, // 0xF8 = 7 = 7
0b10000000, // 0x80 = 127 = 8
0b10010000}; // 0x90 = 111 = 9
*/
//*******************************************************
//*******************************************************
//
// Init objects
//
//*******************************************************
Servo myservo; // Create Servo object to control a Servo Motor
esp_timer_handle_t timer1, timer2;
//MFRC522 mfrc522(Sda_PIN, Rst_PIN); // Create MFRC522 instance
//set the software serial pins
//SoftwareSerial mySoftwareSerial(/*RX =*/3, /*TX =*/1); // RX, TX
//DFRobotDFPlayerMini myDFPlayer; // Create DFPlayer object to control a MP3
//void printDetail(uint8_t type, int value);
//*******************************************************
//
// Main Setup Method Call
//
//*******************************************************
void setup() {
// SPI.begin(); // Init SPI bus
// mfrc522.PCD_Init(); // Init mfrc522 module
// mySoftwareSerial.begin(9600); // Init the mySoftwareSerial port - DFRobotDFPlayerMini myDFPlayer
Serial.begin(115200); // Init the serial port
PlayTrack = esp_random(); // analogRead(A0);
randomSeed(PlayTrack);
pinMode(CoinButton_PIN, INPUT);
pinMode(RedButton_PIN, INPUT);
pinMode(BlueButton_PIN, INPUT);
pinMode(ResetButton_PIN, INPUT);
pinMode(CoinGLED_PIN, OUTPUT);
pinMode(CoinRLED_PIN, OUTPUT);
pinMode(Latch_PIN, OUTPUT);
pinMode(Clock_PIN, OUTPUT);
pinMode(Data_PIN, OUTPUT);
myservo.attach(Servo_PIN, MinPulse, MaxPulse); // attaches the servo on pin 12 to the servo object
digitalWrite(CoinRLED_PIN, HIGH);
UpdateScore();
InitDFPlayer();
}
//*******************************************************
//
// Primary loop for this firmware
//
//*******************************************************
void loop() {
RedButtonState = digitalRead(RedButton_PIN);
BlueButtonState = digitalRead(BlueButton_PIN);
CoinButtonState = digitalRead(CoinButton_PIN);
ResetButtonState = digitalRead(ResetButton_PIN);
//*********************************************************
if (!CoinDetected) { // CoinDetected is False
// VerifyCard();
if (CoinButtonState) { // CoinButtonState is HIGH
Serial << "Coin inserted" << "\n";
CoinDetected = true;
// CoinButtonState = digitalWrite(CoinButton_PIN, LOW);
BallReleased();
PlayerMP3Track(SystemStart, NULL);
IRS_Timer();
}
}
if (CoinDetected) { // CoinDetected is True
if (ResetButtonState && (RedScore + BlueScore) > 0) {
ResetPressed = true;
Reset_LimitGoal(); // Game Reset
}
if (RedButtonState) { // RedButtonState is HIGH
CurrentTime = millis();
if (CurrentTime - PreviousTime >= Interval1) {
PreviousTime = CurrentTime;
Serial << "Red broken" << "\n";
RedScore++; // Increases the display counter of the red team
UpdateScore(); // Update the scoreboard (HOME | VISITOR)
PlayerMP3Track(RedTeamScore, NULL);
Reset_LimitGoal(); // Game Reset
}
}
if (BlueButtonState) { // BlueButtonState is HIGH
CurrentTime = millis();
if (CurrentTime - PreviousTime >= Interval1) {
PreviousTime = CurrentTime;
Serial << "Blue broken" << "\n";
BlueScore++; // increases the display counter of the blue team
UpdateScore(); // Update the scoreboard (HOME | VISITOR)
PlayerMP3Track(BlueTeamScore, NULL);
Reset_LimitGoal(); // Game Reset
}
}
}
}
/*
// ******************************************************
//
// Verify Card function
//
//*******************************************************
void VerifyCard() {
Serial.println("Scan Your Card...");
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) { // Reset the loop if no new card present on the sensor/reader.
delay(Interval1); // This saves the entire process when idle. And if present, select one.
return;
}
Serial.println(F("**Card Detected**"));
Serial << "Card UID: "; // Show UID on serial monitor
//Reading card UID
for (byte i = 0; i < mfrc522.uid.size; i++) { // Loops through the UID one byte at a time
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX); // Shows the read UID byte in hexadecimal
ReadUID[i] = mfrc522.uid.uidByte[i]; // Stores the byte of the read UID in an array
}
Serial.print("\t"); // Print a tab space
if (CompareUID(ReadUID, validUIDs)){ // Call CompareUID function
Serial << "Authorized access..." << "\n"; // If true shows welcome text
CoinButtonState = digitalWrite(CoinButton_PIN, HIGH);
}else { // If it returns false
Serial << "Access denied..." << "\n"; // shows text: access denied
Access_denied(); // Calls the unidentified card sound function
}
mfrc522.PICC_HaltA(); // Stops card communication
}
9
// ******************************************************
//
// Compare UIDs Card function
//
//*******************************************************
boolean CompareUID(byte Read[], byte Tag[]) { // funcion CompareUID
for (byte i=0; i < mfrc522.uid.size; i++) { // Loops through the UID one byte at a time
if (Read[i] != Tag[i]) { // If the value of the content of the ReadUID variable is different from the content of the TagUID1 variable
return(false); // Returns false
}
return(true); // If the values of the variables match, it returns true
}
}
*/
void IRS_Timer() {
const esp_timer_create_args_t timerArgs1 = { // Defines the arguments to create the timer,
.callback = &OnTimer1, // including the callback function
.name = "Timer1" // and the timer name
};
const esp_timer_create_args_t timerArgs2 = { // Defines the arguments to create the timer,
.callback = &OnTimer2, // including the callback function
.name = "Timer2" // and the timer name
};
esp_timer_create (&timerArgs1, &timer1); // Creates the timer with the specified arguments
esp_timer_start_periodic(timer1, IntervalTime1); // Starts the timer with a period X defined in microseconds (1,000,000 microseconds = 1 second)
esp_timer_create (&timerArgs2, &timer2); // Creates the timer with the specified arguments
esp_timer_start_periodic(timer2, IntervalTime2); // Starts the timer with a period X defined in microseconds (1,000,000 microseconds = 1 second)
}
void OnTimer1(void *arg) { // The 'OnTimer1' function is the IRS that is called every time the timer generates an interrupt
PlayerMP3Track(B_RTeamHot, NULL);
}
void OnTimer2(void *arg) { // The 'OnTimer2' function is the IRS that is called every time the timer generates an interrupt
PlayerMP3Track(CrowdIsBored, NULL);
}
// ******************************************************
//
// Update scoreboard scores function
//
//*******************************************************
void UpdateScore() {
digitalWrite(Latch_PIN, LOW);
shiftOut(Data_PIN, Clock_PIN, MSBFIRST, number[RedScore]); // Show Red Score
shiftOut(Data_PIN, Clock_PIN, MSBFIRST, number[BlueScore]); // Show Blue Score
digitalWrite(Latch_PIN, HIGH);
}
// ******************************************************
//
// Game Reset Function
//
//*******************************************************
void Reset_LimitGoal(){
// Limit the goal counter
if (RedScore + BlueScore == 9 || ResetPressed) { // ResetPressed is True
if (RedScore + BlueScore == 9) {
BlockBall();
if (RedScore > BlueScore) {
mesarray = RedTeamWS - 1;
PlayerMP3Track(SoundEffect, RedTeamWS); // Red Team Goal Sound Effect
} else {
mesarray = BlueTeamWS - 1;
PlayerMP3Track(SoundEffect, BlueTeamWS); // Blue Team Goal Sound Effect
}
} else {
mesarray = GameResetS - 1;
PlayerMP3Track(SoundEffect, GameResetS);
}
delay(Interval4);
ResetPressed = false;
RedScore = 0;
BlueScore = 0;
UpdateScore(); // Update the scoreboard (HOME | VISITOR)
}
}
void BallReleased() {
digitalWrite(CoinRLED_PIN, LOW);
digitalWrite(CoinGLED_PIN, HIGH);
myservo.write(90); // Ball released - Set the servo to the open position
mesarray = BallReleaS - 1;
PlayerMP3Track(SoundEffect, BallReleaS); // Sound effect when the ball is released.
}
void BlockBall() {
CoinDetected = false;
digitalWrite(CoinRLED_PIN, HIGH);
digitalWrite(CoinGLED_PIN, LOW);
myservo.write(0); // Block the ball when the game ends
PlayerMP3Track(GameOver, NULL); // Sound effect indicating that the game is over
}
void Access_denied() { // Sound effect when the card is not recognized, or is not authorized.
mesarray = AccessDenS - 1;
digitalWrite(CoinRLED_PIN, LOW);
PlayerMP3Track(SoundEffect, AccessDenS);
delay(Interval2);
digitalWrite(CoinRLED_PIN, HIGH);
PlayerMP3Track(SoundEffect, AccessDenS);
delay(Interval3);
digitalWrite(CoinRLED_PIN, LOW);
PlayerMP3Track(SoundEffect, AccessDenS);
delay(Interval2);
digitalWrite(CoinRLED_PIN, HIGH);
PlayerMP3Track(SoundEffect, AccessDenS);
}
// ******************************************************
//
// Init DFPlayerMini function
//
//*******************************************************
void InitDFPlayer () {
/*/
Serial.println();
Serial.println(F("DFRobot DFPlayer Mini Demo"));
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while(true);
}
Serial.println(F("DFPlayer Mini online."));
//----Set volume----
myDFPlayer.volume(xVolume);
//----Set different EQ----
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
// myDFPlayer.EQ(DFPLAYER_EQ_POP);
// myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
// myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
// myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
// myDFPlayer.EQ(DFPLAYER_EQ_BASS);
//----Set device we use SD as default----
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_U_DISK);
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_AUX);
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_SLEEP);
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_FLASH);
//myDFPlayer.play(1); //Play the first mp3
myDFPlayer.playFolder(15, PlayMP3); //play specific mp3 in SD:/15/004.mp3; Folder Name(1~99); File Name(1~255)
//myDFPlayer.playMp3Folder(4); //play specific mp3 in SD:/MP3/0004.mp3; File Name(0~65535)
//myDFPlayer.randomAll(); //Random play all the mp3.
//----Read imformation----
// Serial.println(myDFPlayer.readState()); //read mp3 state
// Serial.println(myDFPlayer.readVolume()); //read current volume
// Serial.println(myDFPlayer.readEQ()); //read EQ setting
// Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
// Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
// Serial.println(myDFPlayer.readFileCountsInFolder(3)); //read fill counts in folder SD:/03
*/
}
// ******************************************************
//
// Assign random number to a variable function
//
//*******************************************************
// ******************************************************
//
// Play an audio track function
//
//*******************************************************
void PlayerMP3Track (TrackType tracktype, int playtrack) {
PlayTrack = random(1,6);
// this method takes a string which identifies which audio track on the SD card should be played
// thankfully the audio track is played in the background since this method will normally be called
// from an ISR function
switch (tracktype) {
case B_RTeamHot:
Serial << (F("Blue & Red Team Hot! - ")) << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(1, PlayTrack)
break;
case BlueTeamScore:
Serial << (F("Blue Team Score! - ")) << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(2, PlayTrack)
break;
case CrowdIsBored:
Serial << "Crowd is Bored! - " << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(3, PlayTrack)
break;
case GameOver:
Serial << "Game Over! - " << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(4, PlayTrack)
break;
case RedTeamScore:
Serial << "Red Team Score! - " << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(5, PlayTrack)
break;
case SoundEffect:
Serial << "Sound Effect! - " << "The Playtrack number is = " << playtrack << " - " << Message [mesarray] <<"\n";
// myDFPlayer.playFolder(6, playtrack)
break;
case SystemStart:
Serial << "System Start! - " << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(7, PlayTrack)
break;
// case BlueTeamWin:
// Serial << "System Start - " << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(8, PlayTrack)
// break;
// case RedTeamWin:
// Serial << "System Start - " << "The Playtrack number is = " << PlayTrack << "\n";
// myDFPlayer.playFolder(9, PlayTrack)
// break;
}
}
/*
void printDetail(uint8_t type, int value){
switch (type) {
case TimeOut:
Serial.println(F("Time Out!"));
break;
case WrongStack:
Serial.println(F("Stack Wrong!"));
break;
case DFPlayerCardInserted:
Serial.println(F("Card Inserted!"));
break;
case DFPlayerCardRemoved:
Serial.println(F("Card Removed!"));
break;
case DFPlayerCardOnline:
Serial.println(F("Card Online!"));
break;
case DFPlayerUSBInserted:
Serial.println("USB Inserted!");
break;
case DFPlayerUSBRemoved:
Serial.println("USB Removed!");
break;
case DFPlayerPlayFinished:
Serial.print(F("Number:"));
Serial.print(value);
Serial.println(F(" Play Finished!"));
break;
case DFPlayerError:
Serial.print(F("DFPlayerError:"));
switch (value) {
case Busy:
Serial.println(F("Card not found"));
break;
case Sleeping:
Serial.println(F("Sleeping"));
break;
case SerialWrongStack:
Serial.println(F("Get Wrong Stack"));
break;
case CheckSumNotMatch:
Serial.println(F("Check Sum Not Match"));
break;
case FileIndexOut:
Serial.println(F("File Index Out of Bound"));
break;
case FileMismatch:
Serial.println(F("Cannot Find File"));
break;
case Advertise:
Serial.println(F("In Advertise"));
break;
default:
break;
}
break;
default:
break;
}
}*/