If-Statement should be false but seems to be true

Hi!
I'm working on a small project. A classical quiz bowl buzzer. Nothing big, just 2 pushbuttons and 2 LEDs at the moment (should be expanded to 4 lateron).

Concept:

  • parameter 'winner' = 0
  • While (winner == 0) checks, if button 1 or button 2 has been pressed.
  • If so, 'winner' is set to 1 or 2 and the while loop stops

Ive got a lot of debugging information and so I can say, that there's a problem with the button2-checking If statement. It becomes true, also the button isn't pressed and the state is LOW.

const int button1 = 2;
const int button2 = 1;
const int led1 =  13; 
const int led2 =  12;

int winner = 0;

void setup() {
  pinMode(led1, OUTPUT);    
  pinMode(led2, OUTPUT);    
  pinMode(button1, INPUT);     
  pinMode(button2, INPUT); 
  Serial.begin(9600);
  Serial.print("Init done, 'winner' set to: ");
  Serial.println(winner);
  delay(1000);
}

void loop(){
  Serial.print("Button 1 state: ");
  Serial.println(digitalRead(button1));
  Serial.print("Button 2 state: ");
  Serial.println(digitalRead(button2));
  delay(1000);
  Serial.println("Begin of while()");
  delay(1000);
  
  while(winner == 0) {
    if (digitalRead(button1) == HIGH) {  
      Serial.print("Button 1 state ");
      Serial.println(digitalRead(button1));   
      winner = 1;
      Serial.print("Winner now set to: ");
      Serial.println(winner);  
    }
    
    if (digitalRead(button2) == HIGH) { 
      Serial.print("Button 2 state ");
      Serial.println(digitalRead(button2));
      winner = 2;
      Serial.print("'winner' now set to: ");
      Serial.println(winner);    
    } 
  }
  
  Serial.println("While finished");
  delay(1000);
  
  if (winner == 1) {
    Serial.println("Winner = 1; LED 1 high");
    delay(1000);
    digitalWrite(led1, HIGH);
  }
  
  if (winner == 2) {
    Serial.println("Winner = 2; LED 2 high");
    delay(1000);
    digitalWrite(led2, HIGH);
  }
  
  Serial.println("All done. Going to do nothing");
  while (winner != 0) {
    Serial.print("Waiting for reset, winner is now: ");
    Serial.println(winner);
    delay(2000);
  }
}

And all I get is:

Init done, 'winner' set to: 0
Button 1 state: 0
Button 2 state: 0
Begin of while()
Button 2 state 0
'winner' now set to: 2
While finished
Winner = 2; LED 2 high
All done. Going to do nothing
Waiting for reset, winner is now: 2
[...]

So winner is set to 2, but the button wasn't pressed at all.

Thank you in advance :wink:

const int button2 = 1;

You can't use digital pin 1 while doing serial communication.

Argh!
Thank you very much. I know that it could be just a little mistake. On my protoshield I've wired the buttons correctly to 2 and 3, but I haven't changed the software.

Works perfekt! :slight_smile:

The easy ones are always easier to solve. :sunglasses:

No I have tidied up the code and removed nearly all debugging infos:

  Serial.println("Ready.");
  
  while(winner == 0) {
    if (digitalRead(button1) == HIGH) {  
      winner = 1;
    }
    
    if (digitalRead(button2) == HIGH) { 
      winner = 2;
    } 
  }

When I press button 1, it takes about a second until it is recognized. Button 2 works immediately. Both push buttons are wired the same. 10k pull-down and to +5V :-?

Which pins are you using right now? 2 and 3?
The next question is: how exactly have you wired your switches? I wonder why you pull the pins down and use the switches to pull them up. The atmel chips all have internall pull ups that can be activated. Hence the typical setup is to activate the pull ups and to pull the pins down with switches.

If you leave an input pin disconnected without any pull up/down, it will start to float and cause any number of strange effects (including significantly increased power consumption). This got me several times. Hence it would be interesting to know how exactly you wired your pins.

