Stop a looping RGB LED with a 4x4 keypad arduino - arduino

I am using an RGB LED with a keypad. Pressing '1' turns on a light while pressing '2' turns off the light. After I press '3' I want the LED to loop through colors and only if a different button is pressed is when the code leaves the loop. My problem is while looping the keypads state of HIGH or LOW is not changed therefore the key that is saved as pressed cannot change. I need some way to get out of this loop without stopping the loop.
#include <Keypad.h>
const int GreenLED=9;
const int BlueLED=10;
const int RedLED=11;
const byte numRows=4;
const byte numCols=4;
char keymap[numRows][numCols] =
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
};
byte rowPins[numRows] = {5,4,3,2};
byte colPins[numCols] = {13,8,7,6};
char keypressed;
boolean ledPin_stateGreen;
boolean ledPin_stateRed;
boolean ledPin_stateBlue;
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows,
numCols);
void setup() {
pinMode(GreenLED, OUTPUT);
pinMode(BlueLED, OUTPUT);
pinMode(RedLED, OUTPUT);
ledPin_stateGreen = digitalRead(GreenLED);
ledPin_stateRed = digitalRead(RedLED);
ledPin_stateBlue = digitalRead(BlueLED);
Serial.begin(9600);
}
void loop() {
char key = myKeypad.getKey();
if(key != NO_KEY)
{
Serial.println(key);
}
//Serial.println(myKeypad.getState());
keypadEvent(key);
}
void setColor(int red, int green, int blue)
{
#ifdef COMMON_ANODE
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
#endif
analogWrite(RedLED, red);
analogWrite(GreenLED, green);
analogWrite(BlueLED, blue);
}
void keypadEvent (KeypadEvent key)
{
switch (myKeypad.getState())
{
case PRESSED:
if (key == '1')
{
digitalWrite(GreenLED, HIGH);
digitalWrite(BlueLED, HIGH);
digitalWrite(RedLED, HIGH);
}
if (key == '2')
{
digitalWrite(GreenLED, LOW);
digitalWrite(BlueLED, LOW);
digitalWrite(RedLED, LOW);
}
if (key == '3')
{
int previousState= myKeypad.getState();
while(key == '3')
{
key = myKeypad.getKey();
setColor(255, 0, 0); // red
delay(200);
Serial.println(myKeypad.getState());
setColor (50,50,50); //white
delay (200);
setColor (255,40,0);
delay(200);
setColor(0, 255, 0); // green
delay(200);
setColor(0, 0, 255); // blue
delay(200);
setColor(255, 255, 0); // yellow
delay(200);
setColor(80, 0, 80); // purple
delay(200);
setColor(0, 255, 255); // aqua
delay(200);
Serial.println(myKeypad.getState());
}
}
}
}

In your setup, you have GreenLED, BlueLED, RedLED set to OUTPUT, but then you try to digitalRead() from them...
void setup() {
pinMode(GreenLED, OUTPUT);
pinMode(BlueLED, OUTPUT);
pinMode(RedLED, OUTPUT);
ledPin_stateGreen = digitalRead(GreenLED);
ledPin_stateRed = digitalRead(RedLED);
ledPin_stateBlue = digitalRead(BlueLED);
Serial.begin(9600);
}

