|
|
View previous topic :: View next topic |
Author |
Message |
kd5uzz
Joined: 28 May 2006 Posts: 56
|
Best way to debouce? |
Posted: Fri Mar 09, 2007 3:30 am |
|
|
I'm using a matrix encoded keypad, connected to a MM74C923 keypad decoder. This chip had a built-in debouce function, but I don't have the correct value caps to make use of it.
I figured I could create a debouce function in software tonight and worry about getting the caps another day, but so far I haven't been able to create a working debouce routine. I've tried disabling int_ext inside the ISR, printing the value and enabling int_ext. I'd like to avoid delay_ms(), so I tried using TIMER2 to reenable int_ext after upto 80ms, but that didn't work quite right either.
Ideas?
Code: |
#include <16F877a.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000) //clock speed
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,ERRORS)
int CheckButton = FALSE;
void Main(){
int PortVal;
enable_interrupts(INT_EXT); //INT for B0 (IR or Keypad)
enable_interrupts(GLOBAL); //Actually enable them
printf("Keypad Test\n\n\r");
while(TRUE){
if ((CheckButton == TRUE)) {
CheckButton = FALSE;
PortVal = input_d();
printf("Scan Code:%d\n\r",PortVal);
}
}
}
#int_ext
void ButtonPress() {
CheckButton = TRUE;
}
|
|
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Fri Mar 09, 2007 4:03 am |
|
|
Push buttons connected to the ISRs would normally require hardware debouncing. But in your case the software debouncing algorithm can be as simple as this:
- Declare a global counter variable
- Set up a timer interrupt, which increments the counter.
- The counter is zeroed in the ISR every time th ISR is called. By the way, the majority of the ISR calls will be caused by the bounce transitions. ISR also sets up a flag like your present code.
- The main loop polls for a flag (just like it does already). When it sees the flag, it waits for 50uS. (Don't remember the exact number. It's somewhere in the tens of uS.) Make sure that the button interrupt remains enabled during this delay.
- After this delay the main loop looks at the counter, if it's below some threshold number - the line is still bouncing. You could wait again or proceed with other things.
- If the counter is above the threshold value, then the line has stopped bouncing. Check the state of the button pin: if it's the same as the flag - you have a legitimate button press. If it's not the same as a flag - the interrupt that have set the flag was caused by some kind of glitch. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Mar 09, 2007 8:28 am |
|
|
Kender has all good points.
I'm not sure if you still have the MM74C923 in the circuit.
If you do, you should follow that circuit. Software debounce
may simply NOT be able to work. That chip has timming that
you must adhear to. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Best way to debouce? |
Posted: Fri Mar 09, 2007 10:02 am |
|
|
kd5uzz wrote: | I'm using a matrix encoded keypad, connected to a MM74C923 keypad decoder. This chip had a built-in debouce function, but I don't have the correct value caps to make use of it.
I figured I could create a debouce function in software tonight and worry about getting the caps another day, but so far I haven't been able to create a working debouce routine. I've tried disabling int_ext inside the ISR, printing the value and enabling int_ext. I'd like to avoid delay_ms(), so I tried using TIMER2 to reenable int_ext after upto 80ms, but that didn't work quite right either.
Ideas?
Code: |
#include <16F877a.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000) //clock speed
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,ERRORS)
int CheckButton = FALSE;
void Main(){
int PortVal;
enable_interrupts(INT_EXT); //INT for B0 (IR or Keypad)
enable_interrupts(GLOBAL); //Actually enable them
printf("Keypad Test\n\n\r");
while(TRUE){
if ((CheckButton == TRUE)) {
CheckButton = FALSE;
PortVal = input_d();
printf("Scan Code:%d\n\r",PortVal);
}
}
}
#int_ext
void ButtonPress() {
CheckButton = TRUE;
}
|
|
I think a simple solution would be to do this from the interrupt pin; enable a timer interrupt and set the timer to a value that will cause a timer interrupt in xmS. When the timer interrupts the value has been stable for xmS so it is debounced, read the input from the timer interrupt set flag that input has changed. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
|
mat72
Joined: 19 Jan 2006 Posts: 11
|
|
Posted: Sun Mar 11, 2007 9:55 am |
|
|
I have a bunch of switches that I debounce without using an ISR and it works great. it even picks up on press and release.
Each button has the following structure
Code: |
typedef struct {
BYTE isDirty;
BYTE value;
BYTE holdTime;
unsigned int16 pin;
} DebouncedInput;
|
My code uses a multi tasking design. I have a task which checks the input every 5ms via the following function:
Code: |
void DebounceInput(DebouncedInput *in, BYTE newValue){
if(in->holdTime <0>value != newValue){ // change has occured
in->holdTime = DEBOUNCE_DELAY;
in->value = newValue;
in->isDirty = 1;
}
}
else{
if(in->holdTime)in->holdTime--;
}
}
|
each time there is a change in the input value, a hold time for that input is set (DEBOUNCE_DELAY). I have a DEBOUNCE_DELAY of 4 and because the calling task is scheduled to run every 5ms, thats a hold time of 20ms.
note that onInputChange is called every time the debounced input goes from 1 -> 0 or 0->1.
You can also just read from the debouncedInputDevices[i].value.
I find this code works great, as I have a lot of other tasks running and I don't like spending anytime in ISRs or delaying/blocking the processor with delays.
Code: | void taskPollDebounceInput(){
static BYTE i;
if(timerPollDebounceInput) return;
timerPollDebounceInput = TIMER_DEBOUNCE_INPUTS;
for(i = 0; i < numDebouncedInputDevices; i++){
DebounceInput(&debouncedInputDevices[i], input( (debouncedInputDevices[i].pin) ) );
// there has been a change
if ( debouncedInputDevices[i].isDirty == 1 ){
debouncedInputDevices[i].isDirty = 0;
onInputChange(i);
}
}
} |
|
|
|
|
|
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
|