VHDLで簡単に作るストップウォッチの10選

VHDLでのストップウォッチ作成方法を詳細に説明するイメージ VHDL
この記事は約39分で読めます。

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

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

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

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

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

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

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

はじめに

最近、VHDLを用いたデジタル回路設計がますます注目されています。

特に、実用的なアプリケーションとして、ストップウォッチの実装は多くのエンジニアや学生にとって興味深いトピックです。

この記事では、初心者向けにVHDLでストップウォッチを簡単に作る10の方法を徹底的に解説します。

それぞれの方法には、具体的なサンプルコードと詳細な説明が付属していますので、安心して取り組むことができます。

●VHDLとは

VHDLは、デジタル回路の設計やシミュレーションに使用されるハードウェア記述言語です。

その名前は、VHSIC Hardware Description Languageの略で、VHSICは「非常に高速な集積回路」を意味します。

○VHDLの基本

VHDLは、エンティティ、アーキテクチャ、プロセスなどの基本的な概念を持っています。

エンティティは回路の入出力を定義する部分で、アーキテクチャはその動作を記述する部分です。

プロセスは、アーキテクチャ内で並行に動作する部分的な動作を記述するためのものです。

●ストップウォッチの概念とは

ストップウォッチは、特定の時間を計測するためのデバイスです。

開始ボタンを押すと計測が始まり、停止ボタンを押すとその時点の経過時間が表示されるシンプルな仕組みですが、さまざまな応用が考えられます。

●VHDLでのストップウォッチの作り方

○サンプルコード1:基本的なストップウォッチ

このコードでは、VHDLを使って最も基本的なストップウォッチを作成する方法を紹介しています。

この例では、スタートボタンとストップボタンを使って時間を計測しています。

entity stopwatch is
    Port ( clk : in STD_LOGIC;
           start : in STD_LOGIC;
           stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           time : out INTEGER);
end stopwatch;

architecture Behavioral of stopwatch is
    signal count : INTEGER := 0;
    signal run : BOOLEAN := FALSE;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                count <= 0;
                run <= FALSE;
            elsif start = '1' then
                run <= TRUE;
            elsif stop = '1' then
                run <= FALSE;
            end if;
            if run = TRUE then
                count <= count + 1;
            end if;
            time <= count;
        end if;
    end process;
end Behavioral;

このコードには、スタート、ストップ、リセットの各ボタンと、経過時間を示すtimeという出力が含まれています。

startボタンが押されると計測が始まり、stopボタンが押されると計測が止まります。

resetボタンを押すと、経過時間が0に戻ります。

このストップウォッチを動作させると、timeはクロックの立ち上がりエッジごとに1ずつ増加し、ストップボタンが押されるか、リセットボタンが押されるまでその動作を続けます。

○サンプルコード2:ラップタイム機能付きストップウォッチ

ストップウォッチを使用する際に、特にスポーツや実験などの計測時に役立つのが「ラップタイム」の機能です。

この機能によって、各ラップごとの時間を記録しながら、全体の時間も計測し続けることができます。

VHDLを利用して、このラップタイム機能を持ったストップウォッチを作成する方法について見ていきましょう。

このコードではVHDLを使ってラップタイム機能を持ったストップウォッチの基本的なロジックを構築しています。

この例ではクロック信号を元に時間をカウントし、指定のボタンが押された際にラップタイムをメモリに保存しています。

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

entity LapStopwatch is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           lap_button : in STD_LOGIC;
           time : out STD_LOGIC_VECTOR(31 downto 0);
           lap_time : out STD_LOGIC_VECTOR(31 downto 0));
end LapStopwatch;

architecture Behavior of LapStopwatch is
    signal counter : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
    signal running : STD_LOGIC := '0';
    signal last_lap_button : STD_LOGIC := '0';
begin
    process(clk, reset)
    begin
        if reset = '1' then
            counter <= (others => '0');
            running <= '0';
        elsif rising_edge(clk) then
            if start_stop = '1' then
                if running = '0' then
                    running <= '1';
                else
                    running <= '0';
                end if;
            end if;

            if running = '1' then
                counter <= counter + 1;
            end if;

            -- ラップタイムの記録
            if lap_button = '1' and last_lap_button = '0' then
                lap_time <= counter;
            end if;
            last_lap_button <= lap_button;
        end if;
    end process;

    time <= counter;
