This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Difficulty implementing switch double-click.

Hello 

I'm trying to implement the click and double click and long click of a button in sdk v17.

Click and long click work fine.  But double-click doesn't work.

Code for entering button.

int click_count; //check click or double click
unsigned long timePress = 0;
unsigned long timePressLimit = 0;


static uint32_t pressed_time, released_time, pressed_duration = 0;
static bool pressed_cnt= false;

static uint32_t app_button_duration(void) //press time
{
  pressed_duration = (released_time - pressed_time)*2; //ms
  return pressed_duration;
}

static void app_button_init_time_variable(void)
{
  pressed_duration = 0; //press time
}


static void app_button_event_generator(void) //button press time
{
  ret_code_t err_code;

  app_button_init_time_variable();
}
 

static void app_button_event_handler(uint8_t pin_no, uint8_t button_action)
{
    ret_code_t err_code;
    static uint32_t first_pressed;
    static uint32_t long_pressed;

    switch (pin_no)
    {
      case BUTTON_1: 
        switch (button_action)
        {
          case APP_BUTTON_PUSH:
          {
            NRF_LOG_INFO("Button pressed...");
            printf("Button pressed");

            //get pressed time
            pressed_time = app_timer_cnt_get()*1000/32768;//milli-sec
            NRF_LOG_INFO("pressed_time: %d", (int)pressed_time);
            printf("pressed_time: %d\n", (int)pressed_time);
            pressed_cnt = true;

            PowerOff_timers_start(); //press timer count

            if(click_count == 0) //first click
            {
              printf("One click\n");
              timePress = app_timer_cnt_get()*1000/32768;
              timePressLimit = timePress + 500; //time press + 0.5sec
              click_count = 1;
            }

            else if(click_count == 1 && app_timer_cnt_get()*1000/32768 < timePressLimit) // double click, click time < timePressLimit
            {
              printf("Double Click!\n");
              
              //set variables back to 0
              timePress = 0;
              timePressLimit = 0;
              click_count = 0;
            }

            if(click_count == 1 && timePressLimit != 0 && app_timer_cnt_get()*1000/32768 > timePressLimit) //second click but time's up
            {
              printf("One click\n");
          
              //set variables back to 0
              timePress = 0;
              timePressLimit = 0;
              click_count = 0;
            }

          } break;

           case APP_BUTTON_RELEASE:
           {  
              NRF_LOG_INFO("Button releaed...");

              if (pressed_cnt)
              {
                released_time = app_timer_cnt_get()*1000/32768; //milli-sec
                NRF_LOG_INFO("released_time: %d", (int)released_time);
                printf("released_time: %d\n", (int)released_time);
              }

              pressed_cnt = false;

              PowerOff_timers_stop();
                
           } break;
        } 
      break;

      default:
         APP_ERROR_HANDLER(pin_no);
      break;
    }

    if(app_button_duration())
    {
      app_button_event_generator();
    }

    app_button_init_time_variable(); 
}


static void app_buttons_init(void)
{
  uint32_t err_code;

  static const app_button_cfg_t app_buttons[BUTTONS_NUMBER] =
  {
    {BUTTON_1, false, BUTTON_PULL, app_button_event_handler},
  };

  err_code = app_button_init((app_button_cfg_t *)app_buttons,
                                       BUTTONS_NUMBER,        // 1
                                       APP_TIMER_TICKS(50)); //debounce
  APP_ERROR_CHECK(err_code);
}

But there are two problems with this code.
1. Double-click will stop the board. (A single click or long push seems fine.)

2. When I click a button, I must be able to determine whether it is a single click or a double click. However, this code also executes a single click code when double-click.
(There should be time to wait for the next button after pressing the button to determine if there is a double click)

When debugging, double click to print the following error in the terminal.

<info> app: 13
<info> app: 14
<info> app: 12
<info> app: 12
<info> app: 12
<info> app: 13
<info> app: 14
<info> app: 12
<info> app: 12
<info> app: 12
<info> app: 13
<info> app: 14
<info> app: 12
<info> app: 12
<info> app: 12
<info> app: 13
<info> app: 14
<info> app: 12
<info> app: 12
<info> app: 12
<info> app: 13
<info> app: 14
<info> app: 12
<info> app: 12
<info> app: 12
<info> app: Button pressed...
<info> app: pressed_time: 8572
<info> app: Button releaed...
<info> app: released_time: 8598
<info> app: 11
<info> app: 9
<info> app: 10
<info> app: 10
<info> app: 12
<info> app: 11
<info> app: 9
Logs dropped (1)
<info> app: 10
Logs dropped (1)
<info> app: 10
Logs dropped (1)
<info> app: 12
Logs dropped (1)
<info> app: 11
Logs dropped (1)
<info> app: 9
Logs dropped (1)
<info> app: 10
Logs dropped (1)
<info> app: 10
Logs dropped (1)
<info> app: 12
Logs dropped (1)
<info> app: 11

Can I know the cause of this error and what I can refer to about double-click?

