Wrestling with 2 switches and timing

Hi all, first project and already in trouble.

I want to build an right left signaller for my car. I mean Indicators. I have two switches on my steering wheel. Left and Right. (I don't have space in my car for the normal stalk on the steering column.)

If I press left, I want the system to check if Left is on, and switch it off. If it is off, switch it on. But if I pressed it briefly, say a third of a second, I want it to be on for 2 seconds and go off automatically.

If I press Right and left is on, I want left to go off and right to go on.

I tried it with a modified debounce, but ran into trouble and then I found the swPressed routine, so I tried that. Did not work because I have two switches that can be pressed.

So I think I will be using the following pseudo code:

Set all the pins 

start loop

Check state of switch1
   If low, and time1 is empty, set time1 to now 
      else 
     set timediff1 to now-time1  
//So this will loop until switch1 becomes High

If switch1 is High and timediff1 != 0 then
      If timediff1> debounce, then
         If timediff1 > longlimit, then
           Check light2
             If On, switch Off
           Check light1
             If On, switch Off, else switch On
         Else
            Switch on for 2 seconds 
            // thought of a simple delay() but that will mess up the timer
end of all Ifs
timediff1=0
time1=0         


Same checks for switch2
           
End of loop

That's what I am thinking of doing. Or is there an easier way?

I was thinking of doing the actual checks of the timediff in a separate function, pull it out of the loop. Good idea?

I thought it would be easy, but I am used to event driven software. So it is harder then I thought. Especially as there are two switches.

I have read all the stuff on interfacing it to relays and so, I think I got that sussed. But this realtime stuff, whew.

I would love your comments on this try. I am sure it is going to be messy, but this was all I could come up with.

Thanks in advance

Lykle

I thought it would be easy, but I am used to event driven software.

If you’re comfortable in event-driven terms, why not make an event system? Store the last known state of the system, and fire an event when the state changes.

#define N 2
byte pins[N] = { 9, 10 };
byte switches[N] = { LOW, LOW };
long when[N] = { 0, 0 };

void loop()
{
    long now = millis();
    for (int i = 0; i < N; i++)
    {
        byte pushed = digitalRead(pins[i]);
        if (switches[i] != pushed)
        {
            if (pushed)
                onButtonPressed(i);
            else
                onButtonReleased(i, when[i] - now);
            when[i] = now;
            switches[i] = pushed;
        }
    }    
}

void onButtonPressed(byte button)
{
    // what to do if a button's pushed
}

void onButtonReleased(byte button, long held)
{
    // what to do if a button's released
    // we learn how long it was held
}

I’m not saying this is complete, or even if it’s the best way to go, but you can adapt the whole system to work in the way you want it to work.

Well, I looked at your code and see what you are doing.
But not totally confident I can get it to run completely.

So I first did it my way. It works up to a point. I manage to get the Left button action, but the Right somehow escapes me.

I think it is a hardware issue, because when I connect the pin with GND it runs the code. But I can’t find the wiring fault on my breadboard.

Anyway, I will now try it your way and see what happens.
For completeness, here is the code my way:

/* Indicators for ONE
 * 
 * Each time one of the push-buttons is pressed the state of the system is checked. 
 * If this light is already on, switch it off.
 * If the other light is on, switch that off and switch this one on.
 * If none of the lights are on, switch this one on.
 * 
 * But all of this with the following check:
 * If the pushbutton is pressed shortly and a light needs to go on, 
 * It will do so for 2 seconds only.
 *
 * 4/4/2009
 *
 * Lykle Schepers, Paradym
 */

#define DEBOUNCE_TIME  40   // switch must be pressed at least this number of ms
#define TIME_LIMIT    1500  // Time limit for 2 seconds or full indicating

#define btnL 2              // pins for buttons
#define btnR 4

int outPinL = 10;          // the number of the output pin for Left
int outPinR = 12;          // The number of the output pin for Right
int stateL = LOW;
int stateR = LOW;


// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long timeL = 0;         
long timediffL = 0;   

long timeR = 0;         
long timediffR = 0;   


// +++++++++++++   Ok here we go   ++++++++++++++//

void setup(){
  Serial.begin(9600); 
  
  pinMode(btnL, INPUT);
  pinMode(btnR, INPUT);
  
  digitalWrite(btnL, HIGH);
  digitalWrite(btnR, HIGH);
   
  pinMode(outPinL, OUTPUT);
  pinMode(outPinR, OUTPUT);
}


// ++ Start of the main loop  ++//
void loop(){
  
// Check the right button
if(digitalRead(btnR) == LOW){
    if (timeR==0) {
    timeR = millis();

  } else { 
    timediffR = millis() - timeR;  // switch still pressed, so calc the time
  }
} else {
  if (timeR!=0) CheckRight();      // switch released, so check what to do.
}

  
// Check the left button
if(digitalRead(btnL) == LOW){
  if (timeL==0) {
    timeL = millis();

  } else { 
    timediffL = millis() - timeL;
  }
} else {
  if (timeL!=0) CheckLeft();
}

  
}  
// ++ end of loop ++ //
      
    
void CheckLeft(){
  
      Serial.print("Left button");
 
      // Button pressed, check duration and do the right thing
   
   if (timediffL > DEBOUNCE_TIME) {     
      if (timediffL > TIME_LIMIT) {
          if (stateR == HIGH) stateR = LOW;
          if (stateL == HIGH) {
            stateL = LOW;
          } else { 
            stateL = HIGH;
          }
      } else {
        if (stateR == HIGH) stateR = LOW;
        stateL=HIGH;
        delay(2000);
        stateL=LOW;  
      }
   }
   timeL = 0;
   timediffL = 0;
       
}  // end of CheckLeft


    
void CheckRight(){
  
      Serial.print("Right button");
      
      // Button pressed, check duration and do the right thing
   
   if (timediffR > DEBOUNCE_TIME) {
      if (timediffR > TIME_LIMIT) {
          if (stateL == HIGH) stateL = LOW;
          if (stateR == HIGH) {
            stateR = LOW;
          } else { 
            stateR = HIGH;
          }
      } else {
        if (stateL == HIGH) stateL = LOW;
        stateR=HIGH;
        delay(2000);
        stateR=LOW;  
      }
   }
   timeR = 0;
   timediffR = 0;
   
}    // end of CheckRight


// ++++++++++++++++  end of sketch  ++++++++++++++++++ //

Hmm, tried to get it to work, but I don’t fully understand what you are doing Ed.

This bit confuses me:

byte pushed = digitalRead(pins*);*
_ if (switches != pushed)_
* {*
* if (pushed)*
I simply don’t get it. Sorry.
Any chance of a noob clarification?
Lykle

I don't know if this helps at all, but coincidentally my first project is also for turn indicators for my car. (I'm an event driven programmer as well)

http://www.raymondandrews.com/zx-lights

I don't understand the momentary signal effect you are going for. You could also solve it with creative hardware. I remember seeing a momentary contact toggle switch that could be pushed or pulled, but then sprang back to center. Using something like that you could use one pin on push and another on pull for either side and avoid any bounce/delay checking at all.

Good Luck

The code is saying that pushed is equal to whatever state the pins are (pins 9 & 10 in this case), and it gets this via the digitalRead of those pins. It then moves on to the if statement and pulls the states of switches, which were both set to LOW to start with. If the state of switches is not equal to pushed (this basically sees if the state has changed, did the button get pressed), then continue on into the if statement.

Hi all,

Yes Ray I saw your work, really nice. But I already have the switches in One, and I just like the idea of blinking for 3 blinks and then off automatically. remember, here in Europe we change lanes all the time and have to indicate them.

the code, Hi Joja. Ye sI figured that bit, but then I don't get it.

If switch I is not pushed, then check if pushed. Huh?

That's the bit I don't get.

We have the same signaling laws here in America, just many more careless/ignorant drivers

How does this look. It may be wordy, but that’s just me.

Using a cycle delay of 50 ms, and counting how long the switch has been down should resolve any switch bounce issues.

const int left_signal_pin = 2;
const int right_signal_pin = 4;

const int off = 0;                       // signal states
const int quick = 1;
const int steady = 2;

const int cycle_delay = 50;              // allows for debouncing
const int quick_countdown = 3 * 1000;    // 3 second blinkers
const int idiot_countdown = 60 * 1000;   // forgot signals on ('doh) 

const int quick_tap = 300;               // ms for a quick tap
const int long_press = 1000;             // ms for full signal change

int left_state = off;
int left_pressed_count = 0;              // how long has switch been pressed
int left_signal_countdown = 0;           // how long till we turn off the signal lights

int right_state = off;
int right_pressed_count = 0;             // how long has switch been pressed
int right_signal_countdown = 0;          // how long till we turn off the signal lights


void setup()
  {
  pinMode(left_signal_pin,INPUT);
  pinMode(right_signal_pin,INPUT);
  }

void loop()
  {
  boolean left_pressed = digitalRead(left_signal_pin);
  boolean right_pressed = digitalRead(right_signal_pin);
  
  if (left_pressed)
    left_pressed_count += cycle_delay;
  else
    {
    // only need to decide what to do when you've let up on the switch
    if (left_pressed_count >= quick_tap && left_pressed_count < long_press)
      set_left_state(quick);
    if (left_pressed_count >= long_press)
      set_left_state(steady);
    left_pressed_count = 0;
    }
  
  if (right_pressed)
    right_pressed_count += cycle_delay;
  else
    {
    if (right_pressed_count >= quick_tap && right_pressed_count < long_press)
      set_right_state(quick);
    if (right_pressed_count >= long_press)
      set_right_state(steady);
    right_pressed_count = 0;
    }

  // do whatever you want to change the lights here  

  delay(cycle_delay);
  
  if (left_signal_countdown > 0)   
    {
    left_signal_countdown -= cycle_delay;
    if (left_signal_countdown <= 0)   set_left_state(off);
    }
  if (right_signal_countdown > 0)  
    {
    right_signal_countdown -= cycle_delay;
    if (right_signal_countdown <= 0)  set_right_state(off);
    }
  }
  
  
void set_left_state(int newstate)
  {
  switch (newstate)
    {
    case off    : left_signal_countdown = 0;
                  break;
    case quick  : left_signal_countdown = quick_countdown;
                  set_right_state(off);
                  break;
    case steady : left_signal_countdown = idiot_countdown;
                  set_right_state(off);
                  break;
    }
  left_state = newstate;
  }

  
void set_right_state(int newstate)
  {
  switch (newstate)
    {
    case off    : right_signal_countdown = 0;
                  break;
    case quick  : right_signal_countdown = quick_countdown;
                  set_left_state(off);
                  break;
    case steady : right_signal_countdown = idiot_countdown;
                  set_left_state(off);
                  break;
    }
  right_state = newstate;
  }

Lykle on reading further into the code it got to me too. For learning purposes as I’m not one of the experts here, but if I’m thinking right it would be a touch better as this.

byte pushed = digitalRead(pins[i]);
        if (switches[i] != pushed)
        {
            [glow]if (pushed == HIGH)[/glow]
                onButtonPressed(i);
            else
                onButtonReleased(i, when[i] - now);
            when[i] = now;
            switches[i] = pushed;
        }
    }

At least to me thinking about it right now this gives something to evaluate in the second “if” statement to deferentiate between the on button being currently pressed or just released, in which if it was just released and pushed now is equal to LOW it would move on to the “else” statement and execute the function onButtonReleased defined outside the loop. But hey it’s a thought!

Nice work Ray, I will certainly check out the code and get it to work. Just to see which one I find easier to work.

By the way, this is the car it is going into. Link to Flickr. http://www.flickr.com/photos/63831668@N00/141264729/in/set-72057594126837776/

@Jonesy, I agree with what you are saying, but I still don't find it easy to read. So I think I will stick to what I have. I wish Halley could explain a bit more.

Lykle