/*
* AS-GAMEBOX
* An Airsoft Game Box for small fields with sound-output and leds
*
* Author: René Brixel <[email protected]>
* Version: 0.6.0
* Date: 2024-05-07
*
*/
/*
* --------------------
* Include neccesary libs
* --------------------
*/
#include <LiquidCrystal_I2C.h>
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
//#include <DFRobotDFPlayerMini.h>
/*
* --------------------
* Defines
* --------------------
*/
#define BTN_UP 4 // Button Up
#define BTN_ENTER 5 // Button Enter
#define BTN_DOWN 6 // Button Down
#define BTN_RED 7 // Button Red
#define BTN_BLUE 8 // Button Blue
#define LEDPIN 9 // NeoPixel-LED-Output
#define DFPRX 10 // Software Serial RX Port for DFPlayer Mini
#define DFPTX 11 // Software Serial TX Port for DFPlayer Mini
#define BATTPIN A0 // ADC-Port of battery-measurement
#define LEDAMOUNT 2 // Amount of LEDs on NeoPixel-String
#define DEBOUNCE 200 // millisecondes for debouncing buttons
/*
* --------------------
* Initializing libs
* --------------------
*/
LiquidCrystal_I2C lcd(0x27, 16, 2); // !! 0x3F !! 16*2 Character LCD with i2c
Adafruit_NeoPixel ledNeoPx = Adafruit_NeoPixel(LEDAMOUNT, LEDPIN, NEO_GRB + NEO_KHZ800); // First parameter is the amount of led-pixels
//DFRobotDFPlayerMini dfPlayer;
/*
* --------------------
* Create special battery-icon for LCD
* --------------------
*/
byte iconBattery[] = {
B01110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte eAccent[] = { // é
B00010,
B00100,
B01110,
B10001,
B11111,
B10000,
B01110,
B00000
};
/*
* --------------------
* Setting variables
* --------------------
*/
byte menuMain = 0;
String gameModes[] = {"Conquest", "Bomb Defuse", "Info/Credits"};
float diodeVcc = 0.7; // Measure voltage before and after the power supply diode and fill in the
// difference here for correct battery measurement
/*
* --------------------
* SETUP-Routine
* --------------------
*/
void setup() {
Serial.begin(9600);
SoftwareSerial softSerial(DFPRX, DFPTX); // RX, TX
softSerial.begin(9600);
pinMode(BTN_UP, INPUT_PULLUP); // internal Hardware-Pullup
pinMode(BTN_ENTER, INPUT_PULLUP); // internal Hardware-Pullup
pinMode(BTN_DOWN, INPUT_PULLUP); // internal Hardware-Pullup
pinMode(BTN_RED, INPUT_PULLUP); // internal Hardware-Pullup
pinMode(BTN_BLUE, INPUT_PULLUP); // internal Hardware-Pullup
ledNeoPx.begin(); // Initialising NeoPixel
for (byte i = 0; i < LEDAMOUNT; i++) {
ledNeoPx.setPixelColor(i, ledNeoPx.Color(0, 0, 0)); // RGB
}
ledNeoPx.show();
lcd.init();
lcd.backlight();
lcd.createChar(0, iconBattery);
lcd.createChar(1, eAccent);
lcd.clear();
menuUpdate();
}
/*
* --------------------
* LOOP-Routine
* --------------------
*/
void loop() {
if (!digitalRead(BTN_UP)) {
menuMain--;
menuUpdate();
delay(DEBOUNCE);
//while (digitalRead(BTN_UP));
}
if (!digitalRead(BTN_DOWN)) {
menuMain++;
menuUpdate();
delay(DEBOUNCE);
}
if (!digitalRead(BTN_ENTER)) {
menuExecute();
delay(DEBOUNCE);
}
}
/*
* --------------------
* Showing the main menu at startup and after a game ends
* --------------------
*/
void menuUpdate() {
lcd.clear();
lcd.print("Start:");
lcd.setCursor(12, 0);
lcd.write(0); // Battery-Icon
lcd.setCursor(13, 0);
lcd.print(String(batStatusPercentage()) + "%");
lcd.setCursor(0, 1);
lcd.print("> ");
if (menuMain == 255) { // handle overflow of byte-variable
menuMain = 2;
}
if (menuMain > 2) {
menuMain = 0;
}
lcd.setCursor(2, 1);
lcd.print(gameModes[menuMain]);
}
/*
* --------------------
* Execute function from main menu
* --------------------
*/
void menuExecute() {
switch(menuMain) {
case 0: // Conquest
startGameConquest();
menuUpdate(); // If game ends, show main menu
break;
case 1: // Bomb Defuse
startGameBombdefuse();
menuUpdate(); // If game ends, show main menu
break;
case 2: // Info-Screen
showInfo();
}
}
/*
* --------------------
* Show info/credits screen from main menu
* --------------------
*/
void showInfo() {
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("AS-GAMEBOX");
lcd.setCursor(0, 1);
lcd.print("V0.6.0 07.05.24");
delay(2000);
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("CONQUEST");
lcd.setCursor(0, 1);
lcd.print("V1.0.0 08.12.23");
delay(2000);
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("BOMB DEFUSE");
lcd.setCursor(0, 1);
lcd.print("V0.2.0 06.12.23");
delay(2000);
/*
lcd.clear();
lcd.print("Airsoft-Verband");
lcd.setCursor(4, 1);
lcd.print("Enztal");
delay(2000);*/
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Ren");
lcd.setCursor(5, 0);
lcd.write(1);
lcd.setCursor(6, 0);
lcd.print(" Brixel");
lcd.setCursor(1, 1);
lcd.print("renebrixel.de");
delay(2000);
menuUpdate();
}
/*
* --------------------
* Reads analog port from voltage divider and return battery level as percentage
* --------------------
*/
byte batStatusPercentage() {
float voltage = analogRead(BATTPIN) * (5.0 / 1023.0) * 2;
// * 2 wegen Spannungsteiler im Test!
//voltage = voltage - diodeVcc; // add the diode consumption to Vcc
// 2S-LiPo max.: 8.4V (4.2V per Cell)
// ...min.: 6.6V (3.3V per Cell)
// (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
float batStatus = (voltage - 6.6) * (99 - 0) / (8.4 - 6.6) + 0;
if (batStatus < 0.0) {
batStatus = 0.0;
}
if (batStatus > 99.9) {
batStatus = 99.9;
}
byte batStatusPertencage = (byte)(batStatus); // round down
return batStatusPertencage;
}