stop digitalRead while ...

hello world! setup: 3 switches 3 lights 3 sounds each switch should turn on one light and play one sound. but only one at a time and while one is running, it shouldn't listen to the others. how can i stop or block the pins from reading while another function is running? problem in my sketch is, that while one is on and i press another switch(or the same switch again), it notes all the presses and performs them after the running one is finished.

i already spent 2 days trying with while, if, else if, switch case, return, break.. but still no success. the result was either, that it doesn't play to the end or it played the other stuff right behind. it shouldn't.

it seems to me, that i don't understand the basic flow of loops?!

i simplified the sketch for you and left out one light and all the audio stuff. the "returns" might be stupid as well, because didn't make any difference as i remember. the Serial.prints are just for checking

i'm losing my faith..

int knopf1 = 3; // Knopf == SWITCH int knopf2 = 4; int knopf3 = 5;

int val1 = 0; //BUTTONSTATE int val2 = 0; int val3 = 0;

int lastval1; //LAST BUTTONSTATE int lastval2; int lastval3;

int licht1 = 6; // licht == light int licht2 = 7; int licht3 = 8;

int x;

void setup() { Serial.begin(9600); pinMode(licht1, OUTPUT); pinMode(licht2, OUTPUT);

pinMode(knopf1, INPUT); pinMode(knopf2, INPUT); }

