This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Debounce Logic

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

  • how did you implement "delay_10micro_sec" ?

  • Hmm, I can see a few problems with the above code.
    First, the debounce algorithm. If I understand correctly, you are going to take 3 samples of the input with 10-microsecond intervals, then make a majority decision. Normally, when you deal with mechanical contacts, you would want 10 milliseconds instead of 10 microseconds. And 3 samples doesn't sound like enough. More importantly, these two parameters (number of samples and time interval) must be chosen based on the typical behaviour of your system. That is, you should look at scope traces first.
    Second, the code looks sloppy. Variable naming is inconsistent. Types like 'uint16_t' and 'char' are intermixed. The array SHIFT_RESULT[] is not initialized properly. Indentation is extremely wobbly. And so on...

  • 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???

    Erik

  • 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;
    }