Your loop is preventing the keypad from being read for about 1.6 seconds. Then you have a very very small window to have the key pressed to pickup the key. Also, as you have stated, once you are in the loop you can't exit out of it due to the fact that you don't check for key presses. The tutorial on Arduino Playground states:
Consider, though, when you are writing your code that every delay()
you use will take processing time away from the keypad. Something as
short as delay(250) can make the keypad seem very unresponsive. And
the same thing will happen if you sprinkle a bunch of delay(10)'s all
through your code.
One way to solve this problem is to remove the delays from your loop and turn your program into a state machine which continuously polls the keypad for key presses. Now there are many ways to do this, of which I have chosen only one, and actually I really have turned it into 2 state machines. The top level one is the overall state of your program (i.e. what is our state based on the key pressed). The second one is a state machine to represent your loop which changes the colors of your LEDs. You can learn more about state machines here.
Here is your program turned into the above state machines:
#include <Keypad.h>
const int GreenLED=9;
const int BlueLED=10;
const int RedLED=11;
const byte numRows=4;
const byte numCols=4;
char keymap[numRows][numCols] =
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
};
byte rowPins[numRows] = {5,4,3,2};
byte colPins[numCols] = {13,8,7,6};
char keypressed;
boolean ledPin_stateGreen;
boolean ledPin_stateRed;
boolean ledPin_stateBlue;
enum MyState {
LIGHT_ON,
LIGHT_OFF,
LIGHT_LOOPING
};
enum LightState {
COLOR_1,
COLOR_2,
COLOR_3,
COLOR_4,
COLOR_5,
COLOR_6,
COLOR_7,
COLOR_8
};
//Our current state for lights
MyState currentState = LIGHT_LOOPING;
LightState currentLightState = COLOR_1;
//The previous time in milliseconds
unsigned long prevTimeMS = 0;
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows,
numCols);
void setup() {
pinMode(GreenLED, OUTPUT);
pinMode(BlueLED, OUTPUT);
pinMode(RedLED, OUTPUT);
ledPin_stateGreen = digitalRead(GreenLED);
ledPin_stateRed = digitalRead(RedLED);
ledPin_stateBlue = digitalRead(BlueLED);
Serial.begin(9600);
prevTimeMS = millis();
}
void loop() {
char key = myKeypad.getKey();
if(key != NO_KEY)
{
Serial.println(key);
}
//Serial.println(myKeypad.getState());
//This function is really checking to see if we need to perform a state
//transition or not for the currentState
keypadEvent(key);
//Do stuff based on the state We are in
unsigned long currentTimeMS = millis();
switch(currentState)
{
case LIGHT_ON:
//Don't really need to do anything since we perform
//the work on the state transition
break;
case LIGHT_OFF:
//Don't really need to do anything since we perform
//the work on the state transition
break;
case LIGHT_LOOPING:
//Now switch based on the current color state to see if we
//need to change to the next state
switch(currentLightState)
{
case COLOR_1:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_2);
}
break;
case COLOR_2:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_3);
}
break;
case COLOR_3:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_4);
}
break;
case COLOR_4:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_5);
}
break;
case COLOR_5:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_6);
}
break;
case COLOR_6:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_7);
}
break;
case COLOR_7:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
transitionLightState(COLOR_8);
}
break;
case COLOR_8:
if(checkDelay(currentTimeMS,prevTimeMS,200))
{
//We need to transition to the next state
//which is back to the first state so we loop
transitionLightState(COLOR_1);
}
break;
}
break;
}
}
//This will return true if the correct amount of time has passed
boolean checkDelay(unsigned long currentMS, unsigned long prevMS, unsigned long delayMS)
{
if((currentMS - prevMS) >= delayMS)
{
return true;
}
return false;
}
void transitionMyState(MyState newState)
{
switch(newState)
{
case LIGHT_ON:
digitalWrite(GreenLED, HIGH);
digitalWrite(BlueLED, HIGH);
digitalWrite(RedLED, HIGH);
break;
case LIGHT_OFF:
digitalWrite(GreenLED, LOW);
digitalWrite(BlueLED, LOW);
digitalWrite(RedLED, LOW);
break;
case LIGHT_LOOPING:
//We want to transition to the COLOR_1 state here
transitionLightState(COLOR_1);
break;
}
currentState = newState;
//need to save off a new prevTimeMS
prevTimeMS = millis();
}
void transitionLightState(LightState newState)
{
//perform the action for the state transition
switch(newState)
{
case COLOR_1:
setColor(255, 0, 0); // red
break;
case COLOR_2:
setColor (50,50,50); //white
break;
case COLOR_3:
setColor (255,40,0);
break;
case COLOR_4:
setColor(0, 255, 0); // green
break;
case COLOR_5:
setColor(0, 0, 255); // blue
break;
case COLOR_6:
setColor(255, 255, 0); // yellow
break;
case COLOR_7:
setColor(80, 0, 80); // purple
break;
case COLOR_8:
setColor(0, 255, 255); // aqua
break;
}
currentLightState = newState;
//need to save off a new prevTimeMS
prevTimeMS = millis();
}
void setColor(int red, int green, int blue)
{
#ifdef COMMON_ANODE
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
#endif
analogWrite(RedLED, red);
analogWrite(GreenLED, green);
analogWrite(BlueLED, blue);
}
void keypadEvent (KeypadEvent key)
{
switch (myKeypad.getState())
{
case PRESSED:
if (key == '1')
{
transitionMyState(LIGHT_ON);
}
if (key == '2')
{
transitionMyState(LIGHT_OFF);
}
if (key == '3')
{
transitionMyState(LIGHT_LOOPING);
}
}
}
The implementation is more for readability then minimizing code by the way. I added 2 state variables which hold what state we are in for the key handler state machine and the looping state machine. The important thing to note about this implementation is that key presses are checked every iteration of the loop and there are no delays implemented. This allows for us to break out of the looping color state machine at anytime. You could also say that the looping of colors changed into a poll of "Do I need to change my color now?"
The other important thing to note is that now the time needs to be tracked so the looping state machine can determine when the right amount of time has passed in order to know when to change states. When a state transition happens then the current time is saved off. Note: The rollover of the millis counter is not taken into account in this example. This happens roughly every 50 days according to the Arduino docs. So every 50 days you will get a glitch if you are in the LIGHT_LOOPING state.

