#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Tone.h>
Tone tone1;
//------------ Leds ------------
const byte led1 = 4;
const byte led2 = 3;
//---------- FIN Leds ----------
//---------- Relay ----------
const byte relay=2;
//-------- FIN Relay --------
//------------- LCD -------------
LiquidCrystal lcd(13, 12, 11, 10, 9, 8); // the pins we use on the LCD
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {6, 7, A1, A0};
byte colPins[COLS] = {A2, A3, A4, A5};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(relay, OUTPUT);
tone1.begin(5);
lcd.begin(16, 2);
Serial.begin(9600);
}
void loop()
{
byte choosed= mainMenu();
if (choosed==0)
{
basicTimerMode();
}
else if (choosed==1)
{
disarmTheBombMode();
}
else if(choosed == 2)
{
lcd.print("Dominacion");
delay(1000);
lcd.clear();
}
}
/**
* Crea el bucle para pedir una key en el keypad
* **/
char getPressedKey()
{
char key=NO_KEY;
while (key == NO_KEY)
{
key=keypad.getKey();
}
return key;
}
/*
* Se debe utilizar para indicar que un numero ingresado
* en el keypad no es valido
*
* recibe la posicion que debe tener en el lcd y el renglon
*
* imprime una X en la posicion, la borra y toca una nota
* al terminar el cursor vuelve a la posicion recibida
* **/
void printInvalidKey(byte posicionx, byte renglon)
{
lcd.setCursor(posicionx, renglon);
lcd.print('X');
tone1.play(NOTE_C4, 200);
delay(90);
lcd.setCursor(posicionx, renglon);
lcd.print(' ');
lcd.setCursor(posicionx, renglon);
}
void playOnLose(byte seconds=30)
{
byte i=0;
digitalWrite(relay, HIGH);
while(i<75)
{
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
delay(100);
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
delay(100);
i++;
}
digitalWrite(relay, LOW);
}
void playOnWin()
{
byte i=0;
//50 ciclos=30 segundos
while(i<25)
{
tone1.play(NOTE_C5, 90);
digitalWrite(led1, HIGH);
delay(100);
tone1.play(NOTE_C5, 90);
digitalWrite(led1, LOW);
delay(100);
tone1.play(NOTE_C5, 90);
digitalWrite(led2, HIGH);
delay(100);
tone1.play(NOTE_C5, 90);
digitalWrite(led2, LOW);
delay(100);
tone1.play(NOTE_C5, 90);
delay(100);
tone1.play(NOTE_C5, 90);
delay(100);
i++;
}
}
//----------------------------------------------------------------------------
//------------------------------- TEMPORIZADOR -------------------------------
//----------------------------------------------------------------------------
/**
* Recibe un arreglo de tiempo, por cada segundo que pasa le resta 1 segundo
*
* @param hs_min_seg es el arreglo con los datos del runTimer, sus tres elementos son
* [0]: horas, [1]: minutos, [2]: segundos
*
* @param speedUpAtEnd se utiliza para verificar si se debe acelerar
* los leds y el *pip* que hace el runTimer cada que resta un segundo
*
* @post si no paso un segundo no se modificara el runTimer
* **/
void runTimer(byte hs_min_seg[3], bool speedUpAtEnd=false, bool silentMode=false)
{
static unsigned long secMillis = 0;
static byte waitPartOfSeg = 0;
uint16_t toneSpeed = 200;
uint16_t period = 1000;
byte horas = hs_min_seg[0];
byte minutos = hs_min_seg[1];
byte segundos = hs_min_seg[2];
if(speedUpAtEnd==true)
{
speedUpTimer(segundos, period, toneSpeed);
}
if (segundos == 0 && minutos > 0)
{
minutos--;
segundos = 60;
}
else if (minutos == 0 && horas > 0)
{
horas--;
minutos = 59;
segundos = 60;
}
if (horas==0 && minutos==0 && segundos==0)
{
hs_min_seg[0] = 0;
hs_min_seg[1] = 0;
hs_min_seg[2] = 0;
}
else if ((millis()-secMillis) >= period)
{
secMillis = millis();
if (waitPartOfSeg * period >= 1000)
{
segundos--;
waitPartOfSeg = 1;
}
if (silentMode == false)
{
tone1.play(NOTE_G5, toneSpeed);
digitalWrite(led2, HIGH);
digitalWrite(led1, HIGH);
delay(10);
digitalWrite(led2, LOW);
digitalWrite(led1, LOW);
delay(10);
}
waitPartOfSeg++;
}
hs_min_seg[0] = horas;
hs_min_seg[1] = minutos;
hs_min_seg[2] = segundos;
}
/**
* Acelera el ruido del runTimer
* cuando quedan < de 10 segundos *2
* cuando quedan < de 5 segundos *4
* **/
void speedUpTimer(byte segundos, uint16_t& period, uint16_t& toneSpeed)
{
if (segundos > 10)
{
period = 1000;
}
else if (segundos <= 10 && segundos > 5)
{
period = 500;
}
else if (segundos <= 5)
{
toneSpeed = 100;
period = 250;
}
}
/**
* Imprime el tiempo que recibe en el lcd, formato 00:00:00 (9 chars) y a partir de la posicion
* especificada
*
* @param hs_min_seg es el arreglo que contiene el runTimer
* debe estar ordenado como horas, minutos, segundos
*
* @param posx es la posicion en x a partir de la que se imprime el runTimer
*
* @param posy es el renglon en el que se imprime el runTimer
* **/
void printTimer(byte hs_min_seg[3], byte posx, byte posy)
{
byte horas = hs_min_seg[0];
byte minutos = hs_min_seg[1];
byte segundos = hs_min_seg[2];
lcd.setCursor(posx, posy);
// Imprime las horas
if (horas < 10)
{
lcd.print("0");
}
lcd.print(horas);
lcd.print(":");
// Imprime los minutos
if (minutos < 10)
{
lcd.print("0");
}
lcd.print(minutos);
lcd.print(":");
// Imprime los segundos
if (segundos < 10)
{
lcd.print("0");
}
lcd.print(segundos);
}
void sumSecsToTimer(byte hs_min_seg[3], byte amount)
{
hs_min_seg[2] += amount;
hs_min_seg[1] += hs_min_seg[2]/60;
hs_min_seg[2] %= 60;
hs_min_seg[0] += hs_min_seg[1]/60;
hs_min_seg[1] %= 60;
}
void countUpTimer(byte hs_min_seg[3], bool silentMode=false)
{
static unsigned long secMillis = 0;
if ((millis()-secMillis) >= 1000)
{
secMillis = millis();
tone1.play(NOTE_G5, 250);
sumSecsToTimer(hs_min_seg, 1);
if (silentMode == false)
{
digitalWrite(led2, HIGH);
digitalWrite(led1, HIGH);
delay(10);
digitalWrite(led2, LOW);
digitalWrite(led1, LOW);
delay(10);
}
}
}
//----------------------------------------------------------------------------
//----------------------------- FIN TEMPORIZADOR -----------------------------
//----------------------------------------------------------------------------
void setTimer(byte hs_ms_sgs[3])
{
byte hms[6] = {0};
char key;
lcd.clear();
lcd.print("Ingrese Tiempo");
byte i = 0;
while (i < 6)
{
hs_ms_sgs[0] = hms[0]*10 + hms[1];
hs_ms_sgs[1] = hms[2]*10 + hms[3];
hs_ms_sgs[2] = hms[4]*10 + hms[5];
lcd.setCursor(15, 1);
lcd.print(" ");
delay(100);
printTimer(hs_ms_sgs, 8, 1);
key = getPressedKey();
if (key == 'A')
{
break;
}
else if (key == 'B')
{
i = 0;
hms[0]=0; hms[1]=0; hms[2]=0;
hms[3]=0; hms[4]=0; hms[5]=0;
lcd.clear();
lcd.print("Ingrese Tiempo");
tone1.play(NOTE_E5, 100);
}
else
{
//si no es un numero o si el primer numero es 0
if ((key<'0' || key>'9') || (i==0 && key=='0'))
{
printInvalidKey(15, 1);
}
else
{
for (byte j=0; j<5;j++)
{
hms[j]= hms[j+1];
}
tone1.play(NOTE_B6, 200);//key normal
hms[5]=key-'0';
i++;
}
}
}
//hms=(h,h, m,m, s,s)
hms[3] += hms[4]/6;//hms[4] decena segundos
hms[4] = hms[4]%6;
hms[1] += hms[2]/6;//hms[2] decena de minutos
hms[2] = hms[2]%6;
hs_ms_sgs[0] = hms[0]*10 + hms[1];
hs_ms_sgs[1] = hms[2]*10 + hms[3];
hs_ms_sgs[2] = hms[4]*10 + hms[5];
lcd.clear();
lcd.print("TIEMPO FINAL");
printTimer(hs_ms_sgs, 8, 1);
tone1.play(NOTE_C6, 200);
delay(900);
}
void setPassword(char password[4])
{
char key;
byte currentDigit = 0;
lcd.clear();
lcd.print("Ingrese codigo");
while(currentDigit < 4)
{
lcd.setCursor(6 + currentDigit, 1);
key= getPressedKey();
if (key=='B')
{
currentDigit=0;
lcd.setCursor(6, 1);
lcd.print(" ");
tone1.play(NOTE_E5, 100);
}
else if (key<'0' || key>'9')
{
printInvalidKey(6+currentDigit, 1);
}
else
{
lcd.print(key);
password[currentDigit] = key;
currentDigit++;
tone1.play(NOTE_C6, 200);
}
}
delay(500);
lcd.clear();
lcd.print("Ingresaste: ");
delay(100);
lcd.setCursor(6,1);
// el lcd.print(password); imprime un caracter 'c' de mas
// no se por que, antes no lo hacia
lcd.print(password[0]);
lcd.print(password[1]);
lcd.print(password[2]);
lcd.print(password[3]);
tone1.play(NOTE_E6, 200);
delay(1500);
lcd.clear();
}
bool enterPassword(char password[4], byte time_hms[3])
{
char entered[4]={0};
bool areEqual;
char key;
byte currentDigit = 0;
lcd.clear();
lcd.print("Codigo: ");
while (currentDigit<4 && (time_hms[0]>0 || time_hms[1]>0 || time_hms[2]>0))
{
runTimer(time_hms, true);
lcd.setCursor(6+currentDigit, 1);
key= keypad.getKey();
if(key != NO_KEY)
{
if (key<'0' || key>'9')
{
printInvalidKey(6+currentDigit, 1);
}
else if (key=='B')
{
currentDigit=0;
lcd.setCursor(6, 1);
lcd.print(" ");
tone1.play(NOTE_E5, 100);
}
else
{
lcd.setCursor(6+currentDigit, 1);
lcd.print(key);
entered[currentDigit]=key;
tone1.play(NOTE_C6, 200);
delay(100);
lcd.setCursor(6+currentDigit, 1);
lcd.print("*");
currentDigit++;
}
}
}
areEqual=true;
for (byte i=0; i<4; i++)
{
if (entered[i] != password[i])
{
areEqual=false;
}
}
return areEqual;
}
void getPreparationTimer(byte preparationTimer[3])
{
lcd.clear();
lcd.print("Tiempo armado?");
lcd.setCursor(0, 1);
lcd.print("A: SI B:NO");
char key= getPressedKey();
if(key=='A')
{
lcd.clear();
lcd.print("TIEMPO ARMADO:");
tone1.play(NOTE_E6, 200);
delay(800);
setTimer(preparationTimer);
}
}
void runPreparationTimer(byte preparationTimer[3])
{
bool adviceToStart=(preparationTimer[0]>0 || preparationTimer[1]>0 || preparationTimer[2]>0);
lcd.clear();
lcd.print("TIEMPO ARMADO:");
while(preparationTimer[0]>0 || preparationTimer[1]>0 || preparationTimer[2]>0)
{
runTimer(preparationTimer);
printTimer(preparationTimer, 4, 1);
}
lcd.clear();
lcd.print("Bomba armada");
lcd.setCursor(0, 1);
lcd.print("Correctamente");
delay(1000);
lcd.clear();
if (adviceToStart==true)
{
playOnLose(5);
}
}
void basicTimerMode()
{
byte preparationTimer[3]={0};
byte timer[3]={0};
lcd.clear();
lcd.print("Juego");
lcd.setCursor(0, 1);
lcd.print(" Temporizado");
delay(500);
getPreparationTimer(preparationTimer);
lcd.clear();
lcd.print("TIEMPO DE JUEGO");
tone1.play(NOTE_E6, 200);
delay(800);
setTimer(timer);
runPreparationTimer(preparationTimer);
lcd.clear();
lcd.print("Tiempo Restante");
while (timer[0]>0 || timer[1]>0 || timer[2]>0)
{
runTimer(timer);
printTimer(timer, 4, 1);
}
lcd.clear();
lcd.print("Termino la");
lcd.setCursor(0, 1);
lcd.print(" Partida");
playOnLose();
}
void disarmTheBombMode()
{
byte preparationTimer[3]={0};
byte mainTimer[3]={0};
char settedPassword[4];
char enteredPassword[4];
bool correctPassword=false;
byte attempts=3;
byte changeInSec=70;
char key;
bool gameIsOver=false;
lcd.clear();
lcd.print("Desarmar Bomba");
delay(500);
setPassword(settedPassword);
getPreparationTimer(preparationTimer);
lcd.clear();
lcd.print("TIEMPO DE JUEGO");
tone1.play(NOTE_E6, 200);
delay(800);
setTimer(mainTimer);
runPreparationTimer(preparationTimer);
while ((mainTimer[0]>0 || mainTimer[1]>0 || mainTimer[2]>0) && gameIsOver==false)
{
runTimer(mainTimer, true);
if (changeInSec != mainTimer[2])
{
changeInSec= mainTimer[2];
lcd.clear();
lcd.print("Tiempo Restante");
printTimer(mainTimer, 4, 1);
}
key= keypad.getKey();
if (key!=NO_KEY)
{
lcd.clear();
lcd.print("ENTRANDO.");
delay(200);
lcd.print(".");
delay(200);
lcd.print(".");
delay(200);
lcd.clear();
correctPassword= enterPassword(settedPassword, mainTimer);
if (correctPassword==true)
{
gameIsOver=true;
}
else
{
attempts--;
lcd.clear();
lcd.print("intentos: ");
lcd.print(attempts);
delay(500);
if (attempts==0)
{
gameIsOver=true;
}
}
}
}
if (correctPassword==true)
{
lcd.clear();
lcd.print("BIEN HECHO");
lcd.setCursor(0, 1);
lcd.print(" INSECTO");
delay(600);
lcd.clear();
lcd.print("LA BOMBA");
lcd.setCursor(0, 1);
delay(100);
lcd.print("FUE DESACTIVADA");
playOnWin();
}
else
{
lcd.clear();
lcd.print("LA RE CAGASTE");
delay(500);
lcd.clear();
lcd.print("LA BOMBA");
lcd.setCursor(0, 1);
delay(100);
lcd.print(" EXPLOTO!");
playOnLose();
}
}
void dominationMode()
{
byte blueTimer[3]={0};
byte redTimer[3]={0};
byte preparationTimer[3]={0};
byte globalTimer[3]={0};
byte changeInSec=70;
char actualTeam='0';
bool gameIsOver=false;
getPreparationTimer(preparationTimer);
lcd.clear();
lcd.print("TIEMPO DE JUEGO");
tone1.play(NOTE_E6, 200);
delay(800);
setTimer(globalTimer);
runPreparationTimer(preparationTimer);
lcd.clear();
lcd.print("Bomba armada");
lcd.setCursor(0, 1);
lcd.print("Correctamente");
delay(1000);
lcd.clear();
while (gameIsOver==false)
{
}
}
byte mainMenu()
{
lcd.clear();
const char rightArrow='>';
const char leftArrow='<';
char key='0';
char gameModes[3][15]={"Temporizador", "Desarma Bomba", "Dominacion"};
lcd.clear();
lcd.print("Modo de juego");
byte i=0;
bool seleccionando=true;
while(seleccionando)
{
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(2, 1);
lcd.print(gameModes[i]);
if (i==0)
{
lcd.setCursor(15, 1);
lcd.print(rightArrow);
}
else if (i==2)
{
lcd.setCursor(0, 1);
lcd.print(leftArrow);
}
else
{
lcd.setCursor(0, 1);
lcd.print(leftArrow);
lcd.setCursor(15, 1);
lcd.print(rightArrow);
}
key= getPressedKey();
if (key=='A')
{
seleccionando=false;
}
else if (key=='*')
{
if (i==0)
{
printInvalidKey(0, 1);
}
else
{
tone1.play(NOTE_B6, 200);//key normal
i--;
}
}
else if (key=='#')
{
if (i==2)
{
printInvalidKey(15, 1);
}
else
{
tone1.play(NOTE_B6, 200);//key normal
i++;
}
}
}
return i;
}