Thursday, October 14, 2010

Debounce Machine! A state approach.

UPDATES IN RED at: 12-11-2010

Reading HackaDay, just can't let to present my debounce routine.
Make my interpretation of it at 2007 with PIC programming.
I start build my debounce routine with a state machine approach.
This way the routine can be solid as stone.(I think least)
And was much more easier to accomplish the right behavior that I wait for.
More, my implementation doesn't force delays, is pretty simple and straight-out - use few bytes of program.
Many keys can be debounced with minimum amount of memory.
Just one byte per key; or less; even a nibble can be used.
And can be combined on a already existent code and interrupt routine.
As I saw on other sites ahead hackaday, it is a low pass filter too.

Below the schematic of all thing.

Created with DiaPortable.

This state machine can be implemented in various ways.
The actual implementation work checking and changing the state on every interrupt (if need).
I prefer compass everything at 5ms interrupt at my routines (due the use I am making).
However if you use a more fast interrupt routine, don't worry, since you may DEFINE the HIGH boundary with a bigger number.
With 4 states (above machine), and 5ms INTs, it can debounce a key in 20ms.
This debounce can be easily converted into code using (I use this way, you are free to chose whatever you want):

  • a variable to register the state of each key that need to be debounced.
  • a variable to register the final status of the key(or just a bit)
  • DEFINE a CONSTANT to HIGH BOUNDARY (1 - 255, how many states you need - this number create the same number of states on each side of diagram)
It need just 2 variables to hold all data and a routine!

Isn't show at picture, but  think and assign to each bullet a number, starting from left to right, from 0 to HIGH. The same with below bullets.

As can be seen on state diagram, a positive or valid signal on monitored PIN will cause the state to increment.
A ZERO cause it to decrement the state (state counter variable).
If the counter was BIGGER or EQUAL than HIGH boundary, then the state register change this value meaning a active PIN and the state doesn't increment more.
If the monitored PIN goes LOW, so the state decrements until reach ZERO.
When this happen, the register is set to ZERO, meaning a inactive PIN and the state stay there too.
I implement this debounce using PIC Assembler, and the code are inside a huge amount of other things.
Below a quickly C version build . I think it can work without major changes.
Better would be change it to work like a function.
Also, I am using two IF inside each state change due I don't know how char will suffer with negative numbers.

// Hernandi Krammes - its me - chico
// 10-14-2010 - use with care! 

#DEFINE HIGH 8    // 8 states between changes 8*5ms = 40ms

char keyA_state;
char keyA;    // 0-1 - need just a bit - use whatever you want

ISR(){    // Interrupt Service Routine

          //   for me at 5ms or anything else

    // key debounce
    char tmp;    // just to hold the state of key
    tmp = getPin(pinA);

   // Pls, use a comparation that recognize the right pin state

   // I think that an LOGICAL AND should be a better approach
   // Let me say, bit 2 is the desired PIN
   // so the PINFILTER should be 'b00000010'
   // and the result will be 0 or 1 and the
   // state machine will work nice
   // Thanks to underwood from german that warm me
   // that the code seens to not work
   // I think that is because this
   // Beyond, code shoud work with any microcontroller
   // PIC, Atmel(AVR), etc
   if (!(tmp AND PINFILTER)){ //old mode deprec. (tmp == 0)
        if(keyA_state == 0) keyA = 0;
        else keyA_state--;
        if(keyA_state == 0) keyA = 0; 
    }else{  // tmp = 1
        if(keyA_state == HIGH) keyA = 1;
        else keyA_state++;
        if(keyA_state == HIGH) keyA = 1;
    // ready! the rest int code goes here
// There is it. I hope that this could help someone!

Let your comment.


underwood said...

Hello, doesn't work for me. I have raised HIGH to 20 and called the IRS only every 8ms.

chico said...

Hi underwood.
This is just a basic scope.
I am sure you implement all the rest and inicalize the variables (0), and your routine is getting right the IOPINDATA, and you are doing the right OR and AND logic operation to detect 0 or 1 on incoming data.
I am usign such algoritm implemented at pic ASM, and is light and operational.
I dont know how this routine will behave with char; maybe try use unsigned char and dont forget initialize it to 0(zero).
LEt me know if it work for you.

chico said...

Still, look that in the code:
if (tmp == 0){
if(keyA_state == 0) keyA = 0;
I am using exacly == 0 (equal ZERO). if your pin data (second) 2° bit, so your input will be always 00000010, that means = 2 in decimal, and never will ==1, and the code will ot work.
Make sure, as I say, to use the right AND and OR and plus the RIGHT(I mean precise) comparation, or try use >=; or even a LOGIC AND compatation, that take few cycles from CPU. The concept, as you can see is very simple. I think, in my opinion, is very light and efective. Actualy I am debouncing with it signals at 5ms rate given a total of 20ms to rise up or down.

underwood said...

thanks for the fast answer. i have used the code again that is listed here (Listing 2):

works in most circumstances but needs loots of tweaking and trying if you change the time of the irs calls or use different switches.

for the next pic project, I'll try your code again.

tamil vanan said...
This comment has been removed by the author.
tamil vanan said...

Hi Chico,

Thanks for sharing your Debounce machine code. I can understand the code. Could you explain me the state machine diagram. i could n't understand it .



Hernandi Krammes said...

Helli Tamil
It is very easy to understand.
The outside numbers represent the signal that come form the input pin, with noise, sampled in a continuous rate preferably. The numbers inside the circles, represent the signal to be returned as active signal debounced. The start state is pointed by the arrow. If the signal do not stay in one for long time enough, (in the exemple picture, 4 cicles) the out signal never goes to 1; else if the signal become one for a time longer that 4 circles, the out become 1 and just get zero again then it stay in zero for time long enough. To test, draw a simple graph with a noise signal and test the signal follow inside the graph.
You will see how it work, in a easy manner.