Related

switching between functions using an IR remote

I have bought a WS2812B Led Strip. I'm trying to controll it with a IR remote. it is all controlled by a arduino uno.
I know the leds work and i know the remote works. I'm trying to pre-program a few animations on the remote.
The code below is as far as i got. I can show one animation, but i have to wait until it end to change it to onother one.
Is it possible to interupt this (becouse some animations are infinite) when i push a button to choose another animation?
#include <IRremote.h>
#include "FastLED.h"
#define NUM_LEDS 232
CRGB leds[NUM_LEDS];
#define PIN 7
const int RECV_PIN = 6;
IRrecv irrecv(RECV_PIN);
decode_results results;
unsigned long key_value = 0;
void setup(){
FastLED.addLeds<WS2812B, PIN, RGB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
Serial.begin(9600);
irrecv.enableIRIn();
irrecv.blink13(true);
}
//switch case for remote
void loop(){
if (irrecv.decode(&results)){
if (results.value == 0XFFFFFFFF)
results.value = key_value;
switch(results.value){
case 0xFF30CF:
Serial.println("1");
RGBLoop();
break ;
case 0xFF18E7:
Serial.println("2");
red();
break ;
case 0xFF7A85:
Serial.println("3");
break ;
}
key_value = results.value;
irrecv.resume();
}
}
void RGBLoop(){
while(key_value==key_value){
for(int j = 0; j < 6; j++ ) {
// Fade IN
for(int k = 0; k < 256; k++) {
switch(j) {
case 0: setAll(k,0,0); break;
case 2: setAll(k,k,0); break;
case 3: setAll(0,k,0); break;
case 4: setAll(0,k,k); break;
case 5: setAll(0,0,k); break;
}
showStrip();
delay(3);
}
// Fade OUT
for(int k = 255; k >= 0; k--) {
switch(j) {
case 0: setAll(k,0,0); break;
case 2: setAll(k,k,0); break;
case 3: setAll(0,k,0); break;
case 4: setAll(0,k,k); break;
case 5: setAll(0,0,k); break;
}
showStrip();
delay(3);
}
}
}
}
void red(){
irrecv.resume();
setAll(0,255,255);
showStrip();
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }
being honnest most of this I got online. it is my first time programming an arduino. but so far Im liking it
Instead of using infinite loops, you can just check for if any other command is received.
E.g:
instead of
while ( key_value == key_value ) //This is a weird infinite loop condition but whatever
{
// do stuff
}
you can have
while ( decode() == condition_for_this_loop )
{
// do stuff
}
or
for(;;) //This also is just an infinite loop, but looks nicer.
{
// do stuff
if ( decode() != condition_for_this_loop ) { break; }
}
Note that this is a pseudo code. You need to properly implement it. And you may need to alter the logic of your program a bit.
Since you have defined irrecv object globally, it will be visible for other functions below, this won't be a problem. Your code may even work just by replacing the loop condition. But if you get errors, you need to deal with them, I am just pointing to the logic. In the end, you can have something like this:
irrecv.decode( &results );
switch ( results )
{
case CONDITION_1:
inf_loop1();
break;
case CONDITION_2:
int_loop2();
break;
}
...
void inf_loop1()
{
for(;;)
{
// do stuff
irrecv.decode( &results );
if ( results != CONDITION_1 ) { break; }
}
}
void inf_loop2()
{
for(;;)
{
// do stuff
irrecv.decode( &results );
if ( results != CONDITION_2 ) { break; }
}
}
By the way, it's not a good idea to start with relatively big projects. By your question, I am assuming this is not only your first program for Arduino, but your first ever program. You don't run before you walk. Start slowly, blink some LEDs, implement some fun algorithms with LEDs, i don't know, have multiple of them and light them in different sequences, have some buttons and combine them with LEDs. Just play with LEDs. As you get more experience, you won't be asking questions like this. And if you start with some big project, chances are, you won't be able to do it, and got disappointed, or you will be just followed some online tutorials and copy-paste code, hence it won't feel like you did it.