end Behavior;

上記のサンプルコードでは、start_stop ボタンでストップウォッチの開始・停止を制御し、lap_button で現在のカウント時間をlap_time として出力します。

ラップタイムは、ボタンが押された瞬間のカウント値を保存しておき、それを出力として提供します。

このプログラムをFPGAボードに書き込んで実行すると、ストップウォッチが動作し始め、指定のボタンを押すことでラップタイムを記録できるようになります。

ラップタイムを記録するためのボタンが押されると、その時点でのカウント時間がlap_time 出力に反映されます。

この機能により、例えばランニングなどのスポーツの計測時に、各ラップごとの時間を簡単に確認することができます。

次に、このストップウォッチの実行結果について説明します。ボタンを押すことでストップウォッチは開始し、再度押すことで停止します。

ラップタイムボタンが押されると、その時点での経過時間が保存され、後から確認できるようになります。

例えば、100秒後にラップボタンを押した場合、lap_timeとして100秒が出力されます。

このラップタイム機能を持ったストップウォッチは、多くのアプリケーションで利用されています。

特に競技や実験など、複数の段階ごとの時間を記録したい場合に非常に便利です。

VHDLを利用してこのようなデバイスを自作することで、必要に応じてカスタマイズしたり、他の機能と組み合わせたりすることができます。

○サンプルコード3:アラーム機能付きストップウォッチ

VHDLでのストップウォッチ作成を学ぶ中で、アラーム機能は非常に役立つものです。

特定の時間が経過したことを知らせるこの機能は、タイムマネジメントの際や特定のタスクを時間内に完了させるために有用です。

このコードではVHDLを使ってアラーム機能を持ったストップウォッチを紹介しています。

この例では、一定の時間が経過したらアラームを鳴らす機能を持ったストップウォッチを作成しています。

-- ライブラリのインクルード
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- エンティティの宣言
entity stopwatch_with_alarm is
    Port ( clk : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           time_out : out STD_LOGIC_VECTOR(31 downto 0);
           alarm : out STD_LOGIC);
end stopwatch_with_alarm;

architecture Behavioral of stopwatch_with_alarm is
    signal count : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
    signal alarm_time : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000111001000"; -- ここでアラーム時間を設定
    signal enable : STD_LOGIC := '0';
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= (others => '0');
            enable <= '0';
        elsif rising_edge(clk) then
            if start_stop = '1' then
                enable <= not enable;
            end if;
            if enable = '1' then
                count <= count + 1;
                if count = alarm_time then
                    alarm <= '1';
                else
                    alarm <= '0';
                end if;
            end if;
        end if;
    end process;

    time_out <= count;

end Behavioral;

このVHDLコードでは、ストップウォッチの基本的な動作と、一定の時間(alarm_time)が経過したらアラーム(alarm)を鳴らす機能を組み合わせています。

ストップウォッチはstart_stop入力で開始・停止を切り替えることができ、reset入力でカウントをリセットすることができます。

具体的にこのコードを実行すると、指定されたalarm_timeの時間が経過するとalarm出力が’1’になり、アラームとして利用できる信号が出力されます。

この時点で外部のデバイスやスピーカーに接続してアラーム音を鳴らすことが考えられます。

さらにこのコードのカスタマイズとして、alarm_timeの値を変更することで異なる時間にアラームを鳴らすことができます。

例えば、15分後や30分後にアラームを鳴らすようなタイマーとしても利用可能です。

このアラーム機能を持ったストップウォッチの実装方法を理解し、VHDLでのハードウェア記述の基本を掴むことができれば、さらに高度な機能やデザインを追加して独自のストップウォッチを作成することも可能です。

○サンプルコード4:カウントダウン機能付きストップウォッチ

ストップウォッチの応用例として、カウントダウン機能付きのものを考えることができます。

このコードでは、VHDLを用いてカウントダウンが可能なストップウォッチを実装しています。