Cheers, Udo

Okay, no problem.

I'm using Pin 2 and 3 for the buttons.
Both pins are pulled down by 10k resistors.
The push buttons are connected to an input and +5V.
None of the pins is floating.

I can plug the pin direct to 5V and the delay is still there.
And to the first code I have just added a reset button.

Here are two images (not very usefull, chaos):
http://img687.imageshack.us/img687/1027/quiz004.jpg
http://img684.imageshack.us/img684/1961/quiz002.jpg

"On my protoshield I've wired the buttons correctly to 2 and 3, but I haven't changed the software."

What are button1 and button2 pin constants equated to now? Hopefully button1 = 2 and button 2 = 3.

Also, if that's not it, then can you physically switch the buttons and have the problem follow? I doubt this one since you said you could hook the input straight to 5V and it was still delayed.

What about the resistor that's obscured in the pictures, the one wired to pin 3. What value is it... if it were really large you might have this problem...

Regarding your application. I think for the most part this will run fast enough that it won't matter much, but to be fair I think you have to read both switches at the same exact time, and then process them. So you'd have to do a direct port read, and do some bit tests on the result.

I changed the buttons and the delay was on the other button.
I removed the push buttons and tested it without them - It works.
Then, I put them back and everything was just fine.

If I find some small bushbuttons, I'll build a button board on some stripboard. Then, a lot of wires and potential mistakes should disappear. And I can switch to 4 buttons.

Of course, the system isn't really fair, and for 4 players it becomes even more unfair, but I think, this is ok. At least I have no other ideas how to solve this.

Interesting, so initially the problem didn't follow the buttons, but after messing with the wires and putting it back they did. I have a theory, replace your wires with 22AWG solid. I have those same jumpers, because they looked perfect. And for the most part they are, but they have a weak connection from the wire to pin. If you solder them, even briefly, that connection desolders itself and you'll have an intermittent connection under the rubber tube. Maybe you didn't desolder and it just broke under there. I think if you rewire it will be fine.

Here's how I would code it to be fair, for two buttons:

#include <SoftwareSerial.h>
char val; // Data received from the serial port
byte buttons = 0; // Temporary value to store port D

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

void loop ()
{
  if (Serial.available()>0)  // If any character sent, read the switches
  {
    Serial.flush(); // flush buffer
        
    buttons = PIND;  // Read entire port D bus pins at once (read only)
    if ((buttons & 0x0C) == 0x0C ) //TIE!
    {
      Serial.println("BUTTON 1 & 2, TIE!");
    }
    else if ((buttons & 0x08) == 0x08 )
    {
      Serial.println("BUTTON 2");
    }
    else if ((buttons & 0x04) == 0x04 )
    {
      Serial.println("BUTTON 1");
    }
    else
    {
      Serial.println("NO BUTTONS");
    }
  }
}

Tested and working.

This can easily be expanded to 4 buttons or 8 even if you use a different port (bits 0 and 1 are RX/TX).

Have fun with your new game show!

Hi, I like the example of how to be fair. It is a very useful example for high speed applications.

But, putting it in perspective, the CPU is running at 16 Mhz, and executes most assembler/machine instructions in one clock cycle. So, even if the C compiles to several hundred instructions, that is only 100,000 th of a second! I think the button press itself going from fully open to fully closed will take much longer.

I think you could hook up all the pins and still have a reaction time faster than any human can perceive.

Not only reaction time is an issue if you have a resultion of ~1 microsecond. If you can resolve microseconds, then all of a sudden the mass of the moving parts of the switch will affect the measurement as well.

  • Udo

I guess I look at it a little differently. If you don't read all of the switches at once, you can't honestly say you're being fair. No matter what the timing. So if there was a close call, and the computer spit out a winner... you could say, "there is absolutely no way anyone else's button was down first".

Now, if you don't scan that port input infinitely fast, you still might have a tie when you really had one input come first. You always have one input first, I don't care if it's winning by one electron... one was first. The tie can occur because you didn't get to read the inputs at the very moment the first input was valid, and by the time you read again, the second one is active as well.

