Pages: [1]   Go Down
Author Topic: Help with fading and switching an LED  (Read 548 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello!
I have a [I think] capacitive sensing pad as a light switch in my bedroom. If you tap the pad, it switches the light. If you press your finger on the pad, it fades the light until minumum / maximum brightness, then reverses. If you release your finger, then press down again, it will begin fade in the opposite direction. If you switch the light off by tapping the pad lightly, then if you press the pad again, the light will turn on at the previous brightness (it remembers the brightness before you turned it off), and fade up / down. If that needs more explaination, I would be happy to provide it. I want to imitate that effect using a momentary push button and an LED for now, using Arduino. Here is the non-working code so far:
Code:
#include <Easy.h>
Routine up;
Routine down;
//enum{down, up};
boolean isPushed;
word timeout = 250;
boolean timeoutSwitch = false;
boolean switched = false;
unsigned long prev = 0;
byte led = 10;
byte button = 2;
byte ledVal = 0;
boolean upOrDown = 1;
void fadeLED(){
  static int dir = 1;
  ledVal += dir;
  analogWrite(led, ledVal);
  if(ledVal >= 255 || ledVal <= 0) dir -= 2;
}
void setup(){
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}
void loop(){
  isPushed = !digitalRead(button);
  if(isPushed){
    if(!switched){
      prev = millis();
      switched = true;
    }
    if(millis() - prev > timeout){
      up.begin(20, fadeLED);
    }
  }
  else{
    if(millis() - prev <= timeout){
      ledVal = !ledVal;
      digitalWrite(led, ledVal);
    }
    switched = false;
  }
}

I am having trouble with the logic. I want this to happen: if the button is pressed and released quickly (200ms or so), switch the light, but remeber the ON brightness. If button is held down for longer than 200ms, fade up / down. If brightness reaches maximum / minimum while fading, reverse direction. If button is released, then held again, fade in reverse direction. It is essentially imitating my bedroom light switch. I would appreciate it if someone can shed some light on this.
Thanks!
Logged


Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46240
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The only way to do what you are trying to do is to remember whether the switch was also pressed last time, too.

If the switch is pressed, and was not last time, this is a new press.

If the switch is pressed, and was also pressed last time, the switch is still being pressed. If the switch is still being pressed, then you need to determine how long it has been pressed (by subtracting now from then, where then is when the transition to pressed occurred (see above)).

Without knowing the previous state of the switch, I can see no way to accomplish what you are trying to do.
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I updated the code:
Code:
#include <Streaming.h>
#define DEBUG 1
const byte led = 9;
const byte button = 2;
const word interval = 200;
typedef enum{
  PRESSED, UNPRESSED}
button_state;
button_state lastState = UNPRESSED;
button_state state;
unsigned long prev = 0;
byte ledVal = 0;
byte lastLedVal = 0;
int dir = 1;
boolean beenOff = false;
//boolean beenOn = false;
void setup(){
#if (DEBUG)
  Serial.begin(9600);
#endif
  pinMode(button, INPUT_PULLUP);
  pinMode(led, OUTPUT);
  TCCR1B = TCCR1B & 0b11111000 | 0x04;
}
void loop(){
  state = (button_state)digitalRead(button);
  if(state != lastState){
    if(state == PRESSED){
      prev = millis();
      if(beenOff){
        switchLED();
        beenOff = false;
        //beenOn = true;
        delay(interval+1);
      }
      dir = -dir;
    }
    if(state == UNPRESSED){
      if(millis() - prev < interval){
        lastLedVal = ledVal;
        //if(!beenOn){
        switchLED();
        beenOff = true;
        //}
      }
    }
    lastState = state;
  }
  if(ledVal == 0) dir = 1;
  else if (ledVal == 255) dir = -1;
  if(state == PRESSED && millis() - prev >= interval){
    //beenOn = false;
    ledVal += dir*5;
  }
  analogWrite(led, ledVal);
#if (DEBUG)
  Serial << "state: " << state << ", lastState: " << lastState
    << ", ledVal: " << ledVal << ", lastLedVal: " << lastLedVal
    << ", dir: " << dir << endl;
#endif
}
void switchLED(){
  if(ledVal > 0) ledVal = 0;
  else ledVal = lastLedVal;
}

It works okay now. Next, I will use capacitive sensing instead of a button. That should not be so hard.
One more question: how can I get rid of the delay(interval+1) line? That was to not trigger the if statement for PRESSED and UNPRESSED right after each other, causing the LED to turn right back off once it turned on. You can see some commented-out failed attempts in the code. Do you get what I mean?
« Last Edit: July 11, 2012, 08:09:13 pm by dkl65 » Logged


Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46240
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
One more question: how can I get rid of the delay(interval+1) line?
That delay is apparently to manage debouncing the switch. If the switch bounces for 201 milliseconds, you need a better switch. 20 milliseconds is a lot of bouncing.
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It is more likely due to the software, especially this part:
Code:
if(millis() - prev > interval){
  //...

Now, I exchange the button for CapSense foils. Here is the new code:
Code:
#include <CapSense.h>
#include <Streaming.h>
#define DEBUG 1
const byte led = 9;
const word interval = 200;
/*const byte sendPin = 4;
 const byte recvPins[3] = {
 2, 6, 8};*/
typedef enum{
  TOUCHED, UNTOUCHED}
touch_state;
touch_state lastState = UNTOUCHED;
touch_state state;
unsigned long prev = 0;
byte ledVal = 0;
byte lastLedVal = 0;
int dir = 1;
boolean beenOff = false;
//boolean beenOn = false;
CapSense set1 = CapSense(4,2);        // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired
CapSense set2 = CapSense(4,6);        // 10M resistor between pins 4 & 6, pin 6 is sensor pin, add a wire and or foil
CapSense set3 = CapSense(4,8);        // 10M resistor between pins 4 & 8, pin 8 is sensor pin, add a wire and or foil
void setup(){
#if (DEBUG)
  Serial.begin(9600);
#endif
  pinMode(led, OUTPUT);
  TCCR1B = TCCR1B & 0b11111000 | 0x04;
}
void loop(){
  state = isTouched();
  if(state != lastState){
    if(state == TOUCHED){
      prev = millis();
      if(beenOff){
        switchLED();
        beenOff = false;
        //beenOn = true;
        delay(interval+1);
      }
      dir = -dir;
    }
    if(state == UNTOUCHED){
      if(millis() - prev < interval){
        lastLedVal = ledVal;
        //if(!beenOn){
        switchLED();
        beenOff = true;
        //}
      }
    }
    lastState = state;
  }
  if(ledVal == 0) dir = 1;
  else if (ledVal == 255) dir = -1;
  if(state == TOUCHED && millis() - prev >= interval){
    //beenOn = false;
    ledVal += dir*5;
  }
  analogWrite(led, ledVal);
#if (DEBUG)
  Serial << "state: " << state << ", lastState: " << lastState
    << ", ledVal: " << ledVal << ", lastLedVal: " << lastLedVal
    << ", dir: " << dir << endl;
#endif
}
void switchLED(){
  if(ledVal > 0) ledVal = 0;
  else ledVal = lastLedVal+5;
}
touch_state isTouched(){
  unsigned long prev = millis();
  long totals[3] = {
    set1.capSense(30),
    set2.capSense(30),
    set3.capSense(30)
  };
  unsigned long finished = millis();
#if (DEBUG)
  Serial << "CapSense time: " << (finished - prev) << ", ";
#endif
  for (byte i = 0; i < 3; i++) if(totals[i] > 500) return TOUCHED;
  return UNTOUCHED;
}
But there is a compiler error that I cannot figure out the source of:
Code:
sketch_jul15b:2: error: 'touch_state' does not name a type
sketch_jul15b.cpp: In function 'void loop()':
sketch_jul15b:31: error: 'isTouched' was not declared in this scope
What does that mean?
Logged


Pages: [1]   Go Up
Jump to: