Kampis Elektroecke

Taster entprellen

In diesem Artikel zeige ich, wie ein Taster an ein FPGA angeschlossen und entprellt werden kann. Die Funktionsweise der Entprellschaltung ist ähnelt der Funktionsweise eines MAX6817, welcher speziell für das Entprellen von Tastern entwickelt worden ist.

Was ist überhaupt “Prellen”?:

Bedingt durch den Aufbau von Tastern kommt es vor, dass ein Taster beim Betätigen nicht sauber geschaltet wird, sondern im inneren für kurze Zeit hin- und her federt. Dadurch ergibt sich beim Schalten eines Tasters kein einzelnes, sauberes Signal, sondern es bildet sich eine Reihe von Impulsen, die nach einer Prellzeit tP verschwinden.

Digitale Schaltungen, wie FPGAs oder Mikrocontroller, nehmen dieses mehrere Millisekunden andauernde Prellen als mehrmaliges Betätigen des Tasters wahr, weshalb sich das ausgeführte Programm oder die Schaltung u. U. möglicherweise merkwürdig verhalten (z. B. weil ein Zähler nicht immer nur einen Schritt zählt, sondern unterschiedlich viele).

Eine einfache Möglichkeit um Prellen zu unterdrücken besteht in der Verwendung eines RC-Gliedes. 

Bei dieser Schaltung macht man sich den Umstand zu Nutze, dass an einem Kondensator die Spannung nicht sprunghaft ansteigen, bzw. abfallen kann, sondern einer Exponentialfunktion folgt. Solange der Taster geöffnet ist, wird der Kondensator geladen. Die nachgeschaltete Logik erkennt erst dann einen High-Pegel, wenn die Spannung an dem Kondensator eine bestimmte Schwelle überschreitet. Wird der Taster betätigt, so entlädt sich der Kondensator langsam über den Widerstand R2, wodurch die Spannung am Kondensator abfällt. Sobald ein bestimmter Schwellwert erreicht wird, erkennt die nachgeschaltete Logik einen Low-Pegel.

Der Nachteil an dieser (und an anderen externen Lösungen) ist, das zusätzliche Bauelemente benötigt werden, was bei kleinen Schaltungen eventuell unerwünscht ist. Aus diesem Grund wird das Entprellen in das FPGA verlagert. 

Entprellschaltung für das FPGA:

Die Entprellung des Tasters erfolgt soll über einen Zähler realisiert werden. Dazu wird ein externes Taktsignal benötigt, mit dem die Schaltung dann die Dauer der eingehenden Impulse zählen soll. Erst wenn die Impulsdauer eine bestimmte Zeit überschritten hat wird das Signal des Tasters an den Ausgang der Schaltung gelegt.

Werfen wir mal einen Blick auf das Debounce-Modul…

entity Debounce is
    Generic (   BOUNCETIME : INTEGER
                );
    Port (  Clock    : in  STD_LOGIC;
            ResetN   : in STD_LOGIC;
            Input    : in  STD_LOGIC;
            Output   : out STD_LOGIC
            );
end Debounce;

architecture Debounce_Arch of Debounce is

   signal Debounce_Counter  : INTEGER := 0;
   signal Input_Debounce    : STD_LOGIC := '0';
   
begin

    process
    begin
        wait until rising_edge(Clock);

        if(ResetN = '0') then
            Debounce_Counter <= 0;
        else
            if(Input = Input_Debounce) then
                Debounce_Counter <= 0;
            else
                Debounce_Counter <= Debounce_Counter + 1;
            end if;
        end if;
        
        if(Debounce_Counter = BOUNCETIME) then
            Debounce_Counter <= 0;
            Input_Debounce <= Input;
        end if;
    end process;
    
    Output <= Input_Debounce;

end Debounce_Arch;

Das Modul besitzt zwei Eingänge, einen für das nicht entprellte Taster-Signal und einen für den Takt, sowie einen Output für das entprellte Taster-Signal. Zudem wird noch ein Integerwert in das Modul übergeben, mit dem die Prellzeit in Taktzyklen angegeben wird.

Bei jeder steigenden Taktflanke prüft das FPGA ob der Eingangspin für den Taster den selben Zustand hat wie das Signal InputState:

  • Eingangspin führt den selben Zustand:
    Taster wurde nicht betätigt. DebounceCounter wird auf 0 gesetzt.
  • Eingangspin hat einen anderen Zustand:
    Taster wurde betätigt. DebounceCounter wird um 1 erhöht.

Der oben beschriebene Vorgang wiederholt sich nun solange, bis das Signal DebounceCounter und die Konstante BOUNCETIME gleich groß sind. Sobald dies eintritt, wird DebounceCounter gelöscht und das Signal InputState, welches den aktuellen Zustand des Eingangs speichert, wird auf den Zustand des Eingangs gesetzt. Das Eingangssignal ist jetzt entprellt.

Anschließend kann das Modul verwendet werden:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Top is
    Port (  Bounce_In    : in STD_LOGIC;
            ResetN       : in STD_LOGIC;
            Clock        : in STD_LOGIC;
            Debounce_Out : out STD_LOGIC
            );
end Top;

architecture Top_Arch of Top is
    
   component Debounce 
        Generic (   BOUNCETIME : INTEGER 
                    );
        Port (  Clock    : in  STD_LOGIC;
                ResetN   : in STD_LOGIC;
                Input    : in  STD_LOGIC;
                Output   : out STD_LOGIC
            );
   end component;

begin                       

    Button_1 : Debounce generic map (   BOUNCETIME => 20
                                        )
                        port map (  Input => Bounce_In,
                                    ResetN => ResetN,
                                    Output => Debounce_Out, 
                                    Clock => Clock
                                    );
end Top_Arch;

Der Quellcode kann in meinem Git-Repository heruntergeladen werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.