LED Won't turn off when output mode is set to LOW

I am making an alarm system using an ultrasonic distance sensor. It can be armed and disarmed using a remote, and I want a green led to be on when it is disarmed, and a red led to be on when it is armed. The red led works fine, but the green one stays on.
I have tried commenting out the line that turns on the green led, but it seems to be on by default, so when I start the program, it is already on and won't turn off. The code in question is near the bottom, marked by a comment that says //HERE
#include "IRremote.h"
#include "SR04.h"
#define TRIG_PIN 12
#define ECHO_PIN 11
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long distance;
int receiver = 10;
IRrecv irrecv(receiver); // create instance of 'irrecv'
decode_results results; // create instance of 'decode_results'
int buzzer = 3;
int red_led = 2;
int green_led = 0;
bool can_sense = false;
bool release_pressed = false;
bool alarm_off = false;
/*-----( Function )-----*/
void translateIR() // takes action based on IR code received
// describing Remote IR codes
{
switch(results.value)
{
case 0xFFA25D: Serial.println("POWER"); alarm_off = true; break;
case 0xFFE21D: Serial.println("FUNC/STOP"); break;
case 0xFF629D: Serial.println("VOL+"); break;
case 0xFF22DD: Serial.println("FAST BACK"); break;
case 0xFF02FD: Serial.println("PAUSE"); release_pressed = true; break;
case 0xFFC23D: Serial.println("FAST FORWARD"); break;
case 0xFFE01F: Serial.println("DOWN"); break;
case 0xFFA857: Serial.println("VOL-"); break;
case 0xFF906F: Serial.println("UP"); break;
case 0xFF9867: Serial.println("EQ");release_pressed = false; break;
case 0xFFB04F: Serial.println("ST/REPT"); break;
case 0xFF6897: Serial.println("0"); break;
case 0xFF30CF: Serial.println("1"); break;
case 0xFF18E7: Serial.println("2"); break;
case 0xFF7A85: Serial.println("3"); break;
case 0xFF10EF: Serial.println("4"); break;
case 0xFF38C7: Serial.println("5"); break;
case 0xFF5AA5: Serial.println("6"); break;
case 0xFF42BD: Serial.println("7"); break;
case 0xFF4AB5: Serial.println("8"); break;
case 0xFF52AD: Serial.println("9"); break;
case 0xFFFFFFFF: Serial.println(" REPEAT");break;
default:
Serial.println(" other button ");
}// End Case
delay(100);
}
void setup() {
Serial.begin(9600);
pinMode(buzzer,OUTPUT);
pinMode(red_led,OUTPUT);
pinMode(green_led,OUTPUT);
irrecv.enableIRIn();
}
void loop() {
if (irrecv.decode(&results)) // have we received an IR signal?
{
translateIR();
irrecv.resume(); // receive the next value
}
distance = sr04.Distance();
if (distance < 70)
{
can_sense = true;
}
if (can_sense==true and release_pressed==false)
{
while (alarm_off==false)
{
digitalWrite(buzzer,HIGH);
digitalWrite(red_led,HIGH);
delay(500);
digitalWrite(buzzer,LOW);
digitalWrite(red_led,LOW);
delay(250);
if (irrecv.decode(&results)) // have we received an IR signal?
{
translateIR();
irrecv.resume(); // receive the next value
}
}
}
if (release_pressed==false) //HERE
{
digitalWrite(red_led,HIGH);
digitalWrite(green_led,LOW); // This should turn off the green led, but it doesn't
}
if (release_pressed==true)
{
digitalWrite(red_led,LOW);
digitalWrite(green_led,HIGH);
}
alarm_off = false;
can_sense = false;
}
Thanks for any help :)
Pins 0 and 1 on an Uno are used for serial communication.
As soon as you did Serial.begin(9600);, you enabled those pins for serial comms, so you can't also use them as standard digital pins.
Simply use another pin for your green LED.

Power button IRremote

