CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

short press and long press tactile button

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hemnath



Joined: 03 Oct 2012
Posts: 227
Location: chennai

View user's profile Send private message

short press and long press tactile button
PostPosted: Mon Mar 09, 2020 2:47 am     Reply with quote

Hi,

I have a tactile switch. I want to use this button for multipurpose.

Short press which toggles a LED which is connected to PIN C5. A long press which displays the menu on the LCD display.

Any algorithm or logic, please.
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Mar 09, 2020 5:07 am     Reply with quote

Some options.

1) Use the 'search' option and previous posts. there are several.

2) Check the manual, Q&A section, for 'How do I wait only a specified time for a button press?'

3) Either PCMP or Mr. T posted a 'button.c' driver that might work for you.

Details you need to decide are what is a 'short' press, a 'long' press ? I'd think a maximum of 5 seconds for a 'timeout' or 'cancel button reading' might be a good start. A lot depends on the button quality, debounce, etc.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Mar 10, 2020 6:21 am     Reply with quote

Or you could try something like standard keyboard method where you recognise the difference between a sharp tap and a longer hold for auto-repeat.

There must be loads of examples out there.

Mike
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Mar 10, 2020 7:12 am     Reply with quote

The normal way is to decode 'key down', and 'key released' as two separate
events. Then measuring the time between these allows you to decide which
action to take.
As Mike says having an auto repeat when the time is longer than a specific
value is a common action.
A timer based keyboard scanner that decides a key is 'down' when it
is active for two successive scans, avoids bounce problems and gives
reliable contact detection. Then the same applied for 'release' gives the
ability to take different actions according to the count between the events.
hemnath



Joined: 03 Oct 2012
Posts: 227
Location: chennai

View user's profile Send private message

PostPosted: Mon Nov 09, 2020 5:54 am     Reply with quote

any sample code?
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Nov 09, 2020 6:18 am     Reply with quote

Use the 'search' option, use 'button' as the keyword. Somewhere will be the 'button.c' program.
I KNOW it works ! Have used it for 3-5 years on several projects.
Just copy and save a version, edit YOUR version as required for your needs.
I have a 'short', 'medium', long' version as I needed 3 distinct 'levels' from one switch when I ran out of pins.....
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Nov 09, 2020 6:58 am     Reply with quote

This is the button.c link:
http://www.ccsinfo.com/forum/viewtopic.php?t=23837
hemnath



Joined: 03 Oct 2012
Posts: 227
Location: chennai

View user's profile Send private message

PostPosted: Mon Nov 09, 2020 9:38 pm     Reply with quote

Code:
#include <18F2620.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

// These are the "Bvar" variables required by Button.c.
int8 A4 = 0;   // For the button on pin A4
int8 B0 = 0;   // For the button on pin B0

// Global "button pressed" variables.
int8 A4_pressed = FALSE;
int8 B0_pressed = FALSE;

#include <Button.c>

// This gives an RTCC interrupt rate of 100.16 Hz
// (approx. 10 ms) to sample and debounce the buttons.
#define RTCC_PRELOAD (256 - 39)

// The buttons are read in this Timer0 (RTCC) isr.
#int_rtcc
void rtcc_isr(void)
{
set_rtcc(RTCC_PRELOAD); // Reload the Timer.

if(button(PIN_B0, 0, 50, 10, B0, 1))   
   B0_pressed = TRUE;
 
if(button(PIN_A4, 0, 50, 10, A4, 1))   
   A4_pressed = TRUE;
}

//================================
void main()
{
printf("\n\rStart: ");

// Setup the RTCC for a 10 ms interrupt rate.
setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
set_rtcc(RTCC_PRELOAD);

enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);


while(1)
  {
   if(A4_pressed == TRUE)
     {
      A4_pressed = FALSE;
      printf("A");
     }
   
   if(B0_pressed == TRUE)
     {
      B0_pressed = FALSE;
      printf("B");
     }
  }

}


My code is similar to this. Using button.c and interrupt, i can scan the button. But how can i modify the code for short press and long press for the same button ? Please help.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Nov 10, 2020 9:11 am     Reply with quote

A quick and dirty way to try can be that when the button is pressed, stay in a while loop that has, for instance, a 1ms delay and an up-counter that will count up to 1000.

When the loop exits after 1 second (1000x 1 ms) check if the button is still pressed. If still pressed, run Function1() otherwise run Function2().

Not ideal but a good way of testing
Code:

// Check if button is pressed
if( input( PIN_B0 ) == TRUE )
{
    Counter = 0;

    // Start a 1 second delay
    while( Counter < 1000 )
   {
      delay_ms( 1 );
      Counter ++;
   }
   
   // 1 second delay expired, check if button is still pressed
   if( input( PIN_B0 ) == TRUE )
   {
      // Button is still pressed, run function Function1();
   }
   else
   {
      // Button is not pressed, run function Function2();
   }
}

void Function1( void )
{
   // Code here
}

void Function2( void )
{
   // Code here
}

Haven't tested this so play around with it but you get the idea. I use interrupts for external buttons.

Good luck.

