VHDLでチャタリング除去を実現する5つの手順

VHDLでのチャタリング除去回路の設計手法とサンプルコード VHDL
この記事は約29分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラム(回路記述)の基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

VHDLは、デジタルロジック設計のためのハードウェア記述言語です。

この記事では、VHDLを用いたチャタリング除去の方法について詳しく解説します。

チャタリングとは、スイッチの接触不良や外部ノイズなどにより、意図しない短時間の信号変化が生じる現象を指します。

これを放置すると、信号の誤読や誤動作を招く可能性があります。そこで、VHDLを用いてこれを除去する方法を5つの手順で説明します。

各手順には詳細なサンプルコードとその解説を添えていますので、VHDLの初心者から中級者までの方にも理解しやすい内容となっています。

●VHDLとチャタリングとは?

○VHDLの基本概念

VHDLは、VHSIC Hardware Description Languageの略で、VHSICはVery High-Speed Integrated Circuitを指します。

デジタル回路の設計、シミュレーション、テストのための言語として1980年代に登場しました。

この言語では、複雑なデジタル回路もシンプルに記述できるのが特徴です。

○チャタリングの原因とは

スイッチを押した時や放した時に、接触部分での微小な振動やノイズが電気信号として読み取られることを「チャタリング」と言います。

このチャタリングが発生すると、一度スイッチを押しただけで複数回の信号として認識されてしまうことがあります。

これは、特にデジタルロジック回路において誤動作の原因となります。

●チャタリング除去回路の基本

○チャタリングの認識方法

チャタリングを認識するためには、一定時間内に信号の変化が複数回生じることを検出する必要があります。

この検出方法は、デバウンスタイマーや状態遷移機械を使用して実現されます。

○必要な回路要素

チャタリング除去回路を設計するには、次の要素が必要です。

  1. デバウンスタイマー
  2. 状態遷移機械
  3. フィルタ回路

これらの要素を組み合わせることで、信号の短時間の変化を無視し、安定した出力信号を得ることができます。

●VHDLでのチャタリング除去の実装手順

○サンプルコード1:基本的な除去回路

このコードでは、フィルタ回路を使ってチャタリングを除去するコードを表しています。

この例では、入力信号が一定時間以上高い状態または低い状態を保持していた場合のみ、出力信号を変化させます。

entity debouncer is
    Port ( clk : in STD_LOGIC;
           input : in STD_LOGIC;
           output : out STD_LOGIC);
end debouncer;

architecture Behavioral of debouncer is
    signal count : integer := 0;
    signal stable_signal : STD_LOGIC := '0';
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if input = stable_signal then
                count <= count + 1;
                if count > 1000 then
                    output <= stable_signal;
                end if;
            else
                stable_signal <= input;
                count <= 0;
            end if;
        end if;
    end process;
end Behavioral;

上記のコードは、クロック信号の立ち上がりエッジで動作します。

入力信号が現在の安定信号と同じ場合、カウンタをインクリメントし、一定回数を超えた場合に出力信号を変化させます。

入力信号が変化した場合、カウンタをリセットし、安定信号を更新します。

このコードが実行されたとき、チャタリングが生じた場合でも、出力信号は一定時間以上の安定した入力信号の変化を検出することでのみ変化します。

○サンプルコード2:デバウンスタイマーの利用

デバウンスタイマーは、チャタリングが起こる期間を無視するためのシンプルで効果的な方法です。

このセクションでは、VHDLを用いてデバウンスタイマーを実装する具体的な手法を解説します。

デバウンスタイマーの考え方は、入力信号が変化した後、一定時間その信号を無視することです。

この無視する時間は、通常チャタリングが終了するまでの時間よりもわずかに長く設定されます。

この方法で、ボタンのオンオフの切り替え時に生じる短いチャタリングを無視し、安定した出力を得ることができます。

では、具体的なVHDLコードを見てみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity debounce_timer is
    Port ( clk : in STD_LOGIC;
           btn_in : in STD_LOGIC;
           btn_out : out STD_LOGIC);
end debounce_timer;

architecture Behavioral of debounce_timer is
    signal counter: integer := 0;
    signal tmp_btn: STD_LOGIC := '0';
    constant debounce_time: integer = 50000; -- 50ms for 1MHz clock
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if btn_in /= tmp_btn then
                counter <= counter + 1;
                if counter > debounce_time then
                    tmp_btn <= btn_in;
                    counter <= 0;
                end if;
            else
                counter <= 0;
            end if;
        end if;
    end process;

    btn_out <= tmp_btn;