I am creating 3 LEDs that will light up by a remote. I am able to light up the LEDs individually but I need the power button to shut off all of the LEDs. How can I create a 4th case to turn off all LEDs?
#include <IRremote.h>
int RECV_PIN = 3; // the pin where you connect the output pin of TSOP4838
int led1 = 2;
int led2 = 4;
int led3 = 7;
int itsONled[] = {0,0,0,0};
/* the initial state of LEDs is OFF (zero)
the first zero must remain zero but you can
change the others to 1's if you want a certain
led to light when the board is powered */
#define code1 12495 // code received from button A
#define code2 6375 // code received from button B
#define code3 31365 // code received from button C
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600); // you can comment this line
irrecv.enableIRIn(); // Start the receiver
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
}
void loop() {
if (irrecv.decode(&results)) {
unsigned int value = results.value;
switch(value) {
case code1:
if(itsONled[1] == 1) { // if first led is on then
digitalWrite(led1, LOW); // turn it off when button is pressed
itsONled[1] = 0; // and set its state as off
} else { // else if first led is off
digitalWrite(led1, HIGH); // turn it on when the button is pressed
itsONled[1] = 1; // and set its state as on
}
break;
case code2:
if(itsONled[2] == 1) {
digitalWrite(led2, LOW);
itsONled[2] = 0;
} else {
digitalWrite(led2, HIGH);
itsONled[2] = 1;
}
break;
case code3:
if(itsONled[3] == 1) {
digitalWrite(led3, LOW);
itsONled[3] = 0;
} else {
digitalWrite(led3, HIGH);
itsONled[3] = 1;
}
break;
}
Serial.println(value); // you can comment this line
irrecv.resume(); // Receive the next value
}
}

How to accept input from user after alarm is triggered

So as of right now when I arm the system and move my hand in front of the PIR sensor it says system triggered how do i get it to take a password from the user to deactivate the system. Also when the system is deactive it should say on the screen "Not Active"
#include <LiquidCrystal.h>
#include <Password.h>
#include <Keypad.h>
//Password
Password password = Password("1234");
LiquidCrystal lcd(0, 1, 10, 11, 12, 13);
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = { // Define the Keymap
{
'1','2','3','A' }
,
{
'4','5','6','B' }
,
{
'7','8','9','C' }
,
{
'*','0','#','D' }
};
byte rowPins[ROWS] = {9,8,7,6};
byte colPins[COLS] = {5,4,3,2};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
int armed = 0;
const int pir1 = A4;
int sensorHit = 0;
int alarmStatus = 0;
int alarmActive = 0;
int zone = 0;
void setup() {
// put your setup code here, to run once:
lcd.begin(16,2);
pinMode(pir1, INPUT);
mainScreen();
keypad.addEventListener(keypadEvent);
}
void loop() {
// put your main code here, to run repeatedly:
keypad.getKey();
if(alarmActive == 1){
if(digitalRead(pir1) == HIGH){
zone = 0;
alarmTriggered();
}
}
}
void keypadEvent(KeypadEvent eKey){
switch (keypad.getState()){
case PRESSED:
lcd.print(eKey);
switch (eKey){
case '#': checkPassword(); break;
default:
password.append(eKey);
}
}
}
void alarmTriggered(){
password.reset();
alarmStatus = 1;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("SYSTEM TRIGGERED");
lcd.print(0,1);
if(zone == 0){
lcd.print(" FRONT DOOR OPEN ");
}
}
void checkPassword(){
if (password.evaluate()){ //if code is correct:
lcd.clear(); //clear LCD
lcd.print("VALID PASSWORD"); //print message
password.reset(); //resets password after correct entry
delay(1500); //wait...
lcd.clear(); //clear
if (alarmStatus==0 && alarmActive == 0){ //if system is off (ie: disarmed)
lcd.print("ARMED!"); //display message
alarmActive=1; //system armed
alarmStatus=1;
delay(2000); //wait
lcd.clear(); //clear
lcd.setCursor(0, 0); //return to top left of LCD
lcd.print("Code to disarm:"); //back to where we began
}
else{
lcd.print("DISARMED!"); //display message
alarmActive=0; //system unarmed
alarmStatus=0;
delay(2000); //wait
lcd.clear(); //clear
lcd.setCursor(0, 0); //return to top left of LCD
lcd.print("Code to arm:"); //back to where we began
}
}
else{ //if password is incorrect:
lcd.clear();
lcd.print("INVALID PASSWORD");
password.reset(); //resets password after INCORRECT entry
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Retry Code:");
}
}
void mainScreen(){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Enter Pin:");
}
You need an input device for entering the password. A simple example can be 10 switches where each switch represent 1 so our password has to be between 0 to 10. You add the switches values together and compare with your set password. The rest should be easy for you.