この例では、指定した時間からカウントダウンを開始し、0になったらアラームが鳴る機能を持っています。

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

entity countdown_stopwatch is
    Port ( clk : in STD_LOGIC;
           start : in STD_LOGIC;
           reset : in STD_LOGIC;
           alarm : out STD_LOGIC;
           time_left : out STD_LOGIC_VECTOR(15 downto 0));
end countdown_stopwatch;

architecture Behavioral of countdown_stopwatch is
    signal count : STD_LOGIC_VECTOR(15 downto 0) := "0000000011111111"; -- 15秒としています。
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= "0000000011111111"; -- 15秒
            alarm <= '0';
        elsif rising_edge(clk) then
            if start = '1' then
                if count > "0000000000000000" then
                    count <= count - 1;
                else
                    alarm <= '1';
                end if;
            end if;
        end if;
    end process;

    time_left <= count;
end Behavioral;

このコードでは、countdown_stopwatchという名前のエンティティを宣言しています。

また、外部からの入力としてクロック信号clk、開始信号start、リセット信号resetを受け取り、出力としてアラーム信号alarmと残り時間を示すtime_leftを持っています。

アーキテクチャBehavioralの中で、カウントダウンの実処理が行われます。

初期値として15秒(ここではビットを表しています)が設定されており、start信号が1になった時にカウントダウンを開始します。

そして、カウントが0になったらalarm1になるようにしています。

このカウントダウン機能は、例えば調理のタイマーとして使用することが考えられます。

指定した時間だけ待機し、時間が来たら通知を出す、というシンプルながらも非常に便利な機能です。

実際にこのコードを実装した際、15秒後にalarm1になることを確認できます。

また、time_leftの値をモニタリングすることで、残り時間をリアルタイムで確認することが可能です。

○サンプルコード5:ストップウォッチのスタイル変更

VHDLを使用して、ストップウォッチのディスプレイやフォントのスタイルを変更する方法について詳しく紹介していきます。

このコードでは、VHDLの内部信号やプロセスを利用して、ストップウォッチの見た目をカスタマイズすることが可能です。

この例では、フォントの大きさや色、背景色を変更して、オリジナルのデザインのストップウォッチを作成しています。

-- スタイル変更可能なストップウォッチのサンプルコード
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Stopwatch_Style is
    Port ( clk : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           display : out STD_LOGIC_VECTOR(7 downto 0);
           style_select : in STD_LOGIC_VECTOR(2 downto 0); -- スタイル選択のための入力
           style_out : out STD_LOGIC_VECTOR(7 downto 0) ); -- スタイル適用後の出力
end Stopwatch_Style;

architecture Behavioral of Stopwatch_Style is
    signal count : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
    -- スタイル設定 (ここでは簡易的にフォントのビットマップを示しています)
    signal styles : array(0 to 7) of STD_LOGIC_VECTOR(7 downto 0) := (
        "01100110", "01101101", "00111111", "01011011",
        "01001111", "01110000", "00110001", "01101111"
    );
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                count <= "00000000";
            elsif start_stop = '1' then
                count <= count + 1;
            end if;
        end if;
    end process;

    display <= count;

    process(style_select, count)
    begin
        style_out <= styles(to_integer(style_select)) xor count;
    end process;
end Behavioral;

このコードでは、style_selectという3ビットの入力を使って、8つの異なるスタイルから一つを選択します。

選択されたスタイルは、stylesという配列で定義されており、style_outとして出力される数字のビットマップを変更しています。

例えば、style_selectが”000″のときは、一番最初のスタイルが選択され、style_outはそのスタイルに応じたディスプレイの出力が得られます。

そして、style_selectの値を変更することで、異なるスタイルのストップウォッチのディスプレイが得られるようになっています。

この方法で、VHDLを使って簡単にストップウォッチのスタイルを変更することができます。

独自のスタイルやデザインを追加する場合は、styles配列に新しいビットマップを追加して、style_selectの入力値を変更するだけです。

また、このサンプルコードの実行後、ストップウォッチのディスプレイは、選択されたスタイルに応じて変わることが確認できます。

具体的には、style_selectの値を変更すると、その値に対応するスタイルのディスプレイが得られることが期待されます。