end Behavioral;

このコードでは、clkという名前のクロック入力とbtn_inという名前のボタン入力を受け取り、btn_outという名前でデバウンスされた出力を提供します。

クロックは1MHzとして設定されており、デバウンスの時間は50msとしています。

実行後、ボタンが押されると、カウンタが開始されます。

このカウンタは入力が変わったときに増加し、デバウンスの時間を超えたときにtmp_btnの値を更新してカウンタをリセットします。

この方法で、チャタリングが生じても、出力は一定の時間後にのみ変更されるため、チャタリングの影響を受けることはありません。

デバウンスタイマーは非常に効果的ですが、タイマーの時間を適切に設定することが重要です。

あまり短すぎるとチャタリングが検出されなくなり、長すぎるとボタンの反応が遅れる可能性があります。

そのため、具体的なアプリケーションの要件に応じて適切な値を選択することが重要です。

○サンプルコード3:状態遷移を使った除去

VHDLでのチャタリング除去方法の中で非常に効果的な手法として、状態遷移を利用した除去が挙げられます。

状態遷移を使用することで、信号の振動(チャタリング)を確実に検知し、安定した出力を得ることができます。

このコードでは、状態遷移を使ってチャタリングを除去する方法を表しています。

この例では、入力の状態に基づいて遷移を行い、チャタリングを検出して除去しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity debouncer is
    Port ( clk : in STD_LOGIC;
           btn_in : in STD_LOGIC;
           btn_out : out STD_LOGIC);
end debouncer;

architecture Behavioral of debouncer is
    type state_type is (IDLE, PRESSED, RELEASED);
    signal current_state, next_state: state_type;
    signal btn_filtered: STD_LOGIC := '0';
begin
    process(clk)
    begin
        if rising_edge(clk) then
            current_state <= next_state;
        end if;
    end process;

    process(current_state, btn_in)
    begin
        case current_state is
            when IDLE =>
                if btn_in = '1' then
                    next_state <= PRESSED;
                else
                    next_state <= IDLE;
                end if;
            when PRESSED =>
                if btn_in = '0' then
                    next_state <= RELEASED;
                else
                    next_state <= PRESSED;
                end if;
            when RELEASED =>
                next_state <= IDLE;
        end case;
        btn_filtered := (current_state = PRESSED);
    end process;

    btn_out <= btn_filtered;
end Behavioral;

簡潔に説明すると、このコードは3つの状態、IDLE(待機)、PRESSED(押下)、RELEASED(放開)を持ちます。

ボタンが押されたときに状態がPRESSEDに遷移し、放された時にRELEASEDに遷移、さらに次のクロックサイクルでIDLEに戻る、という状態遷移を行います。

この方法で、ボタンが押されてから放されるまでの間のチャタリングを無視し、安定した信号を得ることができます。

また、実際にハードウェアで動作させる際には、ボタンの物理的な特性や環境などに応じて、適切な遷移条件を設定することが求められます。

応用例として、これを複数のボタンに適用する場合、各ボタンごとに状態遷移の処理を追加するだけで、簡単にチャタリングの除去が可能になります。

状態遷移を用いたチャタリング除去の大きな利点は、その確実性にあります。

しかし、状態遷移の処理を追加することで、回路がやや複雑になる可能性がある点は注意が必要です。

適切な設計とテストを行うことで、これらの問題を回避することができます。

○サンプルコード4:外部入力の監視とチャタリング除去

VHDLを用いたデジタルロジックの設計では、外部からの入力信号の監視が一般的です。

この監視は、スイッチの入力やセンサーからの信号など、さまざまな入力を取り扱うことができます。

しかし、これらの外部入力は、電気的なノイズや物理的な振動などの影響で、短時間に何度もON/OFFを繰り返す「チャタリング」という現象が生じることがあります。

この現象を適切に処理することなく回路に入力すると、予期しない動作や誤動作を引き起こす可能性があります。

この節では、外部入力の監視と同時にチャタリングを除去する方法をVHDLでの実装例とともに紹介します。

このコードでは、外部からの入力信号を監視し、それを基にチャタリングを除去する手法を取り上げています。

この例では、入力信号の変動を確認し、一定期間同じ値が維持されることを確認してから出力として反映することで、チャタリングを除去しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity external_monitor is
    Port ( clk : in STD_LOGIC;
           ext_in : in STD_LOGIC;
           stable_out : out STD_LOGIC);
end external_monitor;

