Go Down

Topic: simple soft-button issue. (Read 763 times) previous topic - next topic

xSmurf

I'm sorry if this is a little stupid, I'm totally new to this (I got the board yesterday ;D )
I'm trying to code a "soft button". Press once the circuit turns on (a LED in this case) press another time and it turns off... It actually works, but only partially. Most of the times when I hit the button the LED will light up until I release the button. If I press many times in a row it will however produce the desired effect and turn on or off the LED.

Code: [Select]
int flashLED    = 11;
int statusLED   = 13;
int actionBTN   = 12;
int btnValue    = 0;
int softValue   = 0;

void setup(void) {
 // initialize inputs/outputs
 pinMode(flashLED, OUTPUT);
 pinMode(statusLED, OUTPUT);
 pinMode(actionBTN, INPUT);
 digitalWrite(statusLED, HIGH); // I just want to know when the AVR is done booting
}

void loop(void) {
 btnValue = digitalRead(actionBTN);

 if (btnValue == LOW) {
   if (softValue == 0) {
     softValue = 1;
   } else {
     softValue = 0;
   }
 }

 if (softValue == 1) {
   digitalWrite(flashLED, HIGH);
 } else {
   digitalWrite(flashLED, LOW);
 }
}
"Pilots believe in a clean living... they never drink wisky from a dirty glass."

xSmurf

Well, adding a bit of delay at the bottom of the (btnValue == LOW) statement seems to help. It works nicely with a "static" LED. If I use a flashing LED though, it will turn it on, but the problem is the same when trying to turn it off.
"Pilots believe in a clean living... they never drink wisky from a dirty glass."

CosineKitty

When I read your code literally, it looks like you are looping as fast as possible, polling digital input pin 12.  If that pin is LOW, you are rapidly toggling the output pin 11 HIGH/LOW.  In fact, it is probably so rapid that it appears to be on all the time.  Two things occur to me:
1. Instead of toggling every time you see pin 12 low, you probably want to toggle only when it goes from high to low.
2. Even that probably won't work right, because real mechanical switches have a tendency to produce noise for a millisecond or so while they are transitioning between open and closed, or closed and open.  So you may want to add a delay(1) on each loop, notice when you are transitioning from input pin 12 being high to low, and then start a countdown of maybe 50 loops (or 0.05 seconds).  Only when pin 12 has been low for 0.05 seconds, immediately after having just been high, should you toggle the output state.

Oh, and instead of doing this:

   if (softValue == 0) {
     softValue = 1;
   } else {
     softValue = 0;
   }

you can do this, which will do the same thing:

   softvalue = !softvalue;

Likewise, because HIGH==1 and LOW==0 (see lib\targets\arduino\wiring.h), you can replace:

 if (softValue == 1) {
   digitalWrite(flashLED, HIGH);
 } else {
   digitalWrite(flashLED, LOW);
 }

with:

  digitalWrite (flashLed, softValue);

I'm not sure if my earlier suggestion is phrased in an understandable way.  Feel free to post again with questions and I'll do my best to help!

- Don

xSmurf

Thanks for the pointers! I've been able to make this work. The code was refined. I did not have to take the noise into account with the switch and code I'm using (the switch is the one included on the SparkFun protoshield). The only thing that could still be integrated (noise excluded) is soft debounce, as it's now tracking changes of LOW to HIGH state. I'll have to look into it, but I don't think it would be so hard to do. I'll post an update when I do. Here is what I came up with.

Code: [Select]
int statusLED  = 13;
int flashLED   = 11;
int actionBtn  = 12;
int btnVal     = 0;
int softVal    = 0;
int lastBtnVal = HIGH;

void setup () {
 pinMode(statusLED, OUTPUT);
 digitalWrite(statusLED, HIGH);

 pinMode(flashLED, OUTPUT);
 pinMode(actionBtn, INPUT);
 
 beginSerial(9600); // Connect to the serial port, used for debugging
}

void loop() {
 btnVal = digitalRead(actionBtn);
 if (btnVal == LOW && lastBtnVal == HIGH) {
    lastBtnVal = LOW;
    Serial.println("Going low");
 }
 
 if (btnVal == HIGH && lastBtnVal == LOW) {
   softVal = !softVal;
   lastBtnVal = HIGH;
   Serial.println("Going high");
 }
 
 digitalWrite(flashLED, softVal);
}


Hopefully this will help others too :)
"Pilots believe in a clean living... they never drink wisky from a dirty glass."

xSmurf

#4
Dec 09, 2006, 09:42 pm Last Edit: Dec 09, 2006, 10:09 pm by xSmurf Reason: 1
I got around implementing soft debounce and figured I could post the code, maybe others will find it useful, maybe others will be able to tell me if I did anything wrong. It works very nicely as far as I can see.

Code: [Select]
int statusLED  = 13;
int flashLED   = 11;
int actionBtn  = 12;
int btnVal     = 0;
int softVal    = 0;
int bounceTime = 0;
int lastBtnVal = HIGH;

void setup () {
 pinMode(statusLED, OUTPUT);
 digitalWrite(statusLED, HIGH);

 pinMode(flashLED, OUTPUT);
 pinMode(actionBtn, INPUT);
 
 Serial.begin(9600);        // connect to the serial port
 Serial.println("Initialized");
}

void loop() {
 btnVal = digitalRead(actionBtn);
 if (btnVal == LOW && lastBtnVal == HIGH && bounceTime != -1) {
    lastBtnVal = LOW;
    Serial.println("Going low");
 }
 
 if (bounceTime == -1 && btnVal == HIGH) {
   bounceTime = 0;
 }
 
 if (btnVal == LOW && lastBtnVal == LOW) {
   bounceTime++;
   if (bounceTime >= 50) {
     bounceTime = -1;
     btnVal = HIGH;
     Serial.println("Action button debounced!");
   }
 }
 
 if (btnVal == HIGH && lastBtnVal == LOW) {
   softVal = !softVal;
   lastBtnVal = HIGH;
   Serial.print("Going high with softVal to: ");
   Serial.println(softVal);
 }
 
 digitalWrite(flashLED, softVal);
}
"Pilots believe in a clean living... they never drink wisky from a dirty glass."

Go Up