○サンプルコード6:マルチウィンドウストップウォッチ

VHDLを用いることで、複数のストップウォッチを同時に表示するマルチウィンドウストップウォッチを作成することができます。

このコードでは、2つのストップウォッチを同時に動作させる方法を表しています。

この例では、主ウィンドウとサブウィンドウでそれぞれ異なるストップウォッチを管理しています。

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

entity multi_window_stopwatch is
    Port ( clk : in STD_LOGIC;
           start_main : in STD_LOGIC;
           start_sub : in STD_LOGIC;
           reset : in STD_LOGIC;
           main_time : out STD_LOGIC_VECTOR(31 downto 0);
           sub_time : out STD_LOGIC_VECTOR(31 downto 0));
end multi_window_stopwatch;

architecture behavior of multi_window_stopwatch is
    signal main_counter, sub_counter : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                main_counter <= (others => '0');
                sub_counter <= (others => '0');
            elsif start_main = '1' then
                main_counter <= main_counter + 1;
            elsif start_sub = '1' then
                sub_counter <= sub_counter + 1;
            end if;
        end if;
    end process;

    main_time <= main_counter;
    sub_time <= sub_counter;
end behavior;

このVHDLコードでは、start_mainstart_subの2つの入力を使用して、それぞれのストップウォッチを開始します。

同様に、reset入力を使用して、両方のストップウォッチをリセットすることができます。

このコードの特徴として、主とサブの2つのストップウォッチを独立して制御できる点が挙げられます。

このコードを適用することで、2つのイベントやアクティビティを同時に計測することができるようになります。

例えば、スポーツのトレーニング中に、主要なアクティビティの時間と休憩時間を別々に計測する際などに役立ちます。

このマルチウィンドウストップウォッチを使うと、例としてトレーニング時間をメインのストップウォッチで計測し、休憩時間をサブのストップウォッチで計測するという使い方が考えられます。

注意点として、このコードでは時間の進行速度を調整する機能は提供していません。

クロックの周波数によって、1秒ごとの増加速度が変わることを考慮してください。

○サンプルコード7:音声出力機能付きストップウォッチ

音声出力機能を持つストップウォッチは、一定の時間が経過した際やタイマーの終了をユーザーに知らせる際に非常に便利です。

特に視界が制限されている状況や、目を使わないシチュエーションでの使用に最適です。

ここでは、VHDLを用いて音声出力機能を持つストップウォッチの作成方法について詳しく解説します。

-- 音声出力機能付きストップウォッチのサンプルコード
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Stopwatch_with_Sound is
    Port ( clk : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           alarm_time : in integer;
           time_out : out integer;
           sound_signal : out STD_LOGIC);
end Stopwatch_with_Sound;

architecture Behavioral of Stopwatch_with_Sound is
    signal count : integer := 0;
    signal is_running : STD_LOGIC := '0';
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= 0;
            is_running <= '0';
        elsif rising_edge(clk) then
            if start_stop = '1' then
                if is_running = '0' then
                    is_running <= '1';
                else
                    is_running <= '0';
                end if;
            end if;

            if is_running = '1' then
                count <= count + 1;
            end if;

            if count = alarm_time then
                sound_signal <= '1';
            else
                sound_signal <= '0';
            end if;
        end if;
    end process;

    time_out <= count;
end Behavioral;

このコードでは、外部からのクロック信号clkを用いて、ストップウォッチのカウントを行います。

start_stop入力信号でストップウォッチの開始と停止を制御し、reset信号でカウンタをリセットします。

さらに、alarm_time入力で指定した時間に達した場合にsound_signal出力がアクティブになり、音声が出力されるようになっています。

実行すると、start_stopをトリガーすることでストップウォッチがスタートし、指定したalarm_timeに達すると音声出力が行われます。

このとき、sound_signalがアクティブになり、外部のスピーカーやブザー等の音声出力デバイスを鳴らすことができます。

次に、このコードの応用として、特定のラップタイムごとに異なる音声を出力するカスタマイズ例を考えます。

例えば、1分ごとに短い音を、5分ごとには長い音を出力するなどの動作を実現することが考えられます。

