Double Click Function

Hi All

I have an Arduino running in my car to close, open and tilt the mirrors.
the open and close function work from the FOB, opens when the doors are unlocked and closes when the doors are locked. I want to modify the code so the mirrors close when I double click the close button, so basically when
pinMode(close_pin,INPUT); is pressed twice.

here is the code

#define reverse_pin 5
#define switch_pin 6
#define close_pin 2
#define open_pin 12
#define tiltup_pin 9
#define tiltdn_pin 10
#define m1_pin 7
#define m2_pin 8
#define tilttmr 1630
#define closetmr 2600

boolean tiltuplock=false,closemrrlk=true;

void setup (){
  pinMode(reverse_pin,INPUT);
  pinMode(switch_pin,INPUT);
  pinMode(close_pin,INPUT);
  pinMode(open_pin,INPUT);
  pinMode(tiltup_pin,OUTPUT);
  pinMode(tiltdn_pin,OUTPUT);
  pinMode(m1_pin,OUTPUT);
  pinMode(m2_pin,OUTPUT);
  digitalWrite(tiltup_pin,LOW);
  digitalWrite(tiltdn_pin,LOW);
  digitalWrite(m1_pin,LOW);
  digitalWrite(m2_pin,LOW);
 }

void loop(){
  if(digitalRead(switch_pin)){
    if(digitalRead(reverse_pin)&&tiltuplock){//Tilt down
      delay(300);
      if(digitalRead(reverse_pin)){
        tiltuplock=false;
        digitalWrite(tiltdn_pin,HIGH);
        delay(tilttmr);
        digitalWrite(tiltdn_pin,LOW);
      }
    }
    if(!digitalRead(reverse_pin)&&!tiltuplock){//Tilt up
      tiltuplock=true;
      digitalWrite(tiltup_pin,HIGH);
      delay(1720);
      digitalWrite(tiltup_pin,LOW);
    }
  }
  else{
    if(digitalRead(open_pin)&&!digitalRead(close_pin)&&!closemrrlk){//Close mirror
      closemrrlk=true;
      digitalWrite(m1_pin,HIGH);
      delay(closetmr);
      digitalWrite(m1_pin,LOW);
    }
    if(!digitalRead(open_pin)&&digitalRead(close_pin)&&closemrrlk){//Open mirror
      closemrrlk=false;
      digitalWrite(m2_pin,HIGH);
      delay(closetmr);
      digitalWrite(m2_pin,LOW);
    }
  }
}

Any suggestions besides searching because I did a lot of that?

Double-click has a time factor. Two clicks in 0.5 seconds might be considered a "double".

So record when you got the last click and compare it to the current time. Use millis() to get the time in milliseconds. Keep most of the calculation in milliseconds, don't convert to seconds.

I'll be honest – I'm too lazy to look at your code, but I'm not too lazy to share my ruff way of doing it:

To convert regular button to a double click button I would create a delay value (see blink without delay example) for that button. After fist button release and debounce time MCU has to check that button state as often as it can (assuming you are not using interrupts) and check time value that passed from button release. If passed time gets bigger than "double click interval" – activate "Single click" event and reset time value. If it gets clicked 2nd time – activate double click event and reset time value as well.

Hello,

Maybe try this library ? GitHub - marcobrianza/ClickButton: A simple button Arduino library to get short and long clicks, multiple clicks (double click, triple click etc.). Click-and-hold is also possible.

Perhaps you could add code to check for a double-clicks happening within a short period of time and set a boolean flag accordingly. Then use that flag as part of the close logic.

This compiles but is not tested. It uses an initial guess of a 350mS time between clicks to qualify:

#define CLOSE_READ_INTERVAL     50ul        //read close button every 50mS
#define MAX_DBL_CLICK_TIME      350ul       //350mS max time between double-clicks to qualify

#define reverse_pin 5
#define switch_pin 6
#define close_pin 2
#define open_pin 12
#define tiltup_pin 9
#define tiltdn_pin 10
#define m1_pin 7
#define m2_pin 8
#define tilttmr 1630
#define closetmr 2600

boolean 
    bCloseDouble = false,
    tiltuplock=false,
    closemrrlk=true;

