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

Recording time for which the button is pressed

Hi,

I want to count the time in seconds for which I press the button and stop the counter when the button is released. How should I detect the long press of button and determine the time for which it was pressed ? I have a nrf 51 development board. Any suggestions would be appreciated.

  • Here's a way to do it that uses the app_timer and the RTC1. This is for SDK 10. This is the method I use now. (I propose a second method below which I used yesterday, funny thing).

    ###button_handler.c

    #define BUTTON_DETECTION_DELAY          APP_TIMER_TICKS(50, APP_TIMER_PRESCALER)
    
    static uint32_t button_tick = 0;
    static uint32_t button_tick_release = 0;
    static uint32_t total_ticks = 0;
    
    APP_TIMER_DEF(m_button_tick_timer);
    
    static void button_handler(uint8_t button, uint8_t action)
    {
    	uint32_t err_code;
    	switch(action) {
    	case APP_BUTTON_PUSH:
    		app_timer_start(m_button_tick_timer, 65535, NULL);
    		err_code = app_timer_cnt_get(&button_tick);
    		APP_ERROR_CHECK(err_code);
    		break;
    	case APP_BUTTON_RELEASE:
    		err_code = app_timer_cnt_get(&button_tick_release);
    		APP_ERROR_CHECK(err_code);
    		
    		err_code = app_timer_stop(m_button_tick_timer);
    		APP_ERROR_CHECK(err_code);
    		
    		err_code = app_timer_cnt_diff_compute(button_tick_release, button_tick, &total_ticks);
    		APP_ERROR_CHECK(err_code);
    		SEGGER_RTT_printf(0, "total ticks was: %d\n", total_ticks);
    	break;
    	}
    }
    
    static void timer_handler(void * p_context)
    {
    	UNUSED_PARAMETER(p_context);
    	SEGGER_RTT_printf(0, "timer timed out");
    }
    
    void buttons_init(void)
    {
    
    	// Note: Array must be static because a pointer to it will be saved in the Button handler
    	//       module.
    	uint32_t err_code = 0;
    
    	static app_button_cfg_t buttons[] = {
    		{BUTTON_PIN, APP_BUTTON_ACTIVE_LOW, NRF_GPIO_PIN_PULLUP, button_handler}
    	};
    	err_code = app_button_init((app_button_cfg_t *)buttons,
    	                           sizeof(buttons) / sizeof(buttons[0]),
    	                           BUTTON_DETECTION_DELAY);
    	APP_ERROR_CHECK(err_code);
    	err_code = app_button_enable();
    	APP_ERROR_CHECK(err_code);
    
    	err_code = app_timer_create(&m_button_tick_timer, APP_TIMER_MODE_REPEATED, timer_handler);
    														 
    }
    

    ###way 2 Here's a way to do it if you don't care about it blocking. It isn't a good way.

    ###button_handler.c

    #define BUTTON_DETECTION_DELAY          APP_TIMER_TICKS(100, APP_TIMER_PRESCALER)
    
    static volatile uint16_t button_tick = 0;
    static volatile uint16_t button_min_hand = 0;
    static volatile bool button_pressed = false;
    
    void buttons_init(void)
    {
    	uint32_t err_code = 0;
    	static app_button_cfg_t buttons[] = {
    		{BUTTON_PIN, APP_BUTTON_ACTIVE_LOW, NRF_GPIO_PIN_PULLUP, button_handler}
    	};
    	err_code = app_button_init((app_button_cfg_t *)buttons,
    	                           sizeof(buttons) / sizeof(buttons[0]),
    	                           BUTTON_DETECTION_DELAY);
    	APP_ERROR_CHECK(err_code);
    	err_code = app_button_enable();
    	APP_ERROR_CHECK(err_code);
    
    }
    
    static void button_handler(uint8_t button, uint8_t action)
    {
    
    	switch(action) {
    	case APP_BUTTON_PUSH:
    		button_pressed = true;
    		break;
    	case APP_BUTTON_RELEASE:
    		button_pressed = false;
    		//SEGGER_RTT_printf(0, "button_ticks are: %d, button_min_hand is %d\n", button_tick, button_min_hand);
    		button_tick = 0;
    		button_min_hand = 0;
    		break;
    	}
    }
    
    void button_tick_increment(void)
    {
       	if (button_pressed == true) {
    		if (button_tick >= 65534) {
    			button_min_hand++;
    			button_tick = 0;
    		}
    		button_tick++;
    	}
    }
    

    ###main.c

    #include "button_handler.h"
    int main()
    {
      buttons_init();
      for(;;) {
        button_tick_increment();
      }
    }
    

    Effectively this lets me figure out how long the button has been held down by multiplying the "button_min_hand" by button_tick. As I said, there's probably a better way; but this works for my purposes (turning off the device if the button is held down for x seconds; or whatever).

  • Thanks for the response. It is a great reference point to start with. When I press the button on the board, it doesn't get detected. Any particular reason for that ?

  • I would recommend using a rtc based timer to count the ticks. If you follow this approach you will be stuck in the loop for counting the ticks. I suppose you would want your MCU to do other tasks apart from button press time.

  • Yes ofcourse using RTC would be the best method

  • @soumil I just updated the answer with an RTC based answer. I've also tested that code and it works on the PCA10028 board.

Related