[Solved] -> See below
I'm trying to create a Bomb Prop for use in our Airsoft games.
For this purpose I have connected multiple modules (listed below) to my Arduino.
Arduino Nano V3 Atmega328P CH340 Chip
1x 2004 LCD Display with I2C Adapter
2x 7-Segment Display with 4 digits using I2C
1x 4x4 Matrix Keypad with PCF8574 I/O Expander
3x Push Buttons
1x Flip Switch
I tested each module by itself and had no problems with them.
When using all modules at the same time, I can send out hard coded signals and they work just fine.
I've managed to get the most basic version of the Game running.
The problems start once I try to program the the full game into the Arduino.
First I have 2 switch statements. The first to switch between different game modes and the second to switch between different phases in these game modes. (ATM there is just one game mode).
I need to calculate different values (Game Time Left, Bomb Time Left...) and convert them to Seconds and minutes to display them on the 7-Segment Displays, while also checking for Input on the buttons and Key Matrix.
So the code runs 2 switch statements, a few calculations, sends signals to the displays and checks for input.
At this point the loop runs very slow. It takes over a second for input to be recognized and the 7-seg displays don't seem to work (I guess because the loop is to slow). The LCD Display works just fine, other than the slow updates.
I can't imagine how slow it will be when I finish coding this game mode and add some more.
The point at which it starts to run slower, is when I add the Timer calculations. If I remove them, it works perfectly fine.
So I'm assuming the switch statements are not the problem. Could the problem be the millis() function?
Is it possible to use the Arduino for this purpose or do I have to many modules?
Is the problem the lengthy code? How can I structure my code to run more smoothly?
I used the two switch statements to only have part of the code loop depending on the game mode and stage of the game.
Is there a better way to structure it?
Sorry in advance for the messy code.
(The part that slows everything down is right after 'case 2: //Place Bomb')
#include <LiquidCrystal_I2C.h>
#include <Keypad_I2C.h>
#include "SevenSegmentTM1637.h"
//Constant Variables to change in Code
const int segBacklight = 100;
/*
0 - Main Menu,
10 - Gamemode Bomb
10 - Setup
12 - Place Bomb
14 - Defuse Bomb
16 - Victory Screen
20 - Gamemode Domination
30 - Gamemode Virus
*/
unsigned int GameMode = 10;
unsigned int Phase = 0;
unsigned gameTime = 60;
unsigned bombTime = 30;
unsigned gameStartTime;
unsigned bombStartTime;
//Clock and Data Pin for both 7-Segment Displays
const byte dsp1_clk = 10;
const byte dsp1_dio = 11;
const byte dsp2_clk = 12;
const byte dsp2_dio = 13;
//Input pins for the Buttons
const byte butL = 2;
const byte butM = 3;
const byte butR = 4;
//Input for the SafeSwitch
const byte sfsw = 5;
//Create the Objects for the LCD, 7-Segment and Keypad
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);
SevenSegmentTM1637 dsp1(dsp1_clk, dsp1_dio);
SevenSegmentTM1637 dsp2(dsp2_clk, dsp2_dio);
char hexaKeys[4][4] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte colPins[4] = {7, 6, 5, 4};
byte rowPins[4] = {3, 2, 1, 0};
Keypad_I2C I2C_Keypad(makeKeymap(hexaKeys), rowPins, colPins, 4, 4, 0x20, PCF8574);
void setup() {
//Pinmodes for Buttons and Buzzer
pinMode(butL, INPUT);
pinMode(butM, INPUT);
pinMode(butR, INPUT);
pinMode(sfsw, INPUT);
pinMode(buzz, OUTPUT);
//Initializing the LCD
lcd.init();
lcd.backlight();
//Initializing the Keypad
I2C_Keypad.begin();
//Initializing the 7-Seg 1
dsp1.begin();
dsp1.setBacklight(segBacklight);
//Initializing the 7-Seg 2
dsp2.begin();
dsp2.setBacklight(segBacklight);
Serial.begin(9600);
}
void loop() {
switch (GameMode) {
case 0:
{
//Gamemode for Main Menu
}
break;
case 10:
{
GamemodeBomb();
}
break;
//Error retrieving Gamemode
default:
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error occured");
lcd.setCursor(0, 1);
lcd.print("Unknown Gamemode");
lcd.setCursor(0, 2);
lcd.print("Gamemode: ");
lcd.setCursor(0, 3);
lcd.print(GameMode);
}
}
}
void GamemodeBomb() {
switch (Phase) {
case 0: //Setup
{
lcd.clear();
lcd.home();
lcd.print("Place Bomb and");
lcd.setCursor(0, 1);
lcd.print("flip the Switch...");
lcd.setCursor(0, 3);
lcd.print("Bomb is STANDBY ");
gameStartTime = millis();
Phase = 2;
}
break;
case 2: //Place Bomb
{
int gameTimeLeft = (gameTime - (millis() - gameStartTime)) / 1000;
int gameTimeLeftSec = gameTimeLeft % 60;
int gameTimeLeftMin = gameTimeLeft / 60;
char timer[10];
sprintf(timer, "%02d%02d", gameTimeLeftMin, gameTimeLeftSec);
dsp1.print(timer);
dsp2.print(timer);
dsp1.setColonOn(gameTimeLeftSec % 2 == 0);
dsp2.setColonOn(gameTimeLeftSec % 2 == 0);
if (digitalRead(sfsw) == 1) {
if (digitalRead(butM) == 1) {
lcd.setCursor(0, 3);
lcd.print("Bomb is ACTIVE ");
} else {
lcd.setCursor(0, 3);
lcd.print("Bomb is ARMED ");
}
} else {
lcd.setCursor(0, 3);
lcd.print("Bomb is STANDBY ");
}
}
break;
case 4: //Defuse Bomb
{
}
break;
case 6: //Victory Screen
{
}
break;
//Error retrieving Gamemode
default:
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error occured");
lcd.setCursor(0, 1);
lcd.print("Unknown Phase");
lcd.setCursor(0, 2);
lcd.print("Phase: ");
lcd.setCursor(0, 3);
lcd.print(Phase);
}
}
}
Edit:
After about 3 hours of painfully adding Serial.println to every line and commenting out different lines I have finally found the two parts of the code that caused the problem. Thanks to anyone who tried to find a solution.
First thing was a minor error in the formula for gameTime, where I subtracted the time since the game started (millis() - gameStartTime), which is in milliseconds, from the time the game should run (gameTime) which is in seconds. This resulted in gameTimeLeft being negative which apparently caused some problems with the 7-Segment library.
After taking care of that, I had no problems with the speed of the calculations, but the display wasn't showing the correct timer. After some research I found that doing calculations with millis() should not involve an int. Changing gameTime to an unsigned long did the trick.
I can still notice some minor lags in the speed of the loop, mostly just the buzzer beeping a few milliseconds longer than it should every now and then, but thats probably because of the terrible code that will most likely be rewritten.
again thanks to everyone for taking a look at this,