void setup ()
{
    pinMode(reverse_pin,INPUT);
    pinMode(switch_pin,INPUT);
    pinMode(close_pin,INPUT);
    pinMode(open_pin,INPUT);
    //
    pinMode(tiltup_pin,OUTPUT);
    pinMode(tiltdn_pin,OUTPUT);
    pinMode(m1_pin,OUTPUT);
    pinMode(m2_pin,OUTPUT);
    //
    digitalWrite(tiltup_pin,LOW);
    digitalWrite(tiltdn_pin,LOW);
    digitalWrite(m1_pin,LOW);
    digitalWrite(m2_pin,LOW);
 }

void loop()
{
    if( !bCloseDouble )
        bCloseDouble = QualifyCloseDoubleClick();
    
    if( digitalRead(switch_pin) )
    {
        if( digitalRead(reverse_pin) && tiltuplock )
        {
            //Tilt down
            delay(300);
            if( digitalRead(reverse_pin) )
            {
                tiltuplock=false;
                digitalWrite( tiltdn_pin,HIGH );
                delay( tilttmr );
                digitalWrite( tiltdn_pin,LOW );
                
            }//if
            
        }//if
        
        if( !digitalRead(reverse_pin) && !tiltuplock )
        {
            //Tilt up
            tiltuplock=true;
            digitalWrite(tiltup_pin,HIGH);
            delay(1720);
            digitalWrite(tiltup_pin,LOW);
            
        }//if
        
    }//if
    else
    {
        if( digitalRead(open_pin) && bCloseDouble && !closemrrlk )
        {
            //Close mirror
            bCloseDouble = false;
            closemrrlk=true;
            digitalWrite(m1_pin,HIGH);
            delay(closetmr);
            digitalWrite(m1_pin,LOW);
            
        }//if
        
        if( !digitalRead(open_pin) && !bCloseDouble && digitalRead(close_pin) && closemrrlk )
        {
            //Open mirror
            closemrrlk=false;
            digitalWrite(m2_pin,HIGH);
            delay(closetmr);
            digitalWrite(m2_pin,LOW);
            
        }//if
        
    }//else
    
}//loop

//state names
#define PRESS_A     0
#define PRESS_B     1
//
bool QualifyCloseDoubleClick( void )
{
    static byte
        stateClose = PRESS_A,
        lastSwStat=HIGH;
    byte
        swStat;
    static unsigned long
        timeClose,
        timeSwRead = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( (timeNow - timeSwRead) < CLOSE_READ_INTERVAL )
        return false;

    timeSwRead = timeNow;

    swStat = digitalRead( close_pin );
    if( swStat != lastSwStat )
    {
        lastSwStat = swStat;
        if( swStat == LOW )
        {
            switch( stateClose )
            {
                case    PRESS_A:
                    timeClose = timeNow;
                    stateClose = PRESS_B;
                    
                    return false;
                    
                break;
            
                case    PRESS_B:
                    stateClose = PRESS_A;
                    
                    if( (timeNow - timeClose) <= MAX_DBL_CLICK_TIME )
                        return true;
                    else
                        return false;                    
                        
                break;
                
            }//switch
            
        }//if
        
    }//if
    
}//QualifyCloseDoubleClick

Blackfin:
Perhaps you could add code to check for a double-clicks happening within a short period of time and set a boolean flag accordingly. Then use that flag as part of the close logic.

This compiles but is not tested. It uses an initial guess of a 350mS time between clicks to qualify:

#define CLOSE_READ_INTERVAL     50ul        //read close button every 50mS

#define MAX_DBL_CLICK_TIME      350ul      //350mS max time between double-clicks to qualify

#define reverse_pin 5
#define switch_pin 6
#define close_pin 2
#define open_pin 12
#define tiltup_pin 9
#define tiltdn_pin 10
#define m1_pin 7
#define m2_pin 8
#define tilttmr 1630
#define closetmr 2600

boolean
    bCloseDouble = false,
    tiltuplock=false,
    closemrrlk=true;

void setup ()
{
    pinMode(reverse_pin,INPUT);
    pinMode(switch_pin,INPUT);
    pinMode(close_pin,INPUT);
    pinMode(open_pin,INPUT);
    //
    pinMode(tiltup_pin,OUTPUT);
    pinMode(tiltdn_pin,OUTPUT);
    pinMode(m1_pin,OUTPUT);
    pinMode(m2_pin,OUTPUT);
    //
    digitalWrite(tiltup_pin,LOW);
    digitalWrite(tiltdn_pin,LOW);
    digitalWrite(m1_pin,LOW);
    digitalWrite(m2_pin,LOW);
}

