Hey! I'm working on a project and I have 4 input buttons and 4 output LEDs. I am tracking the signal for one of the buttons by printing it in the Serial monitor, and I noticed that while any LED is on, the Arduino is not reading in the signal for the button. This is an issue because I need to be able to push the button and create actions while the LEDs are on. For reference, I'm trying to code a whack-a-mole game using buttons and LEDs. Please help! My code is below:
unsigned long startMillis;
unsigned long currentMillis;
unsigned long onMillis;
const unsigned long period = 1000;
const int bButton = 2;
const int gButton = 4;
const int yButton = 6;
const int rButton = 8;
const int bLED = 3;
const int gLED = 5;
const int yLED = 7;
const int rLED = 9;
volatile int bbState = 0;
int gbState = 0;
int ybState = 0;
int rbState = 0;
int lastbbState = 0;
int lastgbState = 0;
int lastybState = 0;
int lastrbState = 0;
volatile bool gbPressed = false;
volatile bool bbPressed = false;
volatile bool ybPressed = false;
volatile bool rbPressed = false;
bool gameCondition = true;
int mole = 0;
int hitCount = 0;
void endGame()
{
gameCondition = false;
for(int j = 0; j<3; j++)
{
for(int i = 2; i<9; i=i+2)
{
digitalWrite(i,HIGH);
delay(100);
digitalWrite(i,LOW);
}
}
}
void setup() {
// put your setup code here, to run once:
startMillis = millis();
Serial.begin(9600);
for(int i = 0; i < 10; i++)
{
if(i%2 == 0)
{
pinMode(i, INPUT);
digitalWrite(i, 1);
}
else
{
pinMode(i, OUTPUT);
digitalWrite(i, HIGH);
delay(200);
digitalWrite(i, LOW);
}
}
}
void loop() {
// put your main code here, to run repeatedly:
currentMillis = millis();
Serial.print(bbState);
mole = 2*random(2,6)-1;
bbState = digitalRead(bButton);
gbState = digitalRead(gButton);
ybState = digitalRead(yButton);
rbState = digitalRead(rButton);
if (currentMillis - startMillis >= period)
{
digitalWrite(mole, !digitalRead(mole));
while(currentMillis - startMillis < 2*period)
{
bbState = digitalRead(bButton);
gbState = digitalRead(gButton);
ybState = digitalRead(yButton);
rbState = digitalRead(rButton);
currentMillis = millis();
digitalWrite(mole, digitalRead(mole));
}
digitalWrite(mole, !digitalRead(mole));
startMillis = currentMillis;
}
if(bbState != lastbbState)
{
if(bbState == 1)
{
if(mole == bLED)
{
if(digitalRead(bLED) == 1)
{
digitalWrite(bLED, 0);
hitCount++;
Serial.print(hitCount);
}
}
}
}
delay(100);
}
A while loop like this is no better than a delay. This is your problem. You're still reading the buttons, but you can't do anything with the values until you're out of the loop.
I figured that was it. So how can I wait that full period without writing in a delay. I need a random light to turn on, wait the period, and turn off again before a new random number is generated.
Do you think you can show me how to do this? I was using just the if statement before but it would generate a new random number before the timing period was over, so it would just turn another LED on instead of turning the same one back off. I used your blink without delay tutorial to do this, actually, but I couldn’t figure out how to turn the same LED back off since a new random number is generated at the start of each loop.
No, actually the opposite. A randomly generated light should turn on for a certain amount of time, and when I press the corresponding button it should turn off. It’s like whack-a-mole, but with LEDs and buttons instead of moles and a hammer. My issue is that while the light is on the buttons don’t take any input.
Hi,
Can you please post a circuit diagram?
How have you got your buttons wired?
If your button is between 5V and the input pin, have you got a 10k resistor between the input and gnd, to pull the input pin LOW when the button is not pressed.
OR
If your button is between GND and the input pin, have you got a 10k resistor between the input and 5V, to pull the input pin HIGH when the button is not pressed.
I wrote this a while ago as an example for someone
const byte ledPins[] = {3, 5, 6, 9};
const byte inputPins[] = {A3, A2, A1, A0};
byte currentInputState = HIGH;
byte previousInputStates[] = {HIGH, HIGH, HIGH, HIGH};
byte ledStates[] = {LOW, LOW, LOW, LOW};
unsigned long startTimes[] = {0, 0, 0, 0};
unsigned long periods[] = {0, 0, 0, 0};
unsigned long currentTime;
byte currentLed;
byte moleCount;
void setup()
{
Serial.begin(115200);
while (!Serial);
for (int p = 0; p < 4; p++)
{
pinMode(inputPins[p], INPUT_PULLUP); //turn on the built in pullup resistors
pinMode(ledPins[p], OUTPUT);
digitalWrite(ledPins[p], HIGH); //turn off the LEDs
}
}
void loop()
{
currentTime = millis();
//
//choose an LED to turn on
//
currentLed = random(4); //choose an LED (0 to 3)
if (digitalRead(ledPins[currentLed]) == HIGH) //if the LED is off
{
if (random(5000) == 0) //1 in 4999 chance of turning on
{
periods[currentLed] = random(1000, 5000); //random on time
startTimes[currentLed] = currentTime;
digitalWrite(ledPins[currentLed], LOW); //turn on the LED
}
}
//
//read the inputs and detect button presses
//
for (int p = 0; p < 4; p++)
{
currentInputState = digitalRead(inputPins[p]);
if (currentInputState != previousInputStates[p]) //input state has changed
{
if (currentInputState == LOW) //the button has become pressed
{
if (digitalRead(ledPins[p]) == LOW) //the LED is on
{
digitalWrite(ledPins[p], HIGH); //turn off the LED
moleCount++;
Serial.print("number of moles whacked : ");
Serial.println(moleCount);
}
}
}
previousInputStates[p] = currentInputState;
//
//now turn off an LED if its period is up
//
if (currentTime - startTimes[p] >= periods[p]) //has the period ended ?
{
digitalWrite(ledPins[p], HIGH); //turn off the LED
}
}
}
The pin numbers and logic will need changing to suit your project but it may give you some ideas. It would be neater if it used an array of structs but the use of individual arrays works just as well
Thanks so much. I input this into my code and changed the variable names and stuff, but now only one LED will turn on, it won't turn off, and pressing my button does nothing. I'm so confused. :((
Hi @UKHeliBob. This was done by accident by one of the moderators. I'm working now on relisting all the affected posts and we will get this straightened out.
So basically it's just not shown in the topic listing, but anyone who has a link to it can still participate in the topic.
Yeah, I think we're all struggling a bit to learn this complex new system. I've already caught a couple of fumbles I made.
We haven't figured it out yet. I'm going to try to investigate now. At first, when I saw all the unlisted topics in the context of the conversation we were having at the time it occurred, I assumed it was only a result of a misunderstanding of the global nature of unlisting a topic, but I have now learned that I was wrong about that. I'll report my findings.