When you expand this out to 4 or 8 switches, the "round robin" approach of testing in switch in succession, in a loop, gets worse. Now as you go down the line checking #4, #5, #6 ... #1, #2, and #3 could go active and you wouldn't know which came first.

Technically, I think you want to LATCH your inputs as well. So a bouncy switch, or operator of that switch doesn't factor in. If the switch ever closes, it stays closed until the code can read it.

All of this would be accomplished pretty easily with an interrupt on pin change. The hardware is even faster than the code, and then the code can take a snapshot of which pin of a particular port has activated the interrupt, all in a few instructions.

It just depends on how "technical" and "ethical" you want to be about the process of reading multiple switches to determine which came first.

BrettW: if you want to push it that far there is no guarantee that your approach is any more fair than the others. Reason: the processor can never resolve anything below a discrete period of time (here: 1/16 us). Whever is faster in such a period of time will not necessarily win but might only tie. It is even possible for someone to be faster and neither win not tie. Reason: switching actually means charging the line (as a capacitator) until some thresshold is exceeded. For any number of influences (thermal, magnetic, whatever) the second in the row may tip of the switch an epsilon earlier. And there is nothing you can do about it. Our current understanding of physics tells that (look for Werner Heisenberg).

So there is not point to push this to "absolute fairness". It is not even clear what this means. You can only reach something like "proabilistic fairness". And this can be achieved with round robin just as well.

Cheers, Udo

Udo, the round robin approach is perfectly acceptable, for you. I prefer reading all of the inputs at once an order of magnitude faster than the round robin approach. It's easy enough to do, and I don't have to split atoms to do it. I just have to write some code and be comfortable with it for my application.

In this case, it's Sebi's application so the decision is not ours to make, only ours to influence and support.

Wow, thank you guys.
But I don't think, I'll go that far with this project.

I have found this circuit wirh CMOS ICs: http://www.zen22142.zen.co.uk/Circuits/Misc/quiz.htm

Maybe I just but this between the buttons and the Arduino. Then, the Arduino can control the LEDs (the delay doesn't matter this way) and I can use some serial commands to control a selfmade audio-player, that should stop, when somebody has hit his button.

But nevertheless, it's an interesting challenge to make something like this as fair as possible by using just a µC.

@BrettW: I know that it is faster. My current application is so time critical that I directly access the ports using inline assembler. However this application is not at all time critical. And it is complete overkill to optimize something like this. This was my point.

@Sebi: this is called over optimization or developer gold plating. Unless you really need this (e.g. for learning) it is a waste of time.

Think about it: if you push the time resolution to 1us or lower. How much impact would a mass difference of the button or difference in the springiness of the button have on the timing?

Cheers, Udo

@Udo: I know you know it's faster. It's not even about the speed. It's about reading all of the inputs at once to be fair. If you are going to make a decision that once switch was down before the others, how can you do that if you don't look at them all at the same time? Because of the probability that no two switches will be down within the same couple of microseconds between reads, it would be fairly hard to result in a tie.

I think it's absurd to suggest that the same amount of coding is over optimizing or a waste of time. I would characterize this as anything you personally are not willing to do. Just because it's easy and natural to do it that way for others, doesn't make it a waste of time. Just a waste of your time.

But I guess we are going to have to agree to disagree...

Good luck with your project Sebi!

@BrettW: I fully understand your point. But I disagree that you have to read all inputs at the same time to be "fair". You can read them round robin if you ensure that the time intervalls between the reads are spaces evenly. Of course whoever is polled first will have an "unfair" advantage. But this unfair advantage will be evenly distributed.

You always state that I am not willing to go that far and that it would not be easy for me. How do you know? In fact I have >1000 lines of inline assembler in my current project. And I have used direct port manipulation ever since I learned about it.

My point is that I would not push it for this kind of application.

Cheers, Udo