|
|
View previous topic :: View next topic |
Author |
Message |
MegatroniC
Joined: 08 Dec 2009 Posts: 35
|
Please help for a simple code to read buttons. |
Posted: Tue Mar 16, 2010 12:03 pm |
|
|
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.
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
|
|
Posted: Tue Mar 16, 2010 3:59 pm |
|
|
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
|
|
Posted: Wed Mar 17, 2010 12:22 am |
|
|
Đ¢housand thanks PCM programmer. |
|
|
ssaguiar
Joined: 02 Nov 2003 Posts: 11 Location: Brazil
|
|
Posted: Wed Jun 23, 2010 10:11 pm |
|
|
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
|
|
|
ssaguiar
Joined: 02 Nov 2003 Posts: 11 Location: Brazil
|
|
Posted: Thu Jun 24, 2010 3:24 pm |
|
|
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
|
|
Posted: Thu Jun 24, 2010 3:28 pm |
|
|
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
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 24, 2010 5:28 pm |
|
|
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
|
|
Posted: Thu Jun 24, 2010 5:36 pm |
|
|
Thanks, PCM programmer.
You are very kind to share this.
Sergio |
|
|
ssaguiar
Joined: 02 Nov 2003 Posts: 11 Location: Brazil
|
|
Posted: Mon Jul 19, 2010 8:50 pm |
|
|
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
|
|
Posted: Fri Sep 02, 2011 6:16 am |
|
|
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. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 02, 2011 4:58 pm |
|
|
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
|
|
Posted: Fri Sep 02, 2011 5:12 pm |
|
|
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
|
|
Posted: Fri Sep 02, 2011 11:54 pm |
|
|
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. |
|
|
|
|
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
|