We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I have done software debounce logic with 2/3 voter logic and kindly verify the coding i don't no whether it is correct or not. Please help me
Coding:
void inputRoutine() { uint16_t temp; InputP1_Temp=P1&0x00; for(Index1=0;Index1<MAXINPUTS;Index1++) { temp=debounce(Index1); if(temp==1) { Input_TableP1[Index1]=1; } else if(temp==0) { Input_TableP1[Index1]=0; } } } /***************** -- Debounce Port P1 -- *****************/ bit debounce(uint16_t IN_INDEX) { uint16_t INDEX2,ONE=0,ZERO=0; char TEMP,SHIFT_RESULT[3]=0x00; for(INDEX2=0;INDEX2<3;INDEX2++) { TEMP= P1; SHIFT_RESULT[INDEX2]=(TEMP>>IN_INDEX)& 0x01; delay_10micro_sec(); } /* Comparision of 3 values retreived from same pin*/ for(INDEX2=0;INDEX2<3;INDEX2++) { if(SHIFT_RESULT[INDEX2]==1) ONE++; else if(SHIFT_RESULT[INDEX2]==0) ZERO++; } return (ONE>ZERO); }
With Thanks, G.Karthik Ragunath
Whether there is any standard programs for software debouncing?....Kindly help me.........
I was given Atmel 89C52 processor. P0,P2--Output Ports P1,P3--Input Ports there are 16 input buttons and 16 led outputs I want to implement debounce logic for 16 Input Buttons with 2/3 voter logic. In the above program I done it for one input port.
Debouncing is a corner stone when reading mechanical switches. But the algorithm is so simple that there normally are no standard code. You usually start from scratch - or copy a number of lines from a previous project and adapt a bit.
When debouncing many signals, you have to decide if they should be debounced one-by-one or if it is the complete set of signals that forms the accepted signal, i.e. if all 16 signals should pass the debounce test one-by-one for you to accept a new 16-bit output value.
As already mentioned, you base the algorithm timing on the physical properties of your switches. That is something you look closer at with a scope.
And you normally don't do two-out-of-three voting. You do 20-out-of-thirty, or you do last-10-samples-identical or something like that.
Refine your code and come back for more suggestions. But don't expect people to write the code for you. School work is for the student, not for the net.
the dead simple way to do it is to set a timer to auto reload 'debounce time' and read the keys in this timers ISR. Then when two consequtive reads have been identical you have it.
Erik
"the dead simple way to do it is to set a timer to auto reload 'debounce time' and read the keys in this timers ISR. Then when two consequtive reads have been identical you have it."
I would recommend this technique.
Have used this same fundamental code for the past 18 years with no trouble - Although I check for three consecutive reads.
Erik, now I find myself agreeing with you - This is getting wierd ;)
doing it like Eric suggested makes you vulnerable to changes in the frequency of the timer. depending on the application, you must actually miss key strokes if the frequency is decreased. I'd just poll the hardware in the super-loop (assuming low interrupt execution duration).
I meant of course you might actually...
"...makes you vulnerable to changes in the frequency of the timer."
Never seen that as a problem. I (nearly) always have a periodic tick running at a similar rate anyway to provide timing for the foreground tasks etc.
The ISR triggered by the time may have a variation - But it is slight and probably better than the jitter that might occur in a 'super-loop'.
doing it like Eric suggested makes you vulnerable to changes in the frequency of the timer. depending on the application how would "the frequency of the timer" used for debouncing EVER change???
the same piece of code might be used to measure debounce time of mechanical equipment that does not adhere to "normal" human response times. if so, and the code is integrated without thorough testing - well, then you have a bug.
"...without thorough testing - well, then you have a bug."
Surely that equally goes for any other piece of non-thoroughly tested code?
Wait a second here ... Am I defending Erik ???
I'm recruiting Jack Sprat (and Ms. Embedded...) !
Yes, I'm defending Erik too here.
Any solution that takes multiple samples of an input and produces a filtered output is affected by the time strata. It doesn't matter if the time strata comes from a timer, or is a "best case" busy-loop. Any code change that may affect the size of the time strata may affect the function and requires the code to be retested.
A busy-loop requiring two or three consecutive samples to be identical can be too fast just because of additional compiler optimization. Or can become too slow because a code change results in a background ISR starting to consume a relevant percentage of the total processor capacity. A timer is least likely to randomly change speed - and when the processor load gets so high that you can't service every timer tick then you normally have bigger problems than just properly debouncing the keyboard.
I normally name the variables used by the timer functions so they specify the tick period or tick frequency (depending on how the variables are used) of the involved timer.
When I change the frequency of a timer (by changing a define) I then also visit the timer ISR and renames all variables updated by the ISR.
A variable "keyboard_deboucne_10ms_ticks" may get renamed to "keyboard_debounce_5ms_ticks" which forces me to verify all code that accesses this variable. Most of the time, it is enough to change the variable name on these other locations too, since they normally gets their assigned values computed from the same define that specified the timer period or timer frequency.
[I was bored, again...]
This works just fine for debouncing mechanical contacts. This example uses eight samplings and is not exactly a 'majority vote' type, but rather a filter type.
This algorithm is not a new or original one. I don't remember where I got it, but its been around for a while...
//////////////////////////////////////////////////////////////////////////// // // // #define the world according to C // // // //////////////////////////////////////////////////////////////////////////// #define LEADING_ZERO 0x7F // 0111.1111 Used to caputure new-assertions #define ALL_ONES 0xFF // 1111.1111 Used to detect a 'held' state #define LOCK_INPUT (P1_0) // Ref: hardware definition of the button #define BEEP_INPUT (P1_1) // Ref: hardware definition of the button #define LOCK_ASSERTED 0 // Asserted means a logic low (0 volts) #define BEEP_ASSERTED 0 // Asserted means a logic low (0 volts) #define BUTTON_LOCK 1 // For the switch/case construct to access #define BUTTON_BEEP 2 // or select the state of the button #define SARDINE 0 // NOTE: after studying this fish, it #define ERIK (!SARDINE) // is basically impossible to hurt a // sardine's feelings: a hearty fish // that can handle the humor (!Humour). #define TRUE (ERIK) // per erik #define FALSE (!ERIK) // per others //////////////////////////////////////////////////////////////////////////// // // // Allocate the 'global' data-stores // // // //////////////////////////////////////////////////////////////////////////// bit Lock_Signal; // TRUE == Asserted Signal bit Beep_Signal; // TRUE == Asserted Signal bit New_Lock; // TRUE == Newly asserted & Sticky bit New_Beep; // TRUE == Newly asserted & Sticky /* **====================================================================== ** Scan_Buttons **====================================================================== ** ** Read in each bit and shift it into a data-store. This shall form ** a stream of bits representing the 1's and 0's as the signal is ** asserted--complete with the debouncing of the signal: ** ** Stream: 0001110101000111111111111111111111 ** ** The byte value '11010100' as the stream passed through it. ** ** Check for the value of 7Fh where the leading zero represents the ** 'off' state (or one of the last non-asserted value), and the ** 111.1111 part represents a 'steady-state' assertion. ** ** When this is captured (the 7Fh) it occurs once during the sampling ** of the stream and represents a fresh signal assertion. When the value ** is FFh, then it is a continuously asserted signal. ** ** 0001110101000111111111111111111111 ** 00011111 ** 00111111 ** 01111111 = 7Fh = match (newly pressed) ** 111111111 = on (statically held) ** 111111111 = on (statically held) ** ** This requires this routine to be called at an interval which ** can provide the timing resolution expected for system operations. ** **---------------------------------------------------------------------- ** ** Parameters Passed: <void> ** Parameters Returned: <void> ** Notes: ** 1) This is expected to be in an ISR called from a time-base ** ** 2) This algorithm is common and well known (nothing origional) ** ** 3) The lack of new-lines and open/close braces were ** imposed due to the easy addition/deletion of 'buttons' ** **---------------------------------------------------------------------- */ void Scan_Buttons( void ) { /*------------------------------------------------------------------. ; 8-bits of data store for each signal is used for the shifting ; ; process. 8 x (call interval) = max detect time. ; '------------------------------------------------------------------*/ static u8 lock_byte = 0x00; // (legit use of 'at-file-scope') static u8 beep_byte = 0x00; // /*------------------------------------------------------------------. ; Read in the buttons (Signal is #def'd as a port I/O pin) ; '------------------------------------------------------------------*/ if( LOCK_INPUT ^ (!LOCK_ASSERTED) ) lock_byte |= 1; if( BEEP_INPUT ^ (!BEEP_ASSERTED) ) beep_byte |= 1; /*------------------------------------------------------------------. ; Detect the first edge of signal assertion: declare a new signal ; ;-------------------------------------------------------------------; ; We are looking for the front 0 followed by the 1's: 0111.1111 ; '------------------------------------------------------------------*/ if( lock_byte == LEADING_ZERO ) New_Lock = TRUE; // These are sticky- if( beep_byte == LEADING_ZERO ) New_Beep = TRUE; // bits (reset manually) /*------------------------------------------------------------------. ; Check for static state signal ; ;-------------------------------------------------------------------; ; We are looking for all 1s. A static set of 1s = pressed for XmS ; '------------------------------------------------------------------*/ if( lock_byte == ALL_ONES ) Lock_Signal = TRUE; else Lock_Signal = FALSE; if( beep_byte == ALL_ONES ) Beep_Signal = TRUE; else Beep_Signal = FALSE; /*------------------------------------------------------------------. ; Shift them for next iteration ; '------------------------------------------------------------------*/ lock_byte <<= 1; beep_byte <<= 1; }
[continued]
/* **====================================================================== ** Check_Button [ ACCESSOR ] **====================================================================== ** ** Checks if the signal selected is asserted by simply accessing the ** Button_Scan assigned data-stores. ** **---------------------------------------------------------------------- ** ** Parameters Passed: (u8) button number #defined ** Parameters Returned: (bit) TRUE = Asserted ** Notes: ** 1) The lack of new-lines and open/close braces were ** imposed due to the easy addition/deletion of 'buttons' ** ** 2) Doesn't return TRUE upon detection of a new assertion. ** (modify if you need that included) ** **---------------------------------------------------------------------- */ bit Check_Button( u8 button ) { u8 pressed; pressed = FALSE; // although assigned in the switch( ), ensure it here /*------------------------------------------------------------------. ; If the selected input is TRUE, return TRUE (else FALSE) ; '------------------------------------------------------------------*/ switch( button ) { case BUTTON_LOCK: if( Lock_Signal == TRUE ) pressed = TRUE; break; case BUTTON_BEEP: if( Beep_Signal == TRUE ) pressed = TRUE; break; default: pressed = FALSE; break; } /*------------------------------------------------------------------. ; (bit) { TRUE | FALSE } ; '------------------------------------------------------------------*/ return( pressed ); } /* **====================================================================== ** main **====================================================================== ** ** The Ultra-Lame main-line routine to illustrate the [very common] ** debounce algorithm. ** **---------------------------------------------------------------------- ** ** Parameters Passed: <void> ** Parameters Returned: <void> ** Notes: ** ** This was extracted from prior artwork and NOT compiled, ** so if this doesn't compile without errors, I don't care: its ** an example of the algorithm and its usage. This algorithm ** as worked for me in the past, so it might work for you. ** **---------------------------------------------------------------------- */ void main( void ) { bit button; // for testing the state of the button /*------------------------------------------------------------------. ; Initialize the system's states ; '------------------------------------------------------------------*/ Lock_Signal = FALSE; Beep_Signal = FALSE; New_Lock = FALSE; New_Beep = FALSE; /*------------------------------------------------------------------. ; Do it forever ; '------------------------------------------------------------------*/ while( GOD_PARTICLE != FOUND ) { /*--------------------------------------------------------------. ; This is typically put into a timer ISR for a predictable dt ; '--------------------------------------------------------------*/ Delay_X_mS( KEYBOARD_DEBOUNCE_5mS_TICKS ); // you do the routine Scan_Buttons( ); /*--------------------------------------------------------------. ; Is there somebody at the door? ; '--------------------------------------------------------------*/ button = Check_Button( BUTTON_BEEP ); if( button != FALSE ) { beep( ); // Wake up the sentry } /*--------------------------------------------------------------. ; If they are to be 'buzzed in' then do it. ; '--------------------------------------------------------------*/ button = Check_Button( BUTTON_LOCK ); if( button != FALSE ) { Unlock( ); // Button must be held while opening door } else { Lock( ); // make sure it returns to the secured position } } } /*=========================================================================== * END OF MODULE ( Debounce_Example.C ) ===========================================================================*/
(if you do find errors, please let me know).
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
hmmmm...you know...there is a lot to be said for a resistor and a cap next to the switch!
R
A resistor and a cap will change the behaviour. But if the input pin doesn't have schmitt-trigger, then the bounces can still get the filtered signal to vary enough to make the input signal toggle multiple times between low and high.
As a matter of fact - all uses of external RC filters should be avoided unless the input has hysterese. Not only can you get multiple toggles, you can also get the input to consume a lot of power when floating in the dead zone between a logic high and a logic low.
Besides: A software bug can be corrected by a firmware update. A hw problem - such as too high/low value on a component - is very hard to compensate for. You may have to send the unit in for modification.
The important thing here is that most mechanical switches are quite easy to debounce since the bounce time is short in relation to the expected number of switch activations/second. And since the debounce is so easy to do in software, there is no real need to figure out ways to let the hardware help.