void loop()
{
    if( !bCloseDouble )
        bCloseDouble = QualifyCloseDoubleClick();
   
    if( digitalRead(switch_pin) )
    {
        if( digitalRead(reverse_pin) && tiltuplock )
        {
            //Tilt down
            delay(300);
            if( digitalRead(reverse_pin) )
            {
                tiltuplock=false;
                digitalWrite( tiltdn_pin,HIGH );
                delay( tilttmr );
                digitalWrite( tiltdn_pin,LOW );
               
            }//if
           
        }//if
       
        if( !digitalRead(reverse_pin) && !tiltuplock )
        {
            //Tilt up
            tiltuplock=true;
            digitalWrite(tiltup_pin,HIGH);
            delay(1720);
            digitalWrite(tiltup_pin,LOW);
           
        }//if
       
    }//if
    else
    {
        if( digitalRead(open_pin) && bCloseDouble && !closemrrlk )
        {
            //Close mirror
            bCloseDouble = false;
            closemrrlk=true;
            digitalWrite(m1_pin,HIGH);
            delay(closetmr);
            digitalWrite(m1_pin,LOW);
           
        }//if
       
        if( !digitalRead(open_pin) && !bCloseDouble && digitalRead(close_pin) && closemrrlk )
        {
            //Open mirror
            closemrrlk=false;
            digitalWrite(m2_pin,HIGH);
            delay(closetmr);
            digitalWrite(m2_pin,LOW);
           
        }//if
       
    }//else
   
}//loop

//state names
#define PRESS_A    0
#define PRESS_B    1
//
bool QualifyCloseDoubleClick( void )
{
    static byte
        stateClose = PRESS_A,
        lastSwStat=HIGH;
    byte
        swStat;
    static unsigned long
        timeClose,
        timeSwRead = 0;
    unsigned long
        timeNow;

timeNow = millis();
    if( (timeNow - timeSwRead) < CLOSE_READ_INTERVAL )
        return false;

timeSwRead = timeNow;

swStat = digitalRead( close_pin );
    if( swStat != lastSwStat )
    {
        lastSwStat = swStat;
        if( swStat == LOW )
        {
            switch( stateClose )
            {
                case    PRESS_A:
                    timeClose = timeNow;
                    stateClose = PRESS_B;
                   
                    return false;
                   
                break;
           
                case    PRESS_B:
                    stateClose = PRESS_A;
                   
                    if( (timeNow - timeClose) <= MAX_DBL_CLICK_TIME )
                        return true;
                    else
                        return false;                   
                       
                break;
               
            }//switch
           
        }//if
       
    }//if
   
}//QualifyCloseDoubleClick

Thx for the effort, didn't work but at least I have somewhere to start. Thx

Note that using a double click means that you can't act on a click straight away - you have to wait end see if the user is going to do a second click.

Computer UIs manage this by always making the double-click action an extension of the single-click action: single click selects an icon, the second click does something. But if you want single-click to do something quite different from double-click, you'll need a timeout.

And if you are going to that sort of trouble, you may as well handle long-clicks as well.

You know, if you have a system to catch long and short single and double clicks, it becomes possible to handle arbitrary morse code. Put clicks into a buffer, then when the timeout occurs examine the buffer to work out what the user wanted to do.

PaulMurrayCbr:
Note that using a double click means that you can't act on a click straight away - you have to wait end see if the user is going to do a second click.

Computer UIs manage this by always making the double-click action an extension of the single-click action: single click selects an icon, the second click does something. But if you want single-click to do something quite different from double-click, you'll need a timeout.

And if you are going to that sort of trouble, you may as well handle long-clicks as well.

You know, if you have a system to catch long and short single and double clicks, it becomes possible to handle arbitrary morse code. Put clicks into a buffer, then when the timeout occurs examine the buffer to work out what the user wanted to do.

What im looking to do I think is much simpler than that, the first click does nothing, the second click triggers the system.

With this code on my Mega, the double click works (I toggle the on-board LED). Not sure about the rest of the logic. I noticed you didn't use INPUT_PULLUP mode on your button inputs. I changed that on this code; YMMV.

