Translate

Tuesday, December 18, 2012

Deouncing push buttons




       Hello and welcome back to FPGA Tutorials. In this post I will explain everything about how to use push buttons. If you want to see the basics of FPGA I/O including buttons please visit an older post of mine entitled: Link FPGA I/O to entity I/O.
       Ok. So basically a button sends one of 2 values depending on it's status. Usually if it is pressed it will send back a logic '0' and if it is unpressed, a logic '1' (all FPGAs and other dev boards I have worked with have buttons configured like this). There may be a chance that your FPGA dev board has the logic inverted, meaning that the button will output a '1' if pressed. Tis can be tested by making a simple circuit that links a button to a LED (led <= button) and if the led lights up when the button is unpressed then it has the usual logic. Vice versa it has the inverted one. My development board is a Digilent Nexys 3 so if you have this one you can sleep easily because the buttons are configured as I explained in this and the other post (pressed -> '0', unpressed -> '1').

      Let's get back to business. I want to develop a simple circuit that uses a LED and a push button and every time the button is pressed, the led changes it's state (from '0' to '1' or off to on and vice versa). Well this seems simple enough: we just negate the led every time the buttons sends a '0'. So the entity would have an input (the button) and an output (the led) and the code would be something like this:

              signal l : std_logic;

              process(button)

              begin
                 if(button'event and button='0') then
                    l<=not l;
                 end if;
              end process;
              led <= l;

       You can check that code if you want to but before doing it I have to confess something: it won't work as expected. When you press the button you will notice that sometimes the led doesn't change it's state and other times it changes it's state several times for one button press. This phenomenon is called bounce and it happens because when a button is pressed or released the transition from one state to the other has some intermediate states that will be considered a press or a release. So when you press the button the led may change states several times before it settles. The same thing happens when releasing the button. The procedure used to "clean" the signal is called debouncing. A bounce can be represented like in the following picture:

 

       Debouncing will be done through a circuit designed specially for this and it will be done at a button press and at a release. The basic idea is the following: we need to detect if the button has been pressed. If so then the circuit waits 10 milliseconds in order for the signal to get clean. After the 10 ms, if the button is still pressed we have a valid press operation. Now we have to wait for the button to be released. When this happens, The bounce is filtered out by waiting another 10 ms and the circuit checks again if the button is still released. If so then the release operation is valid. The flowchart below describes this process:


       This flowchart translates into VHDL in the following way: the whole debounce will be done in a process that is synchronized with the board's oscillator. The counter is represented by a 20 bit variable that counts from 0 to 999999 assuring the division of my 100 MHz clock to 100 HZ or 10 ms. Every time when entering the process we'll check to see if the input (the button) is the same as it's old value. If not then the counter is reset to 0 and the old value of the button is updated. If the input is of the same value as the old value then the counter is incremented then a check of it's value is done. If the counter reaches 999999 and the input has the same value as the old one then button gets that value.
       This way we are assured that the debouncing happens at a press and a release and any invalid press/release operations is filtered out.

       The resulting circuit will have as inputs the button and the global clock and as outputs the cleansed button signal.
       
         The entity declaration looks like this:
     
     
        In order for the code to work you need the following library:
           use IEEE.STD_LOGIC_UNSIGNED.all;

       The code is he following:
 
 
       This circuit can be used in any project by just placing it between a button and the input the button controls. To see how it can fit in a project we will continue our led circuit. We want to change the status of the led when the button is pressed. Now that the button works correctly we need a led driver that changes it's status when needed. This is done in exactly the same way we did the blinking led in a previous post of mine named: Synchronization in sequential circuits (clock dividers).

       So the entity is done like this:
       I will let you figure out the code for yourself. Hint: the deb entity replaces the div entity from my other post. Good luck.
       If you have any questions or suggestions please email me at:fpgatutorials@gmail.com
       Thanks for reading.     













1 comment:

  1. Why you use hexadecimal for "if((cnt=x"F423F")..." instead of decimal or logic?

    ReplyDelete