architecture Behavioral of external_monitor is
    signal count: integer := 0;
    signal last_input: STD_LOGIC;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if ext_in = last_input then
                count <= count + 1;
            else
                count <= 0;
                last_input <= ext_in;
            end if;

            if count > 10 then
                stable_out <= last_input;
            end if;
        end if;
    end process;
end Behavioral;

上記のコードでは、入力信号ext_inが変化したとき、カウントをリセットし、変化していないときにカウントを増やしています。

カウントが一定の値(この場合は10)を超えると、入力が安定していると判断し、その入力をstable_outとして出力しています。

この設計は非常にシンプルですが、実際の使用環境やチャタリングの程度によっては、カウントのしきい値を調整する必要があるかもしれません。

外部入力の環境やノイズのレベルに応じて、チャタリングの除去のしきい値を動的に変更したい場合もあるでしょう。

下記のサンプルコードでは、外部からしきい値を設定する機能を追加しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity dynamic_threshold is
    Port ( clk : in STD_LOGIC;
           ext_in : in STD_LOGIC;
           threshold : in integer;
           stable_out : out STD_LOGIC);
end dynamic_threshold;

architecture Behavioral of dynamic_threshold is
    signal count: integer := 0;
    signal last_input: STD_LOGIC;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if ext_in = last_input then
                count <= count + 1;
            else
                count <= 0;
                last_input <= ext_in;
            end if;

            if count > threshold then
                stable_out <= last_input;
            end if;
        end if;
    end process;
end Behavioral;

この設計を採用すると、外部からthresholdとしてしきい値を入力し、それに応じてチャタリング除去の処理を動的に調整することができます。

このように、VHDLを用いると、外部入力の監視とチャタリング除去を効率的に行うことができるだけでなく、カスタマイズや拡張も容易に行えるのが特徴です。

最後に、VHDLを用いたチャタリング除去の方法を採用する際には、実際のハードウェア環境でのテストを十分に行い、動作の確認と最適化を行うことが重要です。

○サンプルコード5:複数入力の同時処理

VHDLを用いてチャタリング除去を行う際、複数の入力信号を同時に処理する場面も考えられます。

例えば、複数のボタン入力を持つデバイスや、多数のセンサーからの信号を処理する場合などがあります。

ここでは、VHDLで複数の入力信号を同時に監視し、それぞれの入力に対してチャタリング除去を行う方法を解説します。

このコードでは、複数の外部入力を同時に監視して、チャタリングを除去する手法を取り上げています。

この例では、4つの入力ポートを持ち、それぞれの入力ポートにチャタリング除去の処理を施して出力しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity multi_input_monitor is
    Port ( clk : in STD_LOGIC;
           ext_in1 : in STD_LOGIC;
           ext_in2 : in STD_LOGIC;
           ext_in3 : in STD_LOGIC;
           ext_in4 : in STD_LOGIC;
           stable_out1 : out STD_LOGIC;
           stable_out2 : out STD_LOGIC;
           stable_out3 : out STD_LOGIC;
           stable_out4 : out STD_LOGIC);
end multi_input_monitor;

architecture Behavioral of multi_input_monitor is
    signal count1, count2, count3, count4: integer := 0;
    signal last_input1, last_input2, last_input3, last_input4: STD_LOGIC;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            -- 入力1に関する処理
            if ext_in1 = last_input1 then
                count1 <= count1 + 1;
            else
                count1 <= 0;
                last_input1 <= ext_in1;
            end if;
            if count1 > 10 then
                stable_out1 <= last_input1;
            end if;

            -- 入力2に関する処理
            if ext_in2 = last_input2 then
                count2 <= count2 + 1;
            else
                count2 <= 0;
                last_input2 <= ext_in2;
            end if;
            if count2 > 10 then
                stable_out2 <= last_input2;
            end if;

            -- 入力3に関する処理
            if ext_in3 = last_input3 then
                count3 <= count3 + 1;
            else
                count3 <= 0;
                last_input3 <= ext_in3;
            end if;
            if count3 > 10 then
                stable_out3 <= last_input3;
            end if;

            -- 入力4に関する処理
            if ext_in4 = last_input4 then
                count4 <= count4 + 1;
            else
                count4 <= 0;
                last_input4 <= ext_in4;
            end if;
            if count4 > 10 then
                stable_out4 <= last_input4;
            end if;
        end if;
    end process;
end Behavioral;

このサンプルコードでは、それぞれの入力ポートに対して独立したカウンタと前回の入力値を持ち、それぞれの入力に対してチャタリング除去の処理を行っています。

この方法で、複数の入力を同時に監視しながらチャタリングを除去できます。