#define CLOSE_READ_INTERVAL     50ul        //mS    read close button period
#define MAX_DBL_CLICK_TIME      500ul       //mS    max time between double-clicks to qualify

#define reverse_pin 5
#define switch_pin 6
#define close_pin 2
#define open_pin 12
#define tiltup_pin 9
#define tiltdn_pin 10
#define m1_pin 7
#define m2_pin 8
#define tilttmr 1630
#define closetmr 2600

#define pinLED  LED_BUILTIN

boolean
    bCloseDouble = false,
    tiltuplock=false,
    closemrrlk=true;

void setup ()
{
    Serial.begin(9600);
    
    pinMode(reverse_pin,INPUT_PULLUP);
    pinMode(switch_pin,INPUT_PULLUP);
    pinMode(close_pin,INPUT_PULLUP);
    pinMode(open_pin,INPUT_PULLUP);
    //
    pinMode(tiltup_pin,OUTPUT);
    pinMode(tiltdn_pin,OUTPUT);
    pinMode(m1_pin,OUTPUT);
    pinMode(m2_pin,OUTPUT);
    pinMode( pinLED, OUTPUT );
    //
    digitalWrite(tiltup_pin,LOW);
    digitalWrite(tiltdn_pin,LOW);
    digitalWrite(m1_pin,LOW);
    digitalWrite(m2_pin,LOW);
 }

void loop()
{
    if( digitalRead(switch_pin) )
    {
        if( digitalRead(reverse_pin) && tiltuplock )
        {
            //Tilt down
            delay(300);
            if( digitalRead(reverse_pin) )
            {
                tiltuplock=false;
                digitalWrite( tiltdn_pin,HIGH );
                delay( tilttmr );
                digitalWrite( tiltdn_pin,LOW );
               
            }//if
           
        }//if
       
        if( !digitalRead(reverse_pin) && !tiltuplock )
        {
            //Tilt up
            tiltuplock=true;
            digitalWrite(tiltup_pin,HIGH);
            delay(1720);
            digitalWrite(tiltup_pin,LOW);
           
        }//if
       
    }//if
    else
    {
        if( digitalRead(open_pin) && bCloseDouble && !closemrrlk )
        {
            //Close mirror
            bCloseDouble = false;
            closemrrlk=true;
            digitalWrite(m1_pin,HIGH);
            delay(closetmr);
            digitalWrite(m1_pin,LOW);
           
        }//if
       
        if( !digitalRead(open_pin) && !bCloseDouble && digitalRead(close_pin) && closemrrlk )
        {
            //Open mirror
            closemrrlk=false;
            digitalWrite(m2_pin,HIGH);
            delay(closetmr);
            digitalWrite(m2_pin,LOW);
           
        }//if
       
    }//else

    bCloseDouble = QualifyCloseDoubleClick();
   
}//loop

//state names
#define PRESS_A     0
#define PRESS_B     1
//
bool QualifyCloseDoubleClick( void )
{
    static bool
        bLEDState = false;
    static byte
        stateClose = PRESS_A,
        lastSwStat=HIGH;
    byte
        swStat;
    static unsigned long
        timeClose,
        timeSwRead = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( (timeNow - timeSwRead) < CLOSE_READ_INTERVAL )
        return false;

    timeSwRead = timeNow;

    swStat = digitalRead( close_pin );
    if( swStat != lastSwStat )
    {
        lastSwStat = swStat;
        if( swStat == LOW )
        {
            switch( stateClose )
            {
                case    PRESS_A:
                    timeClose = timeNow;
                    stateClose = PRESS_B;
                   
                    return false;
                   
                break;
           
                case    PRESS_B:
                    stateClose = PRESS_A;
                   
                    if( (timeNow - timeClose) <= MAX_DBL_CLICK_TIME )
                    {
                        bLEDState ^= true;
                        digitalWrite( pinLED, bLEDState?HIGH:LOW );
                        return true;
                    }
                    else
                        return false;                   
                       
                break;
               
            }//switch
           
        }//if
       
    }//if
   
}//QualifyCloseDoubleClick

Blackfin:
With this code on my Mega, the double click works (I toggle the on-board LED). Not sure about the rest of the logic. I noticed you didn't use INPUT_PULLUP mode on your button inputs. I changed that on this code; YMMV.

