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

Please help for a simple code to read buttons.

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



Joined: 08 Dec 2009
Posts: 35

View user's profile Send private message ICQ Number

Please help for a simple code to read buttons.
PostPosted: Tue Mar 16, 2010 12:03 pm     Reply with quote

Hello, until now I've written in assembly language. And just beginning to learn CCS.
I need your help for a function to read the 3 buttons, one may want to Hold.
I did this interrupt.
But not working properly, perhaps because there is no debounce.
I want to make something simple and universal.
Thank you in advance.
Sorry for my bad English. Smile
Code:

#int_TIMER0
void TIMER0_isr(void)                                         
{
 scroll_press=0; select_press=0; set_press=0; set_hold=0;
 if(!set)
 {
  set_press=true;
  set_time++;
 }
 else set_time=0;
 if(set_time>10)     
 {
  set_hold=true;
  set_time=0;
 }
   
 if(!select) select_press=true;
 if(!scroll) scroll_press=true;
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Mar 16, 2010 3:59 pm     Reply with quote

I don't have a simple code that can do three "held down" buttons.
All I have is the 3-switch version of the code that I previously posted.
I took out the auto-repeat stuff since you didn't request it.
I don't say this program is the best way to do it, or that it's
the most economical in code.

The three push-button switches are connected to pins A4, B0, and D4.
One side of each switch is connected to ground, and the other side to
the PIC pin. Each PIC pin has a 4.7K pull-up resistor on it.
Each switch is connected like this:
Code:

           +5v
            |
            <
            > 4.7K       
            <         ___ Push button switch 
To          |        _|_|_
PIC -----------------o   o------
pin                            |             
                              --- GND
                               -   

The test program just turns an LED on/off depending on which buttons
are pressed. See the comments in main() in the test program for
more info. The driver files (.c and .h) are posted below the test program.

Here is the test program:
Code:

#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)

#define REC_SWITCH_PIN   PIN_A4
#define UP_SWITCH_PIN    PIN_B0
#define DOWN_SWITCH_PIN  PIN_D4


#define LED_PIN  PIN_B1

#include "switch.h"
#include "switch.c"

// This preset value for Timer0 (aka RTCC) will make it
// interrupt at a 100 Hz rate, with a 4 MHz oscillator.
#define RTCC_PRESET  (256 - 39) 

// This routine interrupts every 10 ms.  It's used to poll
// the switches.
#int_rtcc
void rtcc_isr(void)
{
set_rtcc(RTCC_PRESET);

update_switch_status();   // Poll the switches
}


//=====================================
void main(void)
{
output_low(LED_PIN);

// Read and save the initial state of the switches.
gc_old_switch_status = read_switches();

// Setup the RTCC for the 10ms timer tick that runs the multi-tasking.
// A pre-scaler of 256 gives 3906.25 Hz rtcc clock.
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
set_rtcc(RTCC_PRESET);
clear_interrupt(INT_RTCC);
enable_interrupts(INT_RTCC);

enable_interrupts(GLOBAL);

// If the "Rec" button is held down for 2 seconds, turn on the
// LED on pin B1.  If the UP or DOWN buttons are pressed, then
// turn the LED off.
while(1)
  {
   if((rec_button == SW_HELD))
      output_high(LED_PIN);
   else if(up_button == SW_PRESSED)
      output_low(LED_PIN);
   else if(down_button == SW_PRESSED)
      output_low(LED_PIN);


  }

}
 


Here is the switch.c file:
Code:

// switch.c -- Debounces the switches.

//------------------------------------------------------------------
// Return the status of the switches. A "1" bit value means
// the switch is open, and a "0" bit means the switch is pressed.

SW_STATE read_switches(void)
{
SW_STATE switch_values;

// Init all switch values to "open" (ie., not pressed)
switch_values = 0xFF;   

switch_values.rec  = input(REC_SWITCH_PIN);
switch_values.up   = input(UP_SWITCH_PIN);
switch_values.down = input(DOWN_SWITCH_PIN);

return(switch_values);
}

//------------------------------------------------------------------
// This task handles debouncing and the switch event flags.
// This task is called every 10 ms.  The following events are
// stored in a separate global state variable for each button.

// Key Up         (Duration -- 1 or more Ticks)
// Key Pressed    (Duration -- 1 Tick)
// Key Down       (Duration -- 1 or more Ticks)
// Key Held Down  (Duration -- 1 or more Ticks)
// Key Released   (Duration -- 1 Tick)
// Key Up         (Duration -- 1 or more Ticks) (Back to idle state)

// When the program starts, the button state will be initialized to "UP".

void update_switch_status(void)
{
SW_STATE current_switch_status;

// Read the switches.
current_switch_status = read_switches();

//-------------------------
// Handle the "REC" button.

// If the switch is closed, then increment a counter.  Based on the
// value of the counter, set the switch status byte to "Pressed",
// "Down", or "Held Down".
if(current_switch_status.rec == SW_CLOSED)
  {
   if(gc_rec_button_counter != 0xFF)  // Limit count to 0xFF max
      gc_rec_button_counter++;        //  because it's a byte variable

   // Set the state, based on value of the down counter.
   // The down counter will be a value from 1 to 0xFF.
   if(gc_rec_button_counter == 1)
      gc_rec_button_state = SW_PRESSED;
   else if(gc_rec_button_counter < REC_SW_HELD_DOWN_DELAY)
      gc_rec_button_state = SW_DOWN;
   else
      gc_rec_button_state = SW_HELD;
  }
else  // If the switch is open:
  {
   if(gc_rec_button_counter)  // Has the rec sw. been down previously ?
      gc_rec_button_state = SW_RELEASED; // If so, show it is now released
   else
      gc_rec_button_state = SW_UP;  // If not, it's been up for at least 2+ ticks


   gc_rec_button_counter = 0;  // Always clear down ctr if switch is up.
  }


//-------------------------
// Handle the "UP" button.

if(current_switch_status.up == SW_CLOSED)
  {
   if(gc_up_button_counter != 0xFF)  // Limit count to 0xFF max
      gc_up_button_counter++;        //  because it's a byte variable

   // Set the state, based on value of the down counter.
   // The down counter will be a value from 1 to 0xFF.
   // It's called a "down counter" because it counts the number of 10 ms
   // "ticks" that the button has been held down continuously.
   if(gc_up_button_counter == 1)
      gc_up_button_state = SW_PRESSED;
   else if(gc_up_button_counter < UP_DOWN_SW_HELD_DOWN_DELAY)
      gc_up_button_state = SW_DOWN;
   else
      gc_up_button_state = SW_HELD;

  }
else  // If the switch is open:
  {
   if(gc_up_button_counter)
      gc_up_button_state = SW_RELEASED;
   else
      gc_up_button_state = SW_UP;

   gc_up_button_counter = 0;
  }

//----------------------------
// Handle the "DOWN" button.

if(current_switch_status.down == SW_CLOSED)
  {
   if(gc_down_button_counter != 0xFF)  // Limit count to 0xFF max
      gc_down_button_counter++;        //  because it's a byte variable

   // Set the state, based on value of the down counter.
   // The down counter will be a value from 1 to 0xFF.
   if(gc_down_button_counter == 1)
      gc_down_button_state = SW_PRESSED;
   else if(gc_down_button_counter < UP_DOWN_SW_HELD_DOWN_DELAY)
      gc_down_button_state = SW_DOWN;
   else
      gc_down_button_state = SW_HELD;

  }
else  // If the switch is open:
  {
   if(gc_down_button_counter)
      gc_down_button_state = SW_RELEASED;
   else
      gc_down_button_state = SW_UP; 

   gc_down_button_counter = 0; 
  }

//----------------------------
// Tell the user code in main() that the buttons have been updated.
//gc_freq_button_status_updated = TRUE;
//gc_rec_button_status_updated = TRUE;

gc_button_status_updated = TRUE;
gc_old_switch_status = current_switch_status;
}


Here is the switch.h file:
Code:

// switch.h

//---------------------------------------------------------------
// DEFINES

// These are the delay periods (in 10 ms "ticks") for switch events.
// These values are used in the check_switches() function.

#define REC_SW_HELD_DOWN_DELAY       200  //  200 x 10ms = 2 sec
#define UP_DOWN_SW_HELD_DOWN_DELAY   200  //  200 x 10ms = 2 sec

// Logic levels for the switches.
#define SW_CLOSED 0
#define SW_OPEN   1

// The switch states are ordered 1 to 5 because we will clear the
// state variable to 0 in the user code to show that it has been read.
enum sw_states {SW_UP=1, SW_PRESSED, SW_DOWN, SW_HELD, SW_RELEASED};
//                1        2           3        4        5

//---------------------------------------------------------------
// GLOBALS
//
// This structure holds the state of the switches after they are read
// from the i/o port.
typedef struct
{
int1 rec;
int1 up;
int1 down;
}SW_STATE;

// These enum values provide names for the indexes into the array of
// gat_sw_info structures, below, instead of just using 0, 1, 2, 3, 4, 5.
enum switches {REC_SW, UP_SW, DOWN_SW};

struct
{
int8 state;         // This is either UP, PRESSED, DOWN, HELD, or RELEASED
int8 counter;       // Number of ticks that the switch has been held down.
}gat_sw_info[] = {
   {0, 0},  // REC_SW
   {0, 0},  // FREQ_UP_SW
   {0, 0}   // FREQ_DOWN_SW
};

// This variable is used in the check_switches() function.
SW_STATE gc_old_switch_status = {SW_OPEN, SW_OPEN, SW_OPEN};

// Use macros to create easy-to-read names for the switch events.
#define gc_rec_button_counter  gat_sw_info[REC_SW].counter
#define gc_rec_button_state    (gat_sw_info[REC_SW].state)

#define gc_up_button_counter   gat_sw_info[UP_SW].counter
#define gc_up_button_state     (gat_sw_info[UP_SW].state)

#define gc_down_button_counter gat_sw_info[DOWN_SW].counter
#define gc_down_button_state   (gat_sw_info[DOWN_SW].state)

// Short named versions of the button state variables
#define rec_button    (gat_sw_info[REC_SW].state)
#define up_button     (gat_sw_info[UP_SW].state)
#define down_button   (gat_sw_info[DOWN_SW].state)

#define all_buttons_up ((up_button == SW_UP) && (down_button == SW_UP) && (rec_button == SW_UP))
#define any_button_pressed ((up_button == SW_PRESSED) || (down_button == SW_PRESSED) || (rec_button == SW_PRESSED))

// Values for the REC switch state machine.
enum REC_STATE {REC_WAIT_FOR_START, REC_RECORDING, REC_WAIT_FOR_STOP, REC_WAIT_FOR_RELEASED};

int8 gc_button_status_updated = FALSE;

//----------------------------------------------------------------
// FUNCTION PROTOTYPES
SW_STATE read_switches(void);
void task_check_switches(void);

// End of file
MegatroniC



Joined: 08 Dec 2009
Posts: 35

View user's profile Send private message ICQ Number

PostPosted: Wed Mar 17, 2010 12:22 am     Reply with quote

Đ¢housand thanks PCM programmer. Embarassed
ssaguiar



Joined: 02 Nov 2003
Posts: 11
Location: Brazil

View user's profile Send private message Visit poster's website

PostPosted: Wed Jun 23, 2010 10:11 pm     Reply with quote

Dear PCM programmer:

Can you tell where we can see the version with auto-repeat?
It will be very useful for me.
Thank you very much.

Sergio
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 24, 2010 3:13 pm     Reply with quote

Do you only need Auto-repeat ? If so, the button() function has it
and it's a driver that's easier to use:
http://www.ccsinfo.com/forum/viewtopic.php?t=23837
This thread has links to more examples that show to use it:
http://www.ccsinfo.com/forum/viewtopic.php?t=42285

Or, do you need both Auto-repeat and the "held down" features
in the same button driver ?
ssaguiar



Joined: 02 Nov 2003
Posts: 11
Location: Brazil

View user's profile Send private message Visit poster's website

PostPosted: Thu Jun 24, 2010 3:24 pm     Reply with quote

In reality, at this moment, I am trying to do it in asm, but I am experimenting problems with timing.
I need a code where I have auto-repeat 1 per second during 2 seconds, ad, after these 2 seconds, the autorepeat goto to 4 per second (I think this is the "held down" you mention).
Also I need the debounce.
It can be in C, and I will try to convert to asm.
Thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 24, 2010 3:28 pm     Reply with quote

If you're doing ASM, this is the wrong forum. You should choose an
MPASM forum. But anyway, here's a link to the ASM code for the
Button command. It has Auto-repeat:
http://www.dontronics.com/psbpix/button.html
ssaguiar



Joined: 02 Nov 2003
Posts: 11
Location: Brazil

View user's profile Send private message Visit poster's website

PostPosted: Thu Jun 24, 2010 3:38 pm     Reply with quote

No, I started in C, and has already some coding in ccs.
You can see it at:
http://www.ccsinfo.com/forum/viewtopic.php?t=42730&highlight=
I will continue in C, because can't make it work in asm.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 24, 2010 5:28 pm     Reply with quote

Here's the version with the Auto-repeat code in it.

Test program:
Code:

#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)

#define REC_SWITCH_PIN   PIN_A4
#define UP_SWITCH_PIN    PIN_B0
#define DOWN_SWITCH_PIN  PIN_D4

#define LED1_PIN  PIN_B1
#define LED2_PIN  PIN_B2

#include "switch.h"
#include "switch.c"

// This preset value for Timer0 (aka RTCC) will make it
// interrupt at a 100 Hz rate, with a 4 MHz oscillator.
#define RTCC_PRESET  (256 - 39) 

// This routine interrupts every 10 ms.  It's used to poll
// the switches.
#int_rtcc
void rtcc_isr(void)
{
set_rtcc(RTCC_PRESET);

update_switch_status();   // Poll the switches
}


//=====================================
void main(void)
{
// Init the LEDs to "off".
output_low(LED1_PIN);
output_low(LED2_PIN);

// Read and save the initial state of the switches.
gc_old_switch_status = read_switches();

// Setup the RTCC for the 10ms timer tick that runs the multi-tasking.
// A pre-scaler of 256 gives 3906.25 Hz rtcc clock.
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
set_rtcc(RTCC_PRESET);
clear_interrupt(INT_RTCC);
enable_interrupts(INT_RTCC);

enable_interrupts(GLOBAL);

// If the "Rec" button is held down for 2 seconds, turn on the
// LED on pin B1.  If the UP is pressed, turn the LED off.
// If the DOWN button is pressed, flash the LED on pin B2.
while(1)
  {
   if((rec_button == SW_HELD))
     {
      output_high(LED1_PIN);
     }
   else if(up_button == SW_PRESSED)
     {
      output_low(LED1_PIN); 
     }
   else if(down_button == SW_PRESSED)
     {
      output_high(LED2_PIN);
      delay_ms(50);   // Do a short flash
      output_low(LED2_PIN);
     }
  }

}


switch.c
Code:

// switch.c -- Debounces the switches.

// Note: Only the UP and DOWN buttons have auto-repeat code.

//---------------------------------------------------------------------
// Return the status of the switches. A "1" bit value means the switch is open,
// and a "0" bit means the switch is pressed.

SW_STATE read_switches(void)
{
SW_STATE switch_values;

switch_values = 0xFF;   // Init all switch values to "open" (ie., not pressed)

switch_values.rec  = input(REC_SWITCH_PIN);
switch_values.up   = input(UP_SWITCH_PIN);
switch_values.down = input(DOWN_SWITCH_PIN);

return(switch_values);
}

//---------------------------------------------------------------------
// This task handles debouncing, auto-repeat, and the switch event flags.
// This task is called every 10 ms.  The following events are stored in
// a separate global state variable for each button.

// Key Up         (Duration -- 1 or more Ticks)
// Key Pressed    (Duration -- 1 Tick)
// Key Down       (Duration -- 1 or more Ticks)
// Key Held Down  (Duration -- 1 or more Ticks)
// Key Released   (Duration -- 1 Tick)
// Key Up         (Duration -- 1 or more Ticks) (Back to idle state)

// When the program starts, the button state will be initialized to "UP".

void update_switch_status(void)
{
SW_STATE current_switch_status;


// Read the switches.
current_switch_status = read_switches();

//-------------------------
// Handle the "REC" button.

// If the switch is closed, then increment a counter.  Based on the
// value of the counter, set the switch status byte to "Pressed",
// "Down", or "Held Down".
if(current_switch_status.rec == SW_CLOSED)
  {
   if(gc_rec_button_counter != 0xFF)  // Limit count to 0xFF max
      gc_rec_button_counter++;        //  because it's a byte variable

   // Set the state, based on value of the down counter.
   // The down counter will be a value from 1 to 0xFF.
   if(gc_rec_button_counter == 1)
      gc_rec_button_state = SW_PRESSED;
   else if(gc_rec_button_counter < REC_SW_HELD_DOWN_DELAY)
      gc_rec_button_state = SW_DOWN;
   else
      gc_rec_button_state = SW_HELD;
  }
else  // If the switch is open:
  {
   if(gc_rec_button_counter)  // Has the rec sw. been down previously ?
      gc_rec_button_state = SW_RELEASED; // If so, show it is now released
   else
      gc_rec_button_state = SW_UP;  // If not, it's been up for at least 2+ ticks


   gc_rec_button_counter = 0;  // Always clear down ctr if switch is up.
  }


//-------------------------
// Handle the "UP" button.

if(current_switch_status.up == SW_CLOSED)
  {
   if(gc_up_button_counter != 0xFF)  // Limit count to 0xFF max
      gc_up_button_counter++;        //  because it's a byte variable

   // Set the state, based on value of the down counter.
   // The down counter will be a value from 1 to 0xFF.
   // It's called a "down counter" because it counts the number of 10 ms
   // "ticks" that the button has been held down continuously.
   if(gc_up_button_counter == 1)
      gc_up_button_state = SW_PRESSED;
   else if(gc_up_button_counter < UP_DOWN_SW_HELD_DOWN_DELAY)
      gc_up_button_state = SW_DOWN;
   else
      gc_up_button_state = SW_HELD;

   // Check if auto-repeat should be enabled.
   if(gc_up_button_counter == UP_DOWN_SW_AUTO_REPEAT_DELAY)
     {
      gc_up_button_auto_repeat_flag = TRUE;
      gc_up_button_auto_repeat_counter = 0;
     }

   // Check if we're in auto-repeat mode.  If so, check if it's
   // time to issue a "pressed" state.
   if(gc_up_button_auto_repeat_flag)
     {
      gc_up_button_auto_repeat_counter++;

      if(gc_up_button_auto_repeat_counter == UP_DOWN_SW_AUTO_REPEAT_INTERVAL)
        {
         gc_up_button_state = SW_PRESSED;
         gc_up_button_auto_repeat_counter = 0;
        }
      }

  }
else  // If the switch is open:
  {
   if(gc_up_button_counter)
      gc_up_button_state = SW_RELEASED; // Indicate if it was just released
   else
      gc_up_button_state = SW_UP;  // Otherwise, it's been up for 2+ ticks

   gc_up_button_auto_repeat_flag = FALSE;

   gc_up_button_counter = 0;  // Always clear down ctr if switch is up.
  }

//----------------------------
// Handle the "DOWN" button.

if(current_switch_status.down == SW_CLOSED)
  {
   if(gc_down_button_counter != 0xFF)  // Limit count to 0xFF max
      gc_down_button_counter++;        //  because it's a byte variable

   // Set the state, based on value of the down counter.
   // The down counter will be a value from 1 to 0xFF.
   if(gc_down_button_counter == 1)
      gc_down_button_state = SW_PRESSED;
   else if(gc_down_button_counter < UP_DOWN_SW_HELD_DOWN_DELAY)
      gc_down_button_state = SW_DOWN;
   else
      gc_down_button_state = SW_HELD;

   // Check if auto-repeat should be enabled.
   if(gc_down_button_counter == UP_DOWN_SW_AUTO_REPEAT_DELAY)
     {
      gc_down_button_auto_repeat_flag = TRUE;
      gc_down_button_auto_repeat_counter = 0;
     }

   // Check if we're in auto-repeat mode.  If so, check if it's
   // time to issue a "pressed" state.
   if(gc_down_button_auto_repeat_flag)
     {
      gc_down_button_auto_repeat_counter++;

      if(gc_down_button_auto_repeat_counter == UP_DOWN_SW_AUTO_REPEAT_INTERVAL)
        {
         gc_down_button_state = SW_PRESSED;
         gc_down_button_auto_repeat_counter = 0;
        }
     }

  }
else  // If the switch is open:
  {
   if(gc_down_button_counter)
      gc_down_button_state = SW_RELEASED; // Indicate if it was just released
   else
      gc_down_button_state = SW_UP;  // Otherwise, it's been up for 2+ ticks

   gc_down_button_auto_repeat_flag = FALSE;
   gc_down_button_counter = 0;  // Always clear down ctr if switch is up.
  }

gc_button_status_updated = TRUE;
gc_old_switch_status = current_switch_status;

}



switch.h
Code:

// switch.h

// DEFINES

// These are the delay periods (in 10 ms "ticks") for switch events.
// These values are used in the check_switches() function.
#define UP_DOWN_SW_AUTO_REPEAT_DELAY    50   // 50 x 10ms = 500 ms
#define UP_DOWN_SW_AUTO_REPEAT_INTERVAL 14   // 16 x 10ms = 160 ms = 6/sec

// These two lines specify the amount of time (in units of 10ms ticks)
// that a switch must be continuously held down, in order to be
// detected as "held down".
#define REC_SW_HELD_DOWN_DELAY         200  //  200 x 10ms = 2 sec
#define UP_DOWN_SW_HELD_DOWN_DELAY     200  //  200 x 10ms = 2 sec

// Logic levels for the switches.
#define SW_CLOSED 0
#define SW_OPEN   1

// The switch states are ordered 1 to 5 because we will clear the
// state variable to 0 in the user code to show that it has been read.
enum sw_states {SW_UP=1, SW_PRESSED, SW_DOWN, SW_HELD, SW_RELEASED};
//                1        2           3        4        5

//---------------------------------------------------------------------------
// GLOBALS
//
// This structure holds the state of the switches after they are read
// from the i/o port.
typedef struct
{
int1 rec;
int1 up;
int1 down;
}SW_STATE;


// These enum values provide names for the indexes into the array of
// gat_sw_info structures, below, instead of just using 0, 1, 2, 3, 4, 5.
enum switches {REC_SW, FREQ_UP_SW, FREQ_DOWN_SW};


struct
{
int8 state;         // This is either UP, PRESSED, DOWN, HELD, or RELEASED
int8 counter;       // Number of ticks that the switch has been held down.
int8 auto_repeat_counter;  // When in auto-repeat, this counts off the interval.
int8 auto_repeat_flag;
}gat_sw_info[] = {
   {0, 0, 0, 0},  // REC_SW
   {0, 0, 0, 0},  // FREQ_UP_SW
   {0, 0, 0, 0}   // FREQ_DOWN_SW
};

// This variable is used in the check_switches() function.
SW_STATE gc_old_switch_status = {SW_OPEN, SW_OPEN, SW_OPEN};

// Use macros to create easy-to-read names for the switch events.
#define gc_rec_button_counter  gat_sw_info[REC_SW].counter
#define gc_rec_button_state    (gat_sw_info[REC_SW].state)

#define gc_up_button_counter   gat_sw_info[FREQ_UP_SW].counter
#define gc_up_button_state     (gat_sw_info[FREQ_UP_SW].state)
#define gc_up_button_auto_repeat_counter (gat_sw_info[FREQ_UP_SW].auto_repeat_counter)
#define gc_up_button_auto_repeat_flag (gat_sw_info[FREQ_UP_SW].auto_repeat_flag)

#define gc_down_button_counter gat_sw_info[FREQ_DOWN_SW].counter
#define gc_down_button_state   (gat_sw_info[FREQ_DOWN_SW].state)
#define gc_down_button_auto_repeat_counter (gat_sw_info[FREQ_DOWN_SW].auto_repeat_counter)
#define gc_down_button_auto_repeat_flag (gat_sw_info[FREQ_DOWN_SW].auto_repeat_flag)

// Short named versions of the button state variables
#define rec_button    (gat_sw_info[REC_SW].state)
#define up_button     (gat_sw_info[FREQ_UP_SW].state)
#define down_button   (gat_sw_info[FREQ_DOWN_SW].state)

#define all_buttons_up ((up_button == SW_UP) && (down_button == SW_UP) && (rec_button == SW_UP))
#define any_button_pressed ((up_button == SW_PRESSED) || (down_button == SW_PRESSED) || (rec_button == SW_PRESSED))

int8 gc_button_status_updated = FALSE;

//---------------------------------------------------------------------------
// FUNCTION PROTOTYPES
SW_STATE read_switches(void);

// End of file
ssaguiar



Joined: 02 Nov 2003
Posts: 11
Location: Brazil

View user's profile Send private message Visit poster's website

PostPosted: Thu Jun 24, 2010 5:36 pm     Reply with quote

Thanks, PCM programmer.
You are very kind to share this.

Sergio
ssaguiar



Joined: 02 Nov 2003
Posts: 11
Location: Brazil

View user's profile Send private message Visit poster's website

PostPosted: Mon Jul 19, 2010 8:50 pm     Reply with quote

I know this is not a assembler forum, but, the code below, in asm, work with debounce, autorepeat and 2 levels of turbo.
It can be easily ported to C. I will do it and also post here.
In the example, It process only the key UP, but can be adapted to any key use.
The key up increments till 250 value and stops at this value (can be any value).
Hope it can be usefull to all.

Code:


;/****************************************************************************
;* DESCRIPTION: Verify if key Up is pressed
;/****************************************************************************
   BSF      TRISB,7         ; Set PORTB,7 as input (KEY_UP)
   BCF      STATUS, RP0      ; Goto BANK 0
   BTFSS   KEY_UP         ; Test if PORTB pin 7 is 0 (KEY_UP pressed)
   GOTO   KEYUPISR      ; If key pressed, go process it

;/****************************************************************************
;* DESCRIPTION: If we arrive here, no keys are pressed, so clear keys flags.
;/****************************************************************************
   CLRF   KEYS_FLAGS      ; If no key pressed, clear Keys pressed flags.
   CLRF   KEYUPCNT      ; Clear Key UP press counter
   CLRF   KEYDWNCNT      ; Clear Key DOWN press counter
   CLRF   KEYONOFFCNT      ; Clear Key ONOFF press counter
   MOVLW   D'3'         ; Reset key debounce counter
   MOVWF   KEY_DEBOUNCE   ;
   CLRF   KEY_TURBO      ; Reset Key turbo counter
   GOTO   EXITTMR0      ; Done, exit.

;/****************************************************************************
;* DESCRIPTION: Process key Up
;/****************************************************************************
KEYUPISR
   BTFSC   KEYS_FLAGS,0   ; First pass? If not, use debounce/turbo   
   GOTO   CONTDEB         ; Continue, if not.
   CLRF   TMR_1MS         ; Clear 1 ms counter (for 100 ms)
   BSF      BUZZEREN      ; Enable beep (for 100ms)
   GOTO   CONTUPISR2      ; Continue

CONTDEB
   MOVF   KEY_TURBO,W      ; If KEY_TURBO == 255
   SUBLW   D'255'         ; Let it be 255 (we are at maximum TURBO speed).
   BTFSS   STATUS,Z      ; Else
   INCF   KEY_TURBO,F      ; Increment KEY_TURBO

   DECFSZ   KEY_DEBOUNCE,F   ; KEY_DEBOUNCE--;
   GOTO   EXITKEYUPISR   ; If KEY_DEBOUNCE > 0, exit

   MOVF   KEY_TURBO,W      ; Else, if KEY_TURBO < 20,
   SUBLW   D'19'         ; Then, let's use a value of 6 in KEY_DEBOUNCE
   BTFSS   STATUS,C      ;
   GOTO   CONTUPISR0      ; No, it's not < 20, continue
   MOVLW   0x06         ; Yes, it's below 20, then
   MOVWF   KEY_DEBOUNCE   ; set simple autorepeat mode - KEY_DEBOUNCE = 6
CONTUPISR0
   MOVF   KEY_TURBO,W      ; If KEY_TURBO > 20 and KEY_TURBO <= 40
   SUBLW   D'20'         ; > 20?
   BTFSC   STATUS, C      ;
   GOTO   CONTUPISR1      ; No, goto next test
   MOVF   KEY_TURBO,W      ;
   SUBLW   D'40'         ; <= 40?
   BTFSS   STATUS, C      ;
   GOTO   CONTUPISR1      ; No, goto next test
   MOVLW   0x03         ; Yes, KEY_TURBO is > 20 and <= 40 then
   MOVWF   KEY_DEBOUNCE   ; Put in turbo mode - KEY_DEBOUNCE = 3
   GOTO   CONTUPISR2      ; Continue
CONTUPISR1
    MOVF   KEY_TURBO,W      ; Else if KEY_TURBO > 40
    SUBLW   D'40'         ;
    BTFSC   STATUS, C      ;
    GOTO   CONTUPISR2      ; No, Continue
    MOVLW  D'255'         ; If yes, make it 255, so
    MOVWF  KEY_TURBO      ; Next time, it will allways get here...
    MOVLW  0x01         ; KEY_DEBOUNCE = 1
    MOVWF  KEY_DEBOUNCE   ; Put in extra tubo mode - KEY_DEBOUNCE = 1.
CONTUPISR2

   MOVF   TEMPER,W      ; If TEMPER == 250
   SUBLW   D'250'
   BTFSC   STATUS,Z      ;
   GOTO   LLA1         ; get out if = 250 and beep
   INCF   TEMPER,F
   GOTO   LLA            ; continue
   CALL   SETDISPVAR      ; Convert
   DECFSZ   KEYUPCNT,W      ; If this is the first time the key UP is pressed, then beep?
   GOTO   EXITKEYUPISR   ; Exit
LLA1
   CLRF   TMR_1MS         ; Restart 1 ms counter, so timer1 isr can make beep last 100ms
   BSF      BUZZEREN      ; Enable beep (for 100ms), untill it's disabled by timer1 isr
EXITKEYUPISR
   GOTO   EXITTMR0      ; Done, exit


In timer1 interrupt service (at every 500us), do this, to beep:

Code:

;/****************************************************************************
   ;* DESCRIPTION: If beep enabled, toggle buzzer pin.
   ;/****************************************************************************
   BTFSS   BUZZEREN      ; Buzzer Enabled?
   GOTO   ENDBEEPC      ; No, get out
   BSF      STATUS, RP0      ; Bank 1
   BCF      TRISC,0         ; PORTC pin0 output
   MOVLW   D'1'         ; Pin 0 => Buzzer
   BCF      STATUS, RP0      ; Bank 0
   XORWF   PORTC,F         ; Xor PORTC,pin0 with decimal 1 (Binary 00000001).
ENDBEEPC
   ;/****************************************************************************
   ;* DESCRIPTION: Initialize all interrupts values for TIMER0 and TIMER1
   ;/****************************************************************************
   INCF   TMR_1MS,F      ; Increment TR_1MS (0.5 ms counter)
   MOVLW   D'200'         ; 200 because we have an timer1 int at every 500us.
   XORWF   TMR_1MS,W      ; Is TMR_1MS = 200 (100ms)?
   BTFSC   STATUS,Z      ; No, skip if TMR_1MS < 200
   GOTO   INC100MS      ; Yes, zero TMR_1MS and inc TMR_100MS
   GOTO   END_INT         ; No, exit interrupt

INC100MS
   ;/****************************************************************************
   ;* DESCRIPTION: Disable buzzer at every 100ms and process 100ms counter
   ;/****************************************************************************
   BCF      BUZZEREN      ; Disable buzzer
   CLRF   TMR_1MS         ; Zero TMR_1MS
   INCF   TMR_100MS,F      ; Increment TMR_100MS (100 ms counter)
   ...
   ...
   ...
   ...
   ...

END_INT
MegatroniC



Joined: 08 Dec 2009
Posts: 35

View user's profile Send private message ICQ Number

PostPosted: Fri Sep 02, 2011 6:16 am     Reply with quote

I am very grateful to PCM programmer, the code is doing a great job.
But today I tried to do the following:
Code:

while(1)
  {
   if(up_button == SW_PRESSED)
      output_high(LED_PIN1);
   if(down_button == SW_PRESSED)
      output_high(LED_PIN2);
   if(rec_button == SW_PRESSED)
      output_high(LED_PIN3);
   else if(rec_button == SW_HELD)
      output_high(LED_PIN4);
  }
 

When I hold the rec_button lights up LED3 not LED4, where I'm wrong?

Thanks. Smile
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Sep 02, 2011 4:58 pm     Reply with quote

Post your #define statements for the LED pins.

Also post your #define statements for the REC, UP, and DOWN switches.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Fri Sep 02, 2011 5:12 pm     Reply with quote

That is the behavior I would expect with your "else if" statement. The rec_button == SW_HELD is not checked unless the rec_button == SW_PRESSED is false.
_________________
The search for better is endless. Instead simply find very good and get the job done.
MegatroniC



Joined: 08 Dec 2009
Posts: 35

View user's profile Send private message ICQ Number

PostPosted: Fri Sep 02, 2011 11:54 pm     Reply with quote

Code:
#include <18F4520.h>
#FUSES NOWDT                   
#FUSES WDT8192               
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES PUT                      //Power Up Timer
#FUSES PROTECT                  //Code protected from reads
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV27                   //Brownout reset at 2.7V
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset 
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOPBADEN                   //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=4MHz)

#define REC_SWITCH_PIN     PIN_B7
#define UP_SWITCH_PIN       PIN_B6
#define DOWN_SWITCH_PIN  PIN_B5
   

#define LED_PIN1  PIN_B0
#define LED_PIN2  PIN_B1
#define LED_PIN3  PIN_B2
#define LED_PIN4  PIN_B3



SherpaDoug wrote:
That is the behavior I would expect with your "else if" statement. The rec_button == SW_HELD is not checked unless the rec_button == SW_PRESSED is false.


I tried so:



Code:
while(1)
   {
    if(up_button == SW_PRESSED)
       output_high(LED_PIN1);
    if(down_button == SW_PRESSED)
       output_high(LED_PIN2);
    if(rec_button == SW_HELD)
       output_high(LED_PIN4);     
    else if(rec_button == SW_PRESSED)
       output_high(LED_PIN3);
   }


when I hold rec lights led3, after two seconds turns and led4.
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