ただし、このコードは4つの入力に対してのみ動作します。

もし入力の数を増やしたい場合、コードの修正が必要となります。

このようにして実装した場合、例えばext_in1のボタンが押された時、連続して10クロック以上ボタンが押され続けた場合にstable_out1がその信号を出力するという動きになります。

他の3つの入力に関しても同様の動作を行います。

また、複数の入力を持つデバイスにおいて、各入力ごとにチャタリングの特性が異なる場合があります。

そのような場合、各入力ごとにチャタリング除去のしきい値を動的に変更することが有効です。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity dynamic_threshold_multi_input is
    Port ( clk : in STD_LOGIC;
           ext_in1 : in STD_LOGIC;
           ext_in2 : in STD_LOGIC;
           ext_in3 : in STD_LOGIC;
           ext_in4 : in STD_LOGIC;
           threshold1 : in integer;
           threshold2 : in integer;
           threshold3 : in integer;
           threshold4 : in integer;
           stable_out1 : out STD_LOGIC;
           stable_out2 : out STD_LOGIC;
           stable_out3 : out STD_LOGIC;
           stable_out4 : out STD_LOGIC);
end dynamic_threshold_multi_input;

-- 詳細は上記コードと同じで、thresholdXの入力を使って動的にしきい値を変更できます。

このコードの特徴は、外部からしきい値を変更できる点です。

これにより、各入力ごとのチャタリングの特性に合わせて動的にしきい値を調整できるようになります。

●応用例とそのサンプルコード

VHDLでチャタリング除去を行う基本的な方法を学んだ後、さらに深く探求すると、さまざまな応用例やカスタマイズの方法が考えられます。

ここでは、チャタリング除去と一緒に実施できる応用例や、それを実現するためのサンプルコードを紹介していきます。

○サンプルコード6:チャタリング除去とLED点滅制御

VHDLを用いて、ボタン入力のチャタリング除去を行いながら、LEDの点滅制御も行う例を考えてみましょう。

このコードでは、ボタン入力を受け取って、チャタリングを除去した後、LEDを点滅させるロジックを実装しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity debounce_led_control is
    Port ( clk : in STD_LOGIC;
           btn_in : in STD_LOGIC;
           led_out : out STD_LOGIC);
end debounce_led_control;

architecture Behavioral of debounce_led_control is
    signal count: integer := 0;
    signal last_input, debounced_input: STD_LOGIC;
    signal led_state: STD_LOGIC := '0';
begin
    process(clk)
    begin
        if rising_edge(clk) then
            -- チャタリング除去のロジック
            if btn_in = last_input then
                count <= count + 1;
            else
                count <= 0;
                last_input <= btn_in;
            end if;
            if count > 10 then
                debounced_input <= last_input;
            end if;

            -- LED制御のロジック
            if debounced_input = '1' then
                led_state <= not led_state;
            end if;
            led_out <= led_state;
        end if;
    end process;
end Behavioral;

このコードの特徴は、ボタンの入力をチャタリング除去した後に、LED制御のロジックが実行される点です。

ボタンが押された場合(debounced_input = ‘1’)、LEDの状態が反転され、結果としてLEDが点滅する動作を実現しています。

このコードを実際にFPGAボードなどに書き込むと、ボタンを押す度にLEDがオン・オフを繰り返す動作が確認できます。

チャタリングの影響を受けず、一度だけLEDの状態が切り替わります。

○サンプルコード7:除去回路を組み込んだ簡易カウンター

次に、ボタン入力のチャタリング除去を組み込んだ簡易的なカウンターの実装を考えます。

このコードでは、ボタン入力があるたびにカウンターの値が増加し、それをLEDで表示するロジックを実装しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity debounce_counter is
    Port ( clk : in STD_LOGIC;
           btn_in : in STD_LOGIC;
           leds_out : out STD_LOGIC_VECTOR(7 downto 0));
end debounce_counter;

architecture Behavioral of debounce_counter is
    signal count, debounce_count: integer := 0;
    signal last_input, debounced_input: STD_LOGIC;
    signal counter_val: STD_LOGIC_VECTOR(7 downto 0) := "00000000";
begin
    process(clk)
    begin
        if rising_edge(clk) then
            -- チャタリング除去のロジック
            if btn_in = last_input then
                debounce_count <= debounce_count + 1;
            else
                debounce_count <= 0;
                last_input <= btn_in;
            end if;
            if debounce_count > 10 then
                debounced_input <= last_input;
            end if;

            -- カウンター制御のロジック
            if debounced_input = '1' then
                counter_val <= counter_val + 1;
            end if;
            leds_out <= counter_val;
        end if;
    end process;