#define CLOSE_READ_INTERVAL     50ul        //mS    read close button period

#define MAX_DBL_CLICK_TIME      500ul      //mS    max time between double-clicks to qualify

#define reverse_pin 5
#define switch_pin 6
#define close_pin 2
#define open_pin 12
#define tiltup_pin 9
#define tiltdn_pin 10
#define m1_pin 7
#define m2_pin 8
#define tilttmr 1630
#define closetmr 2600

#define pinLED  LED_BUILTIN

boolean
    bCloseDouble = false,
    tiltuplock=false,
    closemrrlk=true;

void setup ()
{
    Serial.begin(9600);
   
    pinMode(reverse_pin,INPUT_PULLUP);
    pinMode(switch_pin,INPUT_PULLUP);
    pinMode(close_pin,INPUT_PULLUP);
    pinMode(open_pin,INPUT_PULLUP);
    //
    pinMode(tiltup_pin,OUTPUT);
    pinMode(tiltdn_pin,OUTPUT);
    pinMode(m1_pin,OUTPUT);
    pinMode(m2_pin,OUTPUT);
    pinMode( pinLED, OUTPUT );
    //
    digitalWrite(tiltup_pin,LOW);
    digitalWrite(tiltdn_pin,LOW);
    digitalWrite(m1_pin,LOW);
    digitalWrite(m2_pin,LOW);
}

void loop()
{
    if( digitalRead(switch_pin) )
    {
        if( digitalRead(reverse_pin) && tiltuplock )
        {
            //Tilt down
            delay(300);
            if( digitalRead(reverse_pin) )
            {
                tiltuplock=false;
                digitalWrite( tiltdn_pin,HIGH );
                delay( tilttmr );
                digitalWrite( tiltdn_pin,LOW );
             
            }//if
         
        }//if
     
        if( !digitalRead(reverse_pin) && !tiltuplock )
        {
            //Tilt up
            tiltuplock=true;
            digitalWrite(tiltup_pin,HIGH);
            delay(1720);
            digitalWrite(tiltup_pin,LOW);
         
        }//if
     
    }//if
    else
    {
        if( digitalRead(open_pin) && bCloseDouble && !closemrrlk )
        {
            //Close mirror
            bCloseDouble = false;
            closemrrlk=true;
            digitalWrite(m1_pin,HIGH);
            delay(closetmr);
            digitalWrite(m1_pin,LOW);
         
        }//if
     
        if( !digitalRead(open_pin) && !bCloseDouble && digitalRead(close_pin) && closemrrlk )
        {
            //Open mirror
            closemrrlk=false;
            digitalWrite(m2_pin,HIGH);
            delay(closetmr);
            digitalWrite(m2_pin,LOW);
         
        }//if
     
    }//else

bCloseDouble = QualifyCloseDoubleClick();
 
}//loop

//state names
#define PRESS_A    0
#define PRESS_B    1
//
bool QualifyCloseDoubleClick( void )
{
    static bool
        bLEDState = false;
    static byte
        stateClose = PRESS_A,
        lastSwStat=HIGH;
    byte
        swStat;
    static unsigned long
        timeClose,
        timeSwRead = 0;
    unsigned long
        timeNow;

timeNow = millis();
    if( (timeNow - timeSwRead) < CLOSE_READ_INTERVAL )
        return false;

timeSwRead = timeNow;

swStat = digitalRead( close_pin );
    if( swStat != lastSwStat )
    {
        lastSwStat = swStat;
        if( swStat == LOW )
        {
            switch( stateClose )
            {
                case    PRESS_A:
                    timeClose = timeNow;
                    stateClose = PRESS_B;
                 
                    return false;
                 
                break;
         
                case    PRESS_B:
                    stateClose = PRESS_A;
                 
                    if( (timeNow - timeClose) <= MAX_DBL_CLICK_TIME )
                    {
                        bLEDState ^= true;
                        digitalWrite( pinLED, bLEDState?HIGH:LOW );
                        return true;
                    }
                    else
                        return false;                 
                     
                break;
             
            }//switch
         
        }//if
     
    }//if
 
}//QualifyCloseDoubleClick

Not working on the UNO, after the code the mirrors no longer close or open. Im looking at the code to find out why.