How can I set a ceratin time interval for reading input in my Arduino game?

I'm making a game with my Arduino Uno.
4 leds on the breadboards are displaying a random binary number.
The player needs to press the button to put in the number that he sees
(for example, if the leds are 0011, push the button 3 times).
If he guessed right, he wins (another led blinks). If not, he loses (led turns on and stays on).
But I want the player to automatically lose if he hasn't pressed a button for two seconds.
But I'm really a beginner so bear with me. Below I'll post what I've got so far. But it's not exactly working. When I turn it on, without me pressing the button, it just goes straight to "you win" and the next round. What am I doing wrong?
int led1 = 9;
int led2 = 6;
int led3 = 5;
int led4 = 3;
int ledResult = 13; //will blink when you won, stay on when you lost
int buttonPin = 2;
int val = 0; // variable for reading the pin status
int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;
long interval = 2000;
long randomNumber;
void setup() {
Serial.begin(9600); //starts serial communication
pinMode (led1, OUTPUT);
pinMode (led2, OUTPUT);
pinMode (led3, OUTPUT);
pinMode (led4, OUTPUT);
pinMode (ledResult, OUTPUT);
pinMode (buttonPin, INPUT);
randomSeed(analogRead(A0)); //the pin is unconnected so it'll return something random (0-1023)
}
void loop() {
randomNumber = random(1, 16);
Serial.println("Random Numbers sequence"); //just for self-check
Serial.println(randomNumber);
if (randomNumber >= 8)
{
digitalWrite (led1, HIGH);
randomNumber - 8;
}
else
{
digitalWrite (led1, LOW);
}
if (randomNumber >= 4)
{
digitalWrite (led2, HIGH);
randomNumber - 4;
}
else
{
digitalWrite (led3, LOW);
}
if (randomNumber >= 2)
{
digitalWrite (led4, HIGH);
randomNumber - 2;
}
else
{
digitalWrite (led1, LOW);
}
if (randomNumber = 1)
{
digitalWrite (led2, HIGH);
}
else
{
digitalWrite (led1, LOW);
}
unsigned long currentMillis = millis();
if (currentMillis > interval) {
Serial.println("You lost.");
digitalWrite(ledResult, HIGH);
}else{
//READ BUTTON STATE
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
if (buttonState == HIGH)
{
buttonPushCounter++;
Serial.println("Button push counter:");
Serial.println(buttonPushCounter);
}
// Delay a little bit to avoid bouncing
delay(50);
}
// save the current state as the last state, for next time through the loop
lastButtonState = buttonState;
if (buttonPushCounter = randomNumber) {
Serial.println("You won!");
digitalWrite(ledResult, HIGH);
delay(700);
digitalWrite(ledResult, LOW);
delay(700);
}
else
{
Serial.println("You lost.");
digitalWrite(ledResult, HIGH);
}
}
}
Essentially you'll want to have a main loop that probes/polls for user input, and if there's no input from the user on probe, then check the current millis time against when you called it for start. This will give you the elapsed time since no input was detected. If the elapsed time is greater than your threshold, you break out of the loop and check a timeout flag to see if you proceed with the button validation code or branch to the "lose" code.
Without writing the whole thing, here's a C pseudo-code mock up of the idea (commented to explain):
void loop() {
while (is_running) { // main loop
unsigned long start = millis(); // get starting probe time
bool timeout = false;
while ((buttonState = probe_input()) == no_input_val) {
/* probe_input function returned no input,
so check for timeout. If the probe_input function
did return a 'value', then this loop won't iterate
and you can check the buttonState below */
if ((millis() - start) >= interval) {
/* millis is monotonic time, so calling it, then
subtracting the value from the start value will give
us elapsed time since user did not give input. */
timeout = true;
break;
}
}
if (!timeout) {
/* button state/level code */
} else {
// lose code
}
}
}
Again, this is just pseudo-code and won't compile as you'd need to implement the probe_input function to poll for input, but it's more to illustrate what you'd need to do to get you moving in the direction you're wanting.
I hope that can help.

Resources