Introduction: CS: GO Cuentra Atras Bomba Con Arduino Mega + Display LCD 1602 + 2 Botones (+ English Version)

Hola a tod@s!

Hace tiempo que juego a CS: GO y me sigue dando rabia no saber exactamente si me dara tiempo a desactivar la bomba, o cuanto tiempo queda. Por esta razon, entre otras, me decidi a montar este chacharro (aunque para ser sincero, muy util no es xD)

Darle al boton cada vez q plantan la bomba, ademas de impreciso, es un coñazo. Pero mola!

Bueno, mas alla de su utilidad real, resulta que para un novato como yo ha sido un buen ejercicio tener que pelearme con botones (que hacen de interruptor), poner en marcha el Display LCD, programar la cuenta atras, crear y dibujar caracteres que representan la barra de progreso, usar millis() para poder controlar diferentes procesos sin uso de delays, etc...

Espero que os guste, y os animo a cualquiera a que propongais correcciones y formas mejores de hacer cualquiera de los pasos seguidos y asi aprendamos tod@s!

Los materiales que vamos a necesitar son los siguientes:

- Arduino board (En mi caso, un clon chino de Arduino Mega)

- Display LCD 16x2 y Driver I2C

- Dos pulsadores

- Dos resistencias, no importa mucho el valor, pero he elegido un valor mas o menos bajo, de alrededor de 1K Ohm.

- Un protoboard y cables.

Nota: Para los cables, lo mas practico que he encontrado es pedirles a los tecnicos de la empresa "Teleco" que van por ahi haciendo trabajos para Vomistar que te regalen un poco de cable de ese de un solo hilo, que se pincha perfectamente en arduinos, protoboards, etc...Si te regalan un par de metros de cable, tienes para muuuchos trocitos jejeje.

And in english....


Started playing CS:GO a while ago, and i still miss something telling me exactly the time the bomb will take to blow up, or if i'll be ale to defuse it within time. This is why, among other reasons, i decided to assemble this gadget (to be honest it's not very useful, tho).


Having to push the button each time they plant the bomb can be inaccurate and annoying, but so cool :D


Well, beyond its real utility, happens that for a newbie like me it's been a nice exercise having to deal with buttons (acting as switches), turn the LCD display on, coding the countdown, to create the chars drawing the progress bar, using millis() to be able to control different processes without using delay, and so on...


I really hope you like it, and would appreciate any correction, comment or way for doing things better so that we all learn! (Any correction about my english will be welcome too, and very appreciated :D)


The materials you are going to need are:

- Arduino board (mine is a chinese clone of the Arduino Mega)

- LCD 16x2 display and I2C Driver

- 2 buttons

- 2 resistors (the value is not very important as long as it's a low value, let's say 1~2KOhm)

- Protoboard and wires.



Step 1: Paso 1: Conectarlo Todo

En primer lugar, vamos a conectar los componentes.

He usado el protoboard pequeño para pinchar ahi los botones.

La configuracion de los botones es de tipo "pull-down".

Para el boton "Start" conectaremos una de las patillas a GND usando una resistencia de 1~2 KOhm, y tambien al pin digital 2. La otra patilla ira conectada a "5V".

Nota: Un valor bajo de resistencia nos podria dar falsos positivos mientras que un valor alto podria dar fallos. En general, el uso de una resistencia de un valor ni muy bajo ni muy alto, deberia funcionar a la perfeccion y no es demasiado importante.

Para el boton "Reset" usaremos la misma configuracion, si bien esta vez lo conectaremos al pin digital 3.

A continuacion, vamos a conectar el display.

Para no complicarme mucho, yo lo he cogido a un palo de polo con un poco de cola caliente, para que quedara como en un atril, un poco inclinado. A continuacion he sujetado el palo de polo a la caja de plastico del arduino con unas bridas, de forma que todo queda bien sujeto.

La controladora I2C tiene 4 pines. Uno GND, que conectaremos a GND de Arduino. Uno Vcc que conectaremos a 5V de Arduino. SDA y SCL que conectaremos a sus homologos de arduino. En el caso de Arduino Mega y su hermano chino, los pines SDA y SCL se corresponden con los pines digitales 20 y 21.

Con todo conectado, toca pasar a la parte digital del asunto!

The first step will be to put everything together.

I used the small protoboard so it also acts as a strong surface to pin the buttons on.

We will connect the buttons using a Pull-Down setup.


For the "Start" button, connect one of the pins to GND using one of the resistors as a wire. Connect this pin to arduino digital pin #2 too. The other pin will be connected to +5V.


Note: A low resistor value could give us false possitives while a high value could just fail. In general, using a low-intermediate value should do it.

For the "Reset" button we'll use the same settings, but this time will be connected to pin #3.


Now let's connect the display.

To make things easier, i used a woden icecream stick and attached it to the display with hot glue. This way it stands inclinated, facing me. After, i attached toe wooden stick to the plastic case of my arduino board, using some plastic flanges.

I2C driver has 4 pins. GND will be connnected to arduino GND pin and Vcc connected to 5V. SDA and SCL pins must be located on your board before connecting. On my chinese clone of Mega, they are located at pins 20 and 21.


If everything is connected properly, let's go to the digital part!

Step 2: Paso 2: El Código

En este caso, voy a pasar a poner el codigo tal cual lo tengo, ya comentado.

(No se por que se parte esto en trozos, lo siento :S)

This time i'm just pasting the code as is, but already commented. Comments are written in spanish, so feel free to ask for anything you don't understand.