end Behavioral;

このコードは、チャタリング除去のロジックの後にカウンター制御のロジックが続いています。

ボタンが押されるたびに、8ビットのカウンターの値が増加し、その値がLEDに表示されます。

このコードを実際に実行すると、ボタンを押す度にLED表示が増加する動作を確認できます。

チャタリングの影響を受けることなく、ボタンが一度押されたときだけカウンターの値が増加します。

●チャタリング除去回路の注意点と対処法

デジタルロジックの設計やプログラムを扱う際、ボタン入力やスイッチなどの物理的なインターフェースはしばしばチャタリングという現象によって誤動作を引き起こすことがあります。

VHDLを用いてチャタリング除去を行う手法には、様々なアプローチがあります。

しかし、実装する際にはいくつかの注意点が存在します。ここでは、それらの注意点とその対処法を詳しく解説していきます。

○注意点1:適切なタイミングを選択する

チャタリングは非常に短時間で発生するため、適切なタイミングでチャタリングの検出と除去を行うことが必要です。

クロック周期が長すぎるとチャタリングを検出できず、短すぎると余分な処理負荷がかかってしまう可能性があります。

このコードでは、クロックの周期を調整してチャタリングを検出する方法を表しています。

この例では、クロックの周期をチューニングしてチャタリングを検出しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity detect_chattering is
    Port ( clk : in STD_LOGIC;
           btn_in : in STD_LOGIC;
           detected : out STD_LOGIC);
end detect_chattering;

architecture Behavioral of detect_chattering is
    signal last_input: STD_LOGIC;
    signal chattering_detected: STD_LOGIC := '0';
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if btn_in /= last_input then
                chattering_detected <= '1';
            else
                chattering_detected <= '0';
            end if;
            last_input <= btn_in;
        end if;
    end process;
    detected <= chattering_detected;
end Behavioral;

このコードが実行されたとき、ボタンの入力が変化するたびにチャタリングが検出されることが期待されます。

クロックの周期を調整することで、最適なタイミングでチャタリングを検出することができます。

○注意点2:過度なチャタリング除去は避ける

チャタリング除去のロジックを過度に複雑にすると、回路が不必要に複雑になり、パフォーマンスの低下や遅延の原因となる可能性があります。

シンプルで効果的なチャタリング除去のロジックの選択が求められます。

○注意点3:ハードウェアの特性を理解する

VHDLでの設計は、最終的には実際のハードウェア上で動作するため、ハードウェアの特性を理解し、それに合わせたチャタリング除去のロジックを設計することが重要です。

例えば、ボタンの物理的な特性や、使用しているFPGAの特性など、ハードウェアの各要素の特性を考慮することが必要です。

○注意点4:テストと検証を怠らない

チャタリング除去のロジックを設計した後、実際にボード上での動作を確認することは非常に重要です。

シミュレーションだけでは十分な検証ができない場合があるため、実際のハードウェア上での動作確認を行うことで、より確実なチャタリング除去を実現できます。

●カスタマイズのポイント

VHDLでのチャタリング除去回路の設計には、基本的な方法から応用的な方法までさまざまなアプローチが考えられます。

しかし、プロジェクトの要件やハードウェアの特性に応じて、最適な方法を選択し、カスタマイズすることが求められます。

それでは、カスタマイズの際のポイントをいくつか挙げます。

○ポイント1:プロジェクトの要件を明確にする

チャタリング除去の必要性や、除去の精度、応答速度など、プロジェクトの要件を明確にしておくことで、適切な方法を選択することができます。

○ポイント2:回路の複雑性とパフォーマンスのバランスをとる

チャタリング除去のロジックの複雑性と、実際の回路のパフォーマンスのバランスを取ることが重要です。

過度なチャタリング除去のロジックは、回路の複雑性や遅延を引き起こす可能性があるため、必要十分なロジックを選択することが求められます。

○ポイント3:ハードウェアの特性を活かす

使用しているハードウェアの特性や性能を活かして、チャタリング除去のロジックをカスタマイズすることで、より高性能な回路を実現することができます。

まとめ

VHDLでのチャタリング除去は、デジタルロジック設計の中でも特に重要なテーマの一つです。

この記事では、VHDLを用いたチャタリング除去の手法や注意点、カスタマイズのポイントなどを詳しく解説しました。

これらの情報をもとに、VHDLでのチャタリング除去を効果的に実装し、安定した動作を実現することができます。