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

Multi-Event Switch Actions

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

Multi-Event Switch Actions
PostPosted: Wed Mar 09, 2005 3:33 pm     Reply with quote

Here is some code that I wrote for another poster to do single click, dbl_click, multi-key presses. It might be useful to someone else.

A suitable LCD driver can be found here
http://www.ccsinfo.com/forum/viewtopic.php?t=20182
Code:

/*****************************************************************************/
/*                                                                           */
/*         Multi-Event Switch Action for Microchip Microcontrollers          */
/*                                                                           */
/* This program was designed to run on the PICDEM2 Plus demo board from      */
/* Microchip.                                                                */
/*                                                                           */
/* Usage:                                                                    */
/*         S3 - Is Switch 2                                                  */
/*         S2 - Is Switch 1                                                  */
/*                                                                           */
/* This code was designed for a clock speed of 10MHz                         */
/* The target device was a PIC18F452.                                        */
/*****************************************************************************/
#include <18F452.h>
// Note to check timer2 setup if you change this to make sure it ints every ms
#define clockspeed 10000000
#use delay(clock=clockspeed)
#fuses HS, NOWDT, PUT, NOLVP

#include "PICDEMLCD.C"

#define CLICK_TIME 250       // Maximum time to consider a press/release a click
#define DBL_CLICK_TIME 500   // Time to wait for a dbl_click in ms
#define SWITCH_READ_TIME 30  // Interval to read the switches in ms

// Search for TO ADD MORE SWITCHES to find out where the code needs to be changed
#define NUM_SWITCHES 2  // Good for up to 8 switches without
                        // having to modify the variable types

// Different types of click events
enum SWITCH_STATES
{
  SWITCH_IDLE,
  SWITCH_DOWN,
  SWITCH_HELD,
  SINGLE_CLICK,
  DOUBLE_CLICK
};

// Our system timer
int8 Miliseconds;

// How often we read the switch inputs
int8 Read_Switch_Timer = 0;

// Signal to read the switches
int1 Read_Switch_Flag = FALSE;

// Timeout value or in this case the double click time
int16 Click_Timer[NUM_SWITCHES];

enum SWITCH_STATES Switch_State[NUM_SWITCHES];

// Timer 2 is our system tick
#int_timer2
void timer2_isr(void)
{
  if (Miliseconds < 0xFF)
    Miliseconds++;
}

// Handles what happens when we release a switch
void Switch_Released(int8 number)
{
  // Make sure this is a valid switch
  if (number < NUM_SWITCHES)
  {
    switch (Switch_State[number])
    {
      case SWITCH_DOWN:
        // Set the timer to the maximum time between a press and release to
        // consider this a single click
        Click_Timer[number] = CLICK_TIME;
        Switch_State[number] = SINGLE_CLICK;
        break;
      case SWITCH_HELD:
        // Just set the timer to a small number so that it will fire as soon
        // as we release the switch
        Click_Timer[number] = 1;
        // Don't change the state here, the timers will take care of it
        break;
      case SINGLE_CLICK:
        // Set the timer for the maximum time we will wait for a double click
        Click_Timer[number] = DBL_CLICK_TIME;
        Switch_State[number] = DOUBLE_CLICK;
        break;
      case DOUBLE_CLICK:
        // The user is just clicking away at the button.  We won't really do
        // until he stops or we could cancel the operation by setting the state
        // to idle and the timer to 0
        Click_Timer[number] = DBL_CLICK_TIME;
        Switch_State[number] = DOUBLE_CLICK;
        break;
      default:
        Click_Timer[number] = 0;
        Switch_State[number] = SWITCH_IDLE;
        break;
    }
  }
}

// Handles what happens when we press a switch
void Switch_Pressed(int8 number)
{
  // Make sure this is a valid switch
  if (number < NUM_SWITCHES)
  {
    // Set the state to down only if we haven't just processed a click
    if (Switch_State[number] == SWITCH_IDLE)
      Switch_State[number] = SWITCH_DOWN;
    Click_Timer[number] = DBL_CLICK_TIME;
  }
}