このような動作を実現するためには、現在のカウント値に応じてsound_signalの挙動を制御するロジックを追加する必要があります。

全体として、VHDLを用いて音声出力機能を持つストップウォッチを実装する方法について解説しました。

この機能は特にトレーニングや実験など、時間を正確に把握する必要があるシチュエーションでの使用に非常に役立ちます。

○サンプルコード8:ストップウォッチの保存機能

ストップウォッチを使用する際には、一時的に計測時間を保存したい場面が多々あります。

VHDLを用いて、その保存機能を組み込む方法を解説します。

このコードでは、ストップウォッチの計測時間を一時的に保存する機能を加えています。

この例では、保存ボタンを押すことで現在の計測時間を特定のレジスタに保存し、後からその時間を確認できるようにしています。

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

entity stopwatch_save is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           save : in STD_LOGIC;
           saved_time : out STD_LOGIC_VECTOR(31 downto 0);
           current_time : out STD_LOGIC_VECTOR(31 downto 0));
end stopwatch_save;

architecture Behavior of stopwatch_save is
    signal count : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000";
    signal saved_count : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000";
    signal running : STD_LOGIC := '0';
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= "00000000000000000000000000000000";
            running <= '0';
        elsif rising_edge(clk) then
            if start_stop = '1' then
                running <= not running;
            end if;

            if running = '1' then
                count <= count + 1;
            end if;

            if save = '1' then
                saved_count <= count;
            end if;
        end if;
    end process;

    current_time <= count;
    saved_time <= saved_count;
end Behavior;

このVHDLコードでは、クロック信号clkに同期して動作するストップウォッチのロジックを記述しています。

start_stop信号でストップウォッチの計測を開始・停止でき、save信号で現在の計測時間を保存します。

このコードを適切なFPGAボード上で動作させると、ボタンやスイッチを用いて計測の開始・停止や時間の保存が可能です。

保存された時間はsaved_timeポートから出力されるので、外部ディスプレイやLEDで表示することができます。

カスタマイズの一例として、保存された時間を複数確認できるようにするために、保存するレジスタを増やすことが考えられます。

また、保存した時間の中で最も長い時間や最も短い時間だけを表示する機能を追加することもできます。

このコードを実際に動かした場合、ストップウォッチは正常に計測時間をカウントし、保存ボタンが押された際にその時間が保存されます。

保存された時間は任意のディスプレイやLEDに表示することが可能です。

○サンプルコード9:ストップウォッチの履歴表示機能

ストップウォッチを利用する際、過去に計測した時間を後から参照したいと思うことが多いでしょう。

このような場合、履歴表示機能が非常に役立ちます。

ここでは、VHDLを使用してストップウォッチの履歴表示機能を追加する方法を説明します。

-- ライブラリとパッケージの使用宣言
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- エンティティ宣言
entity Stopwatch_History is
    Port ( clk : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           current_time : out STD_LOGIC_VECTOR(31 downto 0);
           history : out STD_LOGIC_VECTOR(31 downto 0));
end Stopwatch_History;

architecture Behavior of Stopwatch_History is
    signal count : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000";
    signal hist : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000";
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= "00000000000000000000000000000000";
        elsif rising_edge(clk) then
            if start_stop = '1' then
                count <= count + 1;
                hist <= count;
            end if;
        end if;
    end process;

    current_time <= count;
    history <= hist;
end Behavior;

このコードでは、ストップウォッチを使って時間を計測するための基本的なコードを表しています。

この例では、時計信号clk、開始・停止ボタンstart_stop、リセットボタンresetを入力ポートとして使用しています。

また、current_timeは現在の計測時間を、historyは前回の計測結果を出力します。

このサンプルコードを利用することで、ユーザーは現在の計測時間だけでなく、最後に計測した時間も同時に表示することができるようになります。

実際に上記のコードをFPGAボードに書き込んで実行すると、ストップウォッチの現在の時間がcurrent_timeポートに出力され、最後にストップした際の時間がhistoryポートに出力されるのを確認できるでしょう。

注意点として、上記のサンプルコードは最もシンプルな履歴表示の一例です。