Ben
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Nov 10, 2020 10:21 am     Reply with quote

I'm pretty sure CCS supplies a 'timed pin' in the FAQ section of the manual. I know there's a 'timed RS232' chunk of code.....
Similar to what Ben posted...stays in a loop until EITHER 'something ' happens OR a 'timeout' occours.

Jay
jeremiah



Joined: 20 Jul 2010
Posts: 1314

View user's profile Send private message

PostPosted: Tue Nov 10, 2020 11:38 am     Reply with quote

My recommendation would be to modify your ISR to handle counting and let your main code look at the count and decide if it was a short or long press based on how high the count is:

Code:


static unsigned int8 B0_count = 0;
static unsigned int8 A4_count = 0;

// The buttons are read in this Timer0 (RTCC) isr.
#int_rtcc
void rtcc_isr(void)
{
   set_rtcc(RTCC_PRELOAD); // Reload the Timer.

   if(input_state(PIN_B0)) { 
      if(B0_count < 255){
         B0_count++;
      }
   }else{
      // if the input is low, we reset the count
      B0_count = 0;
   }
 
   if(input_state(PIN_A4))   { 
      if(A4_count < 255){
         A4_count++;
      }
   }else{
      // if the input is low, we reset the count
      A4_count = 0;
   }
}


Then in your main you can see if the count is at least some value (1 or higher, up to you) to say that it is pressed, then if it is less than some value (say 100 for one second) it is a short press. Otherwise if it is higher, it is a long press.

You could even make an enumeration and function to categorize the button presses:

Code:

typedef enum {BTTN_NOT_PRESSED, BTTN_SHORT_PRESS, BTTN_LONG_PRESS} button_press_t;

button_press_t check_press(unsigned int8 press_count){
   if(press_count > 100){
      return BTTN_LONG_PRESS;
   }else if(press_count > 5){
      return BTTN_SHORT_PRESS;
   }else{
      return BTTN_NOT_PRESSED;
   }
}


And that can be called on B0_count and A4_count in your main to see what type of press you currently have.
hemnath



Joined: 03 Oct 2012
Posts: 227
Location: chennai

View user's profile Send private message

PostPosted: Thu Nov 12, 2020 10:21 pm     Reply with quote

Modified the code. But it is not working. Please check

Code:
#include <18F2620.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)

#define RS   PIN_A1
#define EN   PIN_A2

#define    UP      PIN_A5   
#define   ENTER   PIN_C2
#define   DOWN   PIN_C0

void lcd_init();
void lcd_cmd(unsigned char c);
void lcd_data(unsigned char z);

#include "lcd.c"

static unsigned int8 B0_count = 0;
static unsigned int8 A4_count = 0;

// This gives an RTCC interrupt rate of 100.16 Hz
// (approx. 10 ms) to sample and debounce the buttons.
#define RTCC_PRELOAD (256 - 39)

// The buttons are read in this Timer0 (RTCC) isr.
#int_rtcc
void rtcc_isr(void)
{
   set_rtcc(RTCC_PRELOAD); // Reload the Timer.
   
   if(input_state(UP))
   {
      if(B0_count < 255)
      {
         B0_count++;
      }
   }
   else
   {
      // if the input is low, we reset the count
      B0_count = 0;
   }
   
   if(input_state(DOWN))   
   {
      if(A4_count < 255)
      {
         A4_count++;
      }
   }
   else
   {
      // if the input is low, we reset the count
      A4_count = 0;
   }
}

//================================
void main()
{
   // Setup the RTCC for a 10 ms interrupt rate.
   setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
   set_rtcc(RTCC_PRELOAD);
   
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);
   delay_ms(100);

   lcd_init();
   lcd_cmd(0x80);
   printf(lcd_data, "Welcome");
   delay_ms(1000);
   
   lcd_cmd(0x01);

   while(1)
   {
      if(B0_count > 100)
      {
         lcd_cmd(0x80);
         printf(lcd_data, "Long    ");
      }
      else if(B0_count > 5)
      {
         lcd_cmd(0x80);
         printf(lcd_data, "Short   ");
      }
      else
      {
         lcd_cmd(0x80);
         printf(lcd_data, "No Press");
      }
      delay_ms(100);
   }
}


PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 13, 2020 1:14 am     Reply with quote

Hemnath wrote:
Modified the code. But it is not working.

How are your switches connected ? I think it's like this:
Code:

           +5v
            |
            <
            > 4.7K       
            <         ___  Switch
To          |        _|_|_
PIC -----------------o   o------
pin A5                         |             
                              --- GND
                               -

The idle state is a logic "1" for this design. A button press gives a logic "0".
jeremiah



Joined: 20 Jul 2010
Posts: 1314

View user's profile Send private message

PostPosted: Fri Nov 13, 2020 8:50 am     Reply with quote

Yeah, I only guessed which way the buttons were oriented but figured the OP could adjust it if they were reversed. Definitely could be active low instead.

If they are active low, then

Code:
if(input_state(UP))


becomes:

Code:
if(0 == input_state(UP))


and similar for the other buttons
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group