// Handles debouncing of the switches
void Switch_Read_Value(void)
{
  static int8 last_read = 0xFF;
  static int8 last_state = 0xFF;
  static int8 debounce_count;
  int8 result = 0xFF;
  int8 i;
  int8 changed;

  // TO ADD MORE SWITCHES you need to put them into result

  // Read the current result
  if (!input(PIN_A4))
    bit_clear(result,0);

  if (!input(PIN_B0))
    bit_clear(result,1);

  // See if it changed
  if (result != last_read)
  {
    // It did so debounce it
    debounce_count = 5;
    last_read = result;
  }
  // We are debouncing
  else if (debounce_count)
  {
    debounce_count--;
    // Done debouncing
    if (debounce_count == 0)
    {
      // See if the state of the switch has changed
      changed = (result ^ last_state);
      // Determine what type of event occurred
      for(i=0;i<8;i++)
      {
        if (bit_test(changed,i))
        {
          if (bit_test(result,i))
            Switch_Released(i);
          else
            Switch_Pressed(i);
        }
        // Save the current state
        last_state = result;
      }
    }
  }
}

// What we do if a switch was pressed longer than the click time
void Switch_Pressed_Event(int8 number)
{
  // TO ADD MORE SWITCHES you need to add the cases
  switch(number)
  {
    case 0:
      // Light an LED on RB3 of the picdem2 plus board
      output_high(PIN_B3);
      printf(lcd_putc,"\fSW1 Pressed");
      break;
   case 1:
      // Light an LED on RB2 of the picdem2 plus board
      output_high(PIN_B2);
      printf(lcd_putc,"\fSW2 Pressed");
     break;
   default:
     break;
  }
}

// What we do if a switch was pressed and held longer than the click time
// and then released
void Switch_Release_Event(int8 number)
{
  // TO ADD MORE SWITCHES you need to add the cases
  switch(number)
  {
    case 0:
      // Turn off the LED on RB3 of the picdem2 plus board
      output_low(PIN_B3);
      printf(lcd_putc,"\fSW1 Released");
      break;
   case 1:
      // Turn off the LED on RB2 of the picdem2 plus board
      output_low(PIN_B2);
      printf(lcd_putc,"\fSW2 Released");
     break;
   default:
     break;
  }
}

// What we do on a single click
void Single_Click_Event(int8 number)
{
  // TO ADD MORE SWITCHES you need to add the cases
  switch(number)
  {
    case 0:
      // Light an LED on RB3 of the picdem2 plus board
      output_high(PIN_B3);
      if (Switch_State[1] == SWITCH_HELD)
        printf(lcd_putc,"\fSW1 Click\nWhile SW2 Held");
      else
        printf(lcd_putc,"\fSW1 Click");
      break;
   case 1:
      // Light an LED on RB2 of the picdem2 plus board
      output_high(PIN_B2);
      if (Switch_State[0] == SWITCH_HELD)
        printf(lcd_putc,"\fSW2 Click\nWhile SW1 Held");
      else
        printf(lcd_putc,"\fSW2 Click");
     break;
   default:
     break;
  }
}

// What we do for a dbl_click
void Double_Click_Event(int8 number)
{
  // TO ADD MORE SWITCHES you need to add the cases
  switch(number)
  {
    case 0:
      // Turn off the LED on RB3 of the picdem2 plus board
      output_low(PIN_B3);
      if (Switch_State[1] == SWITCH_HELD)
        printf(lcd_putc,"\fSW1 Dbl_Click\nWhile SW2 Held");
      else
        printf(lcd_putc,"\fSW1 Dbl_Click");
      break;
   case 1:
      // Turn off the LED on RB2 of the picdem2 plus board
      output_low(PIN_B2);
      if (Switch_State[0] == SWITCH_HELD)
        printf(lcd_putc,"\fSW2 Dbl_Click\nWhile SW1 Held");
      else
        printf(lcd_putc,"\fSW2 Dbl_Click");
     break;
   default:
     break;
  }
}