Thank you.
  • Hi 

    I believe the way to handle this is to start a timer on the first click, and then wait for either the timer to expire or another click to occur. 

    If the timer expires you count it as a single click, and if another click occurs you count it as a double click. 

    Then after that you reset everything and go back to waiting for a click to happen. 

    I don't think you need to add code waiting for the next click after the time has expired.

    I have been able to run your code and see it in action, but I don't have the implementation of the PowerOff_timers_start() and PowerOff_timers_stop() functions. Are you able to share those?

    Best regards
    Torbjørn

  • Hi, ovrebekk.

    Thank you for helping me.
    I've implemented the Button Long Press function before.

    This function was created by applying a timer. Should I apply a timer similar to this for double-click?

    APP_TIMER_DEF(m_PowerOff_timer_id); //button Long press time, repeate timer
    
    static void PowerOff_timer_handler(void * p_context)
    {
      press_time++;
      printf("COUNT : %d\n", press_time);
    
      if(press_time == 2) //press 2sec, Power Off
      {
        printf("Power Off!\n");
        //pwm_change_frequency(1500); 
        //do_play_buzzer();
        //nrf_gpio_pin_clear(POWER_SW); //LOW : power off
      }
    }
    
    
    /**@brief Function for the Timer initialization.
     *
     * @details Initializes the timer module. This creates and starts application timers.
     */
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        // Initialize timer module.
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
       //Create Power off Time timers/
        err_code = app_timer_create(&m_PowerOff_timer_id,
                                    APP_TIMER_MODE_REPEATED,
                                    PowerOff_timer_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void PowerOff_timers_start() //When push button
    {
      ret_code_t err_code;
    
      err_code = app_timer_start(m_PowerOff_timer_id, APP_TIMER_TICKS(1000), NULL); //count 1sec
      APP_ERROR_CHECK(err_code);
    }
    
    
    static void PowerOff_timers_stop() //When release button
    {
        ret_code_t err_code;
    
        //printf("No Power Off\n");
        press_time = 0; //count reset
    
        err_code = app_timer_stop(m_PowerOff_timer_id); 
        APP_ERROR_CHECK(err_code); 
    }

    Thank you.

  • I tried to implement double-click using a timer.  But it stops working when I double click. (The Bluetooth works without stopping.)

    The timer starts when I press the button. And I tried to stop the timer by double click or after a certain time.

    APP_TIMER_DEF(m_DoubleClick_timer_id); //button double click time, repeate timer
    
    static void DoubleClick_timer_handler(void * p_context)
    {
      press_time2++; //timer count
      printf("Click : %d\n", click_count);
      printf("COUNT : %d\n", press_time2);
    
      if(click_count >= 2) //double click
      {
        printf("Double Click\n");
        click_count = 0;
        press_time2 = 0; //count reset
    
        DoubleClick_timers_stop(); 
      }
    
      else if(press_time2 >= 2) //after click 0.5sec, no double click
      {
        printf("One Click\n");
        click_count = 0;
        press_time2 = 0; //count reset
    
        DoubleClick_timers_stop(); 
      }
    }
    
    
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        // Initialize timer module.
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
       //Create DOuble Click Time timers/
        err_code = app_timer_create(&m_DoubleClick_timer_id,
                                    APP_TIMER_MODE_REPEATED,
                                    DoubleClick_timer_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    static void DoubleClick_timers_start()
    {
      ret_code_t err_code;
    
      err_code = app_timer_start(m_DoubleClick_timer_id, APP_TIMER_TICKS(250), NULL); 
      APP_ERROR_CHECK(err_code);
      //printf("Wait next click\n");
    }
    
    
    static void DoubleClick_timers_stop() //Stop Timer
    {
        ret_code_t err_code;
    
        err_code = app_timer_stop(m_DoubleClick_timer_id); 
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void app_button_event_handler(uint8_t pin_no, uint8_t button_action)
    {
        ret_code_t err_code;
    
        switch (pin_no)
        {
          case BUTTON_1: 
            switch (button_action)
            {
              case APP_BUTTON_PUSH:
              {
                click_state = 1;
                click_count++;     
                
                if(click_count == 1) //first click
                {
                  DoubleClick_timers_start();
                }  
            } break;

    It seems to stop at timer_stop() after double click.  Is this problem related to the timer?

    Thank you.

  • Hi

    Can you try the attached method to detect double click below?

    I tried it myself, and it seems to work fine, while requiring relatively little code:

    int click_count; //check click or double click
    bool buttonTimeout = false;
    
    
    static void button_timer_timeout(void *p)
    {
        NRF_LOG_INFO("Timeout");
        buttonTimeout = true;
        if(click_count == 1)
        {
            NRF_LOG_INFO("Single click detected");
        }
        click_count = 0;
    }
    
    
    static void app_button_event_handler(uint8_t pin_no, uint8_t button_action)
    {
        ret_code_t err_code;
    
        switch (pin_no)
        {
            case BUTTON_1: 
                switch (button_action)
                {
                    case APP_BUTTON_PUSH:
                        if(click_count == 0) //first click
                        {
                            buttonTimeout = false;
                            app_timer_start(m_button_click_timer, APP_TIMER_TICKS(400), 0);
                        }
    
                        click_count++;
                        break;
    
                    case APP_BUTTON_RELEASE:
                        if(click_count == 2 && !buttonTimeout)
                        {
                            app_timer_stop(m_button_click_timer);
                            click_count = 0;
                            NRF_LOG_INFO("Double click detected");
                        }
                        break;
                } 
                break;
    
            default:
                APP_ERROR_HANDLER(pin_no);
                break;
        }
    }
    

    Currently the double click timeout is set to 400ms, but you can change that in the call to app_timer_start. 

    Best regards
    Torbjørn

  • Hellon, ovrebekk.
    I'm sorry for the late reply.

    I succeeded with the method you told me.
    But sometimes double-click doesn't work, so I'll try a little more.

    Thank you!

Related