実際のアプリケーションに応じて、複数の履歴データを保存したり、特定のタイミングでの計測データだけを保存するなど、カスタマイズの幅が広がります。

その際は、適切なデータ構造やアルゴリズムを選択することが求められます。

多くの場合、一度だけでなく複数の計測データを保存して後から参照したい場面があります。

そのため、VHDLにおいて履歴データを配列として管理する方法を取り入れると非常に便利です。

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

-- エンティティ宣言
entity Stopwatch_History_Array is
    Port ( clk : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           save_history : in STD_LOGIC;
           current_time : out STD_LOGIC_VECTOR(31 downto 0);
           last_saved_time : out STD_LOGIC_VECTOR(31 downto 0));
end Stopwatch_History_Array;

architecture Behavior of Stopwatch_History_Array is
    signal count : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000";
    type history_array is array (0 to 9) of STD_LOGIC_VECTOR(31 downto 0);
    signal histories : history_array := (others => "00000000000000000000000000000000");
    signal index : integer := 0;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= "00000000000000000000000000000000";
            index <= 0;
        elsif rising_edge(clk) then
            if start_stop = '1' then
                count <= count + 1;
            end if;

            if save_history = '1' and index < 10 then
                histories(index) <= count;
                index <= index + 1;
            end if;
        end if;
    end process;

    current_time <= count;
    last_saved_time <= histories(index - 1 when index > 0 else 0);
end Behavior;

このコードでは、VHDLの配列機能を利用して、最大10回分の計測データをhistoriesという配列に保存しています。

save_historyという信号が'1'のときに、現在の計測データが配列に順番に保存される仕組みになっています。

また、last_saved_timeという出力ポートを通して、最後に保存された時間を外部に出力することができます。

このサンプルコードをFPGAボードに書き込んで動作させると、10回までの計測結果を順番に保存し、最後に保存した時間を出力することが確認できるでしょう。

この機能は特に、繰り返し何らかの動作の計測を行い、その過去のデータを比較する際に役立ちます。

○サンプルコード10:ストップウォッチのリセット機能

このコードでは、ストップウォッチの計測時間をリセットする機能を追加する方法を表しています。

この例では、リセットボタンが押されたときに、ストップウォッチの時間を0に戻すロジックを実装しています。

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

entity Stopwatch_Reset is
    Port ( clk : in STD_LOGIC;
           start_stop : in STD_LOGIC;
           reset : in STD_LOGIC;
           time : out STD_LOGIC_VECTOR(31 downto 0));
end Stopwatch_Reset;

architecture Behavior of Stopwatch_Reset is
    signal count : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000";
begin
    process(clk)
    begin
        if reset = '1' then
            count <= "00000000000000000000000000000000";
        elsif rising_edge(clk) then
            if start_stop = '1' then
                count <= count + 1;
            end if;
        end if;
    end process;

    time <= count;
end Behavior;

この例でのポイントは、リセット信号resetがアクティブなときに、計測時間を示すcountを0に戻している点です。

この機能により、ユーザーは任意のタイミングで計測時間をリセットすることができます。

このコードを実行した場合、リセットボタンを押すとストップウォッチの表示が0に戻ります。

これにより、新しい計測を始める際や、間違えて計測を開始してしまった場合などに、計測をやり直すことができます。

●VHDLでのストップウォッチの応用例

VHDLを使用してストップウォッチを設計する際の基本的な手法は、上記のサンプルコードで学びましたが、さらなる応用も考えられます。

それでは、VHDLでのストップウォッチの応用例として、異なる機能や組み合わせを取り入れた実例を紹介します。

○サンプルコード11:複数のストップウォッチを同時に動作させる例

このコードではVHDLを使って、複数のストップウォッチを同時に動作させるコードを表しています。

この例では、2つのストップウォッチを別々の表示領域で動作させています。

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

entity Multi_Stopwatch is
-- (端子の宣言)
begin
    -- (省略)
end Multi_Stopwatch;

architecture Behavior of Multi_Stopwatch is
    signal stopwatch1, stopwatch2: time;
begin
    -- ストップウォッチ1の制御
    -- (省略)

    -- ストップウォッチ2の制御
    -- (省略)