// Handles all our switch timers
void Switch_Timers(void)
{
  int8 i;

  if (Read_Switch_Timer == 0)
    Read_Switch_Timer--;
  else
    Read_Switch_Flag = TRUE;

  for(i=0;i<NUM_SWITCHES;i++)
  {
    if (Click_Timer[i])
    {
      Click_Timer[i]--;
      if (Click_Timer[i] == 0)
      {
        switch (Switch_State[i])
        {
          case SWITCH_DOWN:
            Switch_Pressed_Event(i);
            Switch_State[i] = SWITCH_HELD;
            break;
          case SWITCH_HELD:
            Switch_Release_Event(i);
            Switch_State[i] = SWITCH_IDLE;
            break;
          case SINGLE_CLICK:
            Single_Click_Event(i);
            Switch_State[i] = SWITCH_IDLE;
            break;
          case DOUBLE_CLICK:
            Double_Click_Event(i);
            Switch_State[i] = SWITCH_IDLE;
            break;
          default:
            Switch_State[i] = SWITCH_IDLE;
            break;
        }
      }
    }
  }
}

// Handles all our switch tasks
void Switch_Tasks(void)
{
  if (Read_Switch_Flag)
  {
    Switch_Read_Value();
    Read_Switch_Timer = SWITCH_READ_TIME;
    Read_Switch_Flag = FALSE;
  }
}

// System counter
void System_Tick(void)
{
  while (Miliseconds)
  {
    Switch_Timers();
    Miliseconds--;
  }
}

// Our main loop
void main (void)
{
  int8 i;

  // Initialize all of the timers and states
  for(i=0;i<NUM_SWITCHES;i++)
  {
    Click_Timer[i] = 0;
    Switch_State[i] = SWITCH_IDLE;
  }
  // Setup timer2 to int every 1ms
  // Note this is good for a clock between 80K - 20MHz
  // Although some frequencies that do not divide equally
  // by 80K will be slightly off.  You might want to verify this
  setup_timer_2(T2_DIV_BY_4,(clockspeed/80000),5);
  enable_interrupts(INT_TIMER2);
  enable_interrupts(GLOBAL);
  lcd_init();
  printf(lcd_putc,"PICDEM Switch\nEvent Test");
  // Start counting now
  Miliseconds = 0;

  while(1)
  {
    System_Tick();
    Switch_Tasks();
  }
}

future



Joined: 14 May 2004
Posts: 321

View user's profile Send private message

PostPosted: Tue Jun 06, 2006 9:36 pm     Reply with quote

Can you give me a point on where to add an auto-repeat function to this code?

I've been analysing the routines but I dont fully understand the internals yet.

Thank you.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu Jun 08, 2006 5:02 pm     Reply with quote

Do you just want an auto repeat function or do you want all the other events (pressed, released, click, dblclick)?
future



Joined: 14 May 2004
Posts: 321

View user's profile Send private message

PostPosted: Thu Jun 08, 2006 8:11 pm     Reply with quote

Can I have all events?? Very Happy

I have been playing with the code, got auto repeat for the single click event working and some other tweaks to deal better with double + single click sequences.

Maybe it isn't the most elegant solution but it seems to work.

Do you have improvements made to this routines already?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Fri Jun 09, 2006 6:24 am     Reply with quote

Nope. I wrote this just for another user.

http://www.ccsinfo.com/forum/viewtopic.php?t=22108&postdays=0&postorder=asc&start=0

I do not use it in any of my products. Of course you could have all the function events. Obviously it is more difficult to have them all and if they were not needed then things would be much easier. It sounds like you are making progress so I'll let you play around with it.
yangzy



Joined: 11 Oct 2007
Posts: 1

View user's profile Send private message

PostPosted: Thu Oct 11, 2007 11:20 pm     Reply with quote

hi Mark,

I found a bug in your code:

// Handles all our switch timers
void Switch_Timers(void)
{
int8 i;

if (Read_Switch_Timer == 0)
Read_Switch_Timer--;
else
Read_Switch_Flag = TRUE;

.....
.....

}


It must modify below:

//====================
if (Read_Switch_Timer == 0)
Read_Switch_Flag = TRUE; //<----here
else
Read_Switch_Timer--; //<-----here

//====================


Shocked
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library 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