void loop(){ val1 = digitalRead(knopf1); val2 = digitalRead(knopf2);

if(val1 == HIGH && lastval1 == LOW && x == 0){ // i use switches as buttons, this section is for checking the state x = 1; lastval1 = val1; Serial.println("case 1a"); Serial.print("x = "); Serial.println(x); return; } else if(val1 == LOW && lastval1 == HIGH && x == 0){ x = 1; lastval1 = val1; Serial.println("case1b"); Serial.print("x = "); Serial.println(x); return; } else if(val2 == HIGH && lastval2 == LOW && x == 0){ x = 2; lastval2 = val2; Serial.println("case 2a"); Serial.print("x = "); Serial.println(x); return; } else if(val2 == LOW && lastval2 == HIGH && x == 0){ x = 2; lastval2 = val2; Serial.println("case2b"); Serial.print("x = "); Serial.println(x); return; }

Serial.print(" zwischencheck x = "); //just a check Serial.println(x);

while(x == 1){ // actual functions start here digitalWrite(licht1, HIGH); digitalWrite(licht2, LOW); delay(3000); x = 0; } while(x == 2){ digitalWrite(licht1, LOW); digitalWrite(licht2, HIGH); delay(3000); x = 0; } }

while(x == 1){                                             // actual functions start here
   digitalWrite(licht1, HIGH);
   digitalWrite(licht2, LOW);
   delay(3000);
   x = 0;
}

That loop will only execute once, if the value of 'x' is initially 1. So it's exactly the same as:

if (x == 1) {                                             // actual functions start here
   digitalWrite(licht1, HIGH);
   digitalWrite(licht2, LOW);
   delay(3000);
   x = 0;
}

This is the sort of thing that gets confusing! Maybe you should write down (on paper) a sort of time-line of what you want to happen, and when, in response to the button inputs. That way, you'll have a clear idea in your mind of what the code needs to do. You'll never get a working program without a clear, unambiguous understanding of exactly what you want to happen.

What does this do? [UNTESTED CODE]

/* || ControlPanel || || @contribution || | klickadiklick || | AlphaBeta || # */ byte knopf1 = 3; // Knopf == SWITCH byte knopf2 = 4; byte knopf3 = 5;

byte val1 = 0; //BUTTONSTATE byte val2 = 0; byte val3 = 0;

byte lastval1 = val1; //LAST BUTTONSTATE byte lastval2 = val2; byte lastval3 = val3;

int licht1 = 6; // licht == light int licht2 = 7; int licht3 = 8;

int x=0;

void setup() { Serial.begin(9600); pinMode(licht1, OUTPUT); pinMode(licht2, OUTPUT);

pinMode(knopf1, INPUT); pinMode(knopf2, INPUT); }

void loop(){ val1 = digitalRead(knopf1); val2 = digitalRead(knopf2);

if (val1 == HIGH && lastval1 == LOW && x == 0){ // i use switches as buttons, this section is for checking the state x = 1; lastval1 = val1; Serial.println("case 1a"); Serial.print("x = "); Serial.println(x); } else if (val1 == LOW && lastval1 == HIGH && x == 0){ x = 1; lastval1 = val1; Serial.println("case1b"); Serial.print("x = "); Serial.println(x); } else if (val2 == HIGH && lastval2 == LOW && x == 0){ x = 2; lastval2 = val2; Serial.println("case 2a"); Serial.print("x = "); Serial.println(x); } else if (val2 == LOW && lastval2 == HIGH && x == 0){ x = 2; lastval2 = val2; Serial.println("case2b"); Serial.print("x = "); Serial.println(x); }

Serial.print(" zwischencheck x = "); //just a check Serial.println(x);

if (x == 1){ // actual functions start here digitalWrite(licht1, HIGH); digitalWrite(licht2, LOW); delay(3000); x = 0; } else if (x == 2){ digitalWrite(licht1, LOW); digitalWrite(licht2, HIGH); delay(3000); x = 0; } }

[edit]How are you switches wired? Your code suggests pulldown resistors.[/edit]

[edit]Just could not resist: Solution Using Hardware Abstraction Libraries[/edit]

thanks for your answers! do you believe, that it might work if i use regular buttons? like it is now, the switches i use should work like buttons, no matter to which side they are pressed. or is there a mistake?

@ anachrocomputer: you're right, flowcharts help, so here it is. i'm not sure if i did it correct/if it works this way. it actually seems pretty simple, i have no idea why i can't get it workin. it would also be ok if one switch would interrupt the play function of the other.

@alphabeta: the code you posted here, without the returns, didn't make any difference.

yep, i'm using 10k pulldowns and i'm assuming, that they work on a switch, just like on a button?!

i took a deeper look at the abstractions you got going. looks quite interesting and pretty sexy. i'll test them and think i'll maybe use them in future. (btw: would be cool now if the switch library had the changed state function) . but: i didn't get them workin. after i inserted them in my libraries, on next startup i got:

In file included from Summer.h:11,
                 from Summer.cpp:9:
(...)/arduino-0015/hardware/cores/arduino/WProgram.h:29:7: warning: no newline at end of file
Summer.cpp:56:2: warning: no newline at end of file
In file included from Button.h:11,
                 from Button.cpp:9:
(...)/arduino-0015/hardware/cores/arduino/WProgram.h:29:7: warning: no newline at end of file
In file included from LED.h:11,
                 from LED.cpp:8:
(...)/arduino-0015/hardware/cores/arduino/WProgram.h:29:7: warning: no newline at end of file
LED.cpp:60:26: warning: no newline at end of file
LED.cpp:60: warning: 'DEBUG_LED' initialized and declared 'extern'

i know they aren't stable, but thought this might be interessting for you.

and when i tried your sketch from pastebin i got:

error: call of overloaded 'Button(int)' is ambiguous
hardware/libraries/Button/Button.h:19: note: candidates are: Button::Button(uint8_t, uint8_t)

hardware/libraries/Button/Button.h:18: note:                 Button::Button(uint8_t)

hardware/libraries/Button/Button.h:16: note:                 Button::Button(const Button&)

though the button example sketch worked fine. i tried on mac and linux.

edit: oops, i forgot now to post my newer sketch. i made one quite similar to alphabetas abstraction version. i got it on my other computer, will post later.

I must have forgotten too update the code.

For your convenience: ControlPanel.zip

All recent classes and the sketch.

i took a deeper look at the abstractions you got going. looks quite interesting and pretty sexy. i’ll test them and think i’ll maybe use them in future.

Thank you :slight_smile:

The rest of the Hardware Abstraction Libraries are listed here.

(btw: would be cool now if the switch library had the changed state function)

I can certantly implement this.

the wasPressed() will return what the previous isPressed() returned, until a new isPressed() call is made.

[edit]

/*
|| Button::wasPressed() Example
*/

#include <Button.h> //http://arduino.cc/playground/Code/Button

#define DELAY 3000

Button button = Button(12,PULLUP);

void setup() {
Serial.begin(9600);
}

void loop(){
if (button.isPressed()){
Serial.println(“button pressed”);
delay( DELAY );
}
//DO SOMETHING ELSE
if (button.wasPressed()){
Serial.println(“button was in fact pressed”);
}
}

[/edit]

thanks for zipping! also it seems your sketch works perfect. (unluckily i don't have my complete equipment here right now to make proper tests). mhhh, somehow i start believing, that the problem is in using the switch as a button. i'll do more testing with simpler sketches and post results soon.

Ahh. My library expects a momentary switch.
That could lead to somproblems. I have a library called Switch, but unfortunantly that makes a momentary switch, to a regular switch.

When testing again, I suggest downloading the ControlPanel.zip again. Fixed a minor bug in the Summer class.
[edit]I also included the most recent version of the Button class. Wich has the wasPressed and stateChanged functions.[/edit]

It works here now :slight_smile:

I would love to see your final sketch, be sure to post :slight_smile:

[edit]
Added a stateChanged() function as well. This would replace the calls to isPressed if you use a switch, not a button.

This sketch will blink 13 every time a switch or button changes state.

/*
|| Button::stateChanged():bool Example
*/

#include <Button.h>

//create a Button object at pin 12
/*
|| Wiring:
|| GND -----/ ------ pin 12
*/
Button button = Button(12,PULLUP);

void setup(){
pinMode(13,OUTPUT); //debug to led 13
}

void loop(){
button.isPressed();
if(button.stateChanged()){
digitalWrite(13,HIGH);
delay(100);
}else{
digitalWrite(13,LOW);
}
}

The stateChanged():bool will return true every time you flip the switch.[/edit]

thanks for doing the stateChanged! i think that’s a thing that will shorten the sketches a lot. shouldn’t it be included in switch.stateChanged instead in the button-library?

well, but now the not so cool thing is, that it still didn’t work out,like i want.
this is the sketch i tried, a “stateChanged-version” of the ControlPanel

/*
|| ControlPanel
||
|| @contribution
|| | klickadiklick
|| | AlphaBeta
|| #
*/

#include <LED.h>//http://arduino.cc/playground/Code/LED
#include <Button.h> //http://arduino.cc/playground/Code/Button
#include <Summer.h> //http://arduino.cc/playground/Code/Summer

#define DELAY 4000

Button knopf1 = Button(3); // Knopf == SWITCH
Button knopf2 = Button(4);
Button knopf3 = Button(5);

LED licht1 = LED(6); // licht == light
LED licht2 = LED(7);
LED licht3 = LED(8);

Summer summer1 = Summer(9);
Summer summer2 = Summer(10);
Summer summer3 = Summer(11);

void setup() {
Serial.begin(9600);
summer1.setTempo(300);
summer2.setTempo(300);
summer3.setTempo(300);
}

void loop(){
knopf1.isPressed();
knopf2.isPressed();

if (knopf1.stateChanged()){
Serial.println(“knopf1 pressed”);
licht1.on();
licht2.off();
summer1.playTone(440,2); //A4
summer1.playTone(880,1); //A5
delay( DELAY );
}
else if (knopf2.stateChanged()){
Serial.println(“knopf2 pressed”);
licht1.off();
licht2.on();
summer2.playTone(880,2); //A5
summer2.playTone(880,1); //A4
delay( DELAY );
}
}

i still keep having the same problem with this! did i declare the .isPressed at the right points?
the ControlPanel sketch, which uses regular buttons works perfect though!

i recognized, that “the bug” follows certain rules: if i flipped the same switch 10 times, it never recognized or play more than 2 or 3 times. also the sequence seems to matter, if i click different buttons after each other, in different sequences, it “remembers” or plays different flips.

i think that’s also why the sketch i posted first, was so complicated in the end, as i tried to do workarounds.

well, i’m giving up now and will use buttons instead, but i’d still like to know if there is a solution to this or what i’m doing wrong here.

ps: i don’t believe that my switches are the problem, because when i use them like a button(quick on-off), they work totally clean.

The delay will prevent you from getting a fast response. Comment it out, and test again.

:)

Btw, with the stateChanged() in button, the Switch class is really just... Obsolete.

uhm,.. there shouldn't be any response after the delay. that's the problem: it shouldn't listen to any presses while delay!!

using buttons, there is none, it doesn't! using switches, stateChanged or !=, it does! why?

If I understand you correctly, you do not want changes made during the delay, to trigger a new event?
Maybe something like this will help:

if (knopf1.stateChanged()){
   Serial.println("knopf1 pressed");
   licht1.on();
   licht2.off();
   summer1.playTone(440,2); //A4
   summer1.playTone(880,1); //A5
   delay( DELAY );
   //account for changes made during the delay
   knopf1.isPressed();
   knopf2.isPressed(); 
 }

wooohoooooooooooo, can't believe it yet, but it works!! :o thank you so much! so, what exactly is done here? by writing "knopf1.isPressed();" you create an "empty statement" for the case, that the button is pressed? how would it look like in regular code?

if (val1 == HIGH && lastval1 == LOW){ 
  lastval1 = val1;
  Serial.println("knopf1 switched");
  delay(3000);
  val1 == LOW && lastval1 == HIGH;  
}
else if (val1 == LOW && lastval1 == HIGH &&){
  lastval1 = val1;
  Serial.println("knopf1 switched");
  delay(3000);
  val1 == HIGH && lastval1 == LOW;
}

something like this? it's still confusing for me, but i'd love to understand.

What the knopf1.isPressed(); statement does is making sure that a change to the switch made during the delay, does not trigger a new if (knopf.stateChanged()).

In ‘regular code’ it would be the same as: previousState = currentState = digitalRead(pin); as the last statement in the if block.

This would be the same as saying “even though a state may have changed, discard it as it happend during this ‘event’”