Also, i apologize for splitting the code, but don't know how to do it better xD

/* <br>    Sketch original:  <a href="https://arduino-info.wikispaces.com/LCD-Blue-I2C" rel="nofollow">  https://arduino-info.wikispaces.com/LCD-Blue-I2C  </a> (Recomendado para empezar con el display)
    Modificado por primera vez 13-10-16 para adaptarlo a mi proyecto.
    Direccion I2C Clon Arduino Mega: 0x3F
*/
#include  <Wire.h> // Comes with Arduino IDE 
#include <LiquidCristal_I2C.h> //<a href="https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library/blob/master/LiquidCrystal_I2C.h" rel="nofollow">LiquidCrystal_I2C Library</a>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
//Variables para el uso de millis()
unsigned long now = 0;          //Comun "ahora"
unsigned long beforeCounter;    //Contador "antes"
unsigned long beforeDraw;       //Dibujar barra "antes"
//Botones Start y Reset
int sPin = 2;
int rPin = 3;
bool isRunning = false;
byte zero[8] = { B00000, B00000, B00000, B00000, B00000, B00000, B00000, B00000 };  //BYTES " | || ||| |||| ||||| "
byte unQuinto[8] = { B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 };
byte dosQuintos[8] = { B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 };
byte tresQuintos[8] = { B11100, B11100, B11100, B11100, B11100, B11100, B11100, B111100 };
byte cuatroQuintos[8] = { B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 };
byte full[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };


void SoftReset(){                                                                             //FUNCION QUE "RESETEA" EL SKETCH
  asm volatile ("  jmp 0");
}
void setup(){
  lcd.begin(16,2);
  lcd.createChar(0, zero);                                                                   
 //CREO CARACTERES A PARTIR DE LOS BYTES
  lcd.createChar(1, unQuinto);
  lcd.createChar(2, dosQuintos);
  lcd.createChar(3, tresQuintos);
  lcd.createChar(4, cuatroQuintos);
  lcd.createChar(5, full);
  beforeDraw = beforeCounter = millis();
}
void loop(){
  now = millis();
  //clear the screen
  
  if(digitalRead(sPin) == HIGH && !isRunning){           //SI PULSO "S" (Start)
    isRunning = true;
    CuentaAtras(40);                                     //COMIENZA LA CTA ATRAS
  }
}
void CuentaAtras(int val){
  float i = 0;
  while(val-i >=0){                                      //ESTE "While" ES EL "LOOP" UNA VEZ EMPIEZA LA CUENTA ATRAS
    if(digitalRead(rPin) == HIGH && isRunning){          //SI PULSO "R" (Reset)
      isRunning = false;
      SoftReset();
    }
    
    now = millis();
    if(beforeCounter + 500 <= now){                       //CADA 500ms ("i" para los segundos restantes)
      beforeCounter = now;
      i = i + 0.5;
    }
    
    if(beforeDraw + 200 <= now){                         //CADA 200ms (Dibujar barra)
      beforeDraw = now;
      Draw(val,i);
    }
  }
  if (val-i == -0.5){                                    //SI TERMINA LA CUENTA ATRAS
    lcd.setCursor(0,0);                                  //Esto podria ser algo mas original ejem...
    lcd.print("BBBBOOOOOOOOMMMM");                       //Pero con eso de un maximo de 8 Chars
    lcd.setCursor(0,1);                                 
    lcd.print("BBBBOOOOOOOOMMMM");
    delay(2000);
    SoftReset();
  }
}
//Dibujar      val=40     x=seg.restantes
void Draw(float val,float x){                                                                 
//FUNCION QUE DUBUJA EL CONTENIDO DEL DISPLAY
  lcd.clear();                                  
  float sec = val - x;                          //"segundo" actual
  int cur = sec/(val/16);                       //Celda actual del LCD q vamos a dibujar
  float portion = 2*(sec-(cur*2.5));            //Devuelve un numero entre 0 y 5 que representa cuantas de las 5 columnas que componen
                                                //...cada celda de la pantalla LCD hemos de rellenar. 1 -> 1 col, 2 -> 2 cols...
                                                //...numero que ademas, coincide con el nombre del byte que representa estas cols.
  
//DIBUJAR CELDAS DEL DISPLAY (PRIMERA FILA - BARRA REGRESIVA)
  for(int j = 0; j < cur; j++){     //Rellenar celdas "llenas", a la izquierda de la celda actual "cur"
    lcd.setCursor (j, 0);
    lcd.write((byte)5);
  }
  for(int j = 15; j > cur; j--){    //Rellenar celdas "vacias", a la derecha de la celda actual "cur"
    lcd.setCursor(j,0);
    lcd.write((byte)0);
  }
 
  lcd.setCursor(cur,0);             //Ahora dibujamos la celda actual, segun los seg. restantes
  lcd.write((byte)portion);
  
//BIBUJAR CELDAS DEL DISPLAY (SEGUNDA FILA - SEG. RESTANTES) 
  if(val-x>9){                          //Si la cuenta atras tiene dos digitos...
    lcd.setCursor(0,1);                 //...escribo en la primera posicion de la segunda fila
  }else if(val-x >= 0){                 //Pero si tiene un solo digito...
    lcd.setCursor(1,1);                 //...muevo el cursor una posicion a la derecha.
  }
  lcd.print((int)val-x);                //Finalmente escribimos los segundos que quedan con el cursor en la posicion correcta
  lcd.print(" sec.");
}