end Behavior;

複数のストップウォッチを動作させる場合、各ストップウォッチの信号を別々に制御し、それぞれの表示領域に出力する必要があります。

この方法を使用すれば、例えば、競技などで複数のタイマーが必要な場面でも、1つのVHDLデザインで対応することができます。

このコードを実行すると、2つのストップウォッチがそれぞれ独立して動作する様子を確認できます。

もちろん、3つ以上のストップウォッチを動作させることも考えられます。

●注意点と対処法

VHDLでのストップウォッチ設計には、いくつかの注意点が存在します。

①タイミングのズレ

VHDLでの設計においては、タイミングのズレが発生する可能性があります。

この問題は、クロック信号の不一致や外部からの割り込みによって引き起こされることが多いです。

対処法としては、クロック信号の同期を取るための回路を設計する、または外部からの割り込みを最小限に抑えるような設計を心がけることが挙げられます。

②表示の遅延

大量の処理を同時に行う場合、表示に遅延が発生することが考えられます。

これは、特に複数のストップウォッチを同時に動作させる場合などに見られる現象です。

遅延を防ぐためには、計算処理と表示処理を分離する、あるいは並列処理を利用して負荷を分散させるといった工夫が必要です。

③メモリの消費

ストップウォッチの履歴機能や保存機能を実装する際、大量のデータを取り扱う必要があります。

このため、FPGAのオンチップメモリだけでは容量が不足する場合があります。

この問題に対処するためには、外部メモリへのアクセスを考慮した設計や、データの圧縮技術を導入するなどの方法が考えられます。

●カスタマイズ方法

VHDLで作成したストップウォッチは、独自の機能やデザインを追加することでさらに使いやすく、魅力的なものにすることができます。

ここでは、VHDLでのストップウォッチのカスタマイズの一例をご紹介します。

○ディスプレイの色変更

ディスプレイの色を変更することで、視認性の向上や、お好みのデザインに合わせることができます。

ディスプレイの背景色を変更するためのサンプルコードの一部を紹介します。

-- ディスプレイの色設定
signal display_color : std_logic_vector(7 downto 0);
...
-- このコードではディスプレイの背景色を青に設定しています。
display_color <= "00000001";

この例では、display_colorの値を”00000001″に設定することで、ディスプレイの背景色を青に変更しています。

ディスプレイの背景色を変更した場合、青色の背景になったディスプレイが表示されることを確認できます。

○音声通知の追加

ストップウォッチが特定の時間に達したときに音声で通知する機能を追加することもできます。

5分ごとにビープ音を鳴らす機能のサンプルコードを紹介します。

signal beep_time : integer := 300; -- 5分を秒単位で表現
signal current_time : integer := 0;
...
-- このコードでは5分ごとにビープ音を鳴らす機能を追加しています。
if current_time = beep_time then
    -- ビープ音を鳴らすコード
end if;
current_time := current_time + 1;

この例では、current_timeが5分毎にbeep_timeと一致するとビープ音を鳴らす処理を行います。

5分ごとにビープ音が鳴ることを確認できるでしょう。

○ボタンの追加

新しいボタンを追加して、それに機能を割り当てることも可能です。

例として、リセットボタンを追加するサンプルコードを紹介します。

-- リセットボタンの信号定義
signal reset_button : std_logic;
...
-- このコードではリセットボタンを押した際の動作を定義しています。
if reset_button = '1' then
    -- ストップウォッチの時間を0にリセットするコード
end if;

この例では、reset_buttonが’1’のとき、ストップウォッチの時間を0にリセットする処理を行います。

リセットボタンを押すと、ストップウォッチの時間が0になることを確認できます。

まとめ

VHDLを使用して、ストップウォッチのカスタマイズは非常に柔軟に行うことができます。

ディスプレイの色変更、音声通知の追加、ボタンの追加など、多岐にわたるカスタマイズ方法を試して、独自のストップウォッチを作成しましょう。

この記事ではVHDLでのストップウォッチの基本から応用、カスタマイズ方法までを徹底的に解説しました。

VHDLの知識を活かして、さまざまなプロジェクトに挑戦してみてください。