|
|
View previous topic :: View next topic |
Author |
Message |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
Multi-Event Switch Actions |
Posted: Wed Mar 09, 2005 3:33 pm |
|
|
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: 330
|
|
Posted: Tue Jun 06, 2006 9:36 pm |
|
|
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
|
|
Posted: Thu Jun 08, 2006 5:02 pm |
|
|
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: 330
|
|
Posted: Thu Jun 08, 2006 8:11 pm |
|
|
Can I have all events??
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
|
|
Posted: Fri Jun 09, 2006 6:24 am |
|
|
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
|
|
Posted: Thu Oct 11, 2007 11:20 pm |
|
|
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
//====================
|
|
|
|
|
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
|