1kHzのクロック信号でカウンタを動作させると、1kHzの周期、
つまり1/1000秒ごとにカウンタの値が増加していくことになります。
これをLEDなどで表示しても、速すぎてわかりません。
そこで少し工夫をして、12ビットのカウンタを使い、
その上位の8ビット分だけを、LEDで表示させてみることにします。
これによって、LEDの一番下位の桁(LSB)は1/1000秒×24=16[ms]ごと
にカウントが増えていきます。
これでもまだ速すぎてわかりませんが、
LEDの一番上位の桁(MSB)では1/1000秒×211=2048[ms]=約2秒
ごとにカウントが増えることになり、これであれば目で見てわかりそうです。
まずプロジェクトをつくります。
名前はcounterとしておきましょう。
続いて、カウンタを記述するVHDLファイルを作ります。
名前はcounter(counter.vhd)としておきましょう。
続いて入出力を定義します。
以下の3つの信号を定義しておきます。
CLKはクロック、RSTはリセット、LED(7)〜LED(0)は、
EDX-001上の8個のLEDにつながる出力です。
カウンタをcount.vhdにVHDLで記述しておきます。
この例では、カウンタの内部に12ビットのカウント値Qをもち、
その上位8本だけを、最後の方で出力LEDに接続しています。
(EDX-001のLEDが負論理(0で点灯)なので、notをつけて接続しています)
またリセット信号RSTはクロックとは非同期にしてあります。 ちなみにこのリセット信号RSTは、EDX-001のスイッチAにつなぐように 次のピン定義ファイルに記述します。 つまりスイッチAを押すとリセットがかかるようにします。
User Constrain内のEdit Constrainsを選んで
ピン定義ファイルを作成し、上記のように記述しておきます。
ちなみにRSTは、EDX-001上のスイッチAがつながっているP50(50番ピン)に
つなげるように指定しています。
(このP50は、第4回の演習ではPSW_Aという名前にしていた信号です)
あとは論理合成から書き込みファイルの生成へ進み、 counter.bitができたら、copyコマンドで転送して動作させてみましょう。
左上の画面でBehavioal Simulationを選び、
テストベンチのファイル(test_counter.vhd)を新規に追加し、
上記のように記述しておきます。
最初の100ns間だけRST=0としてリセットをかけています。
また後半のprocess文では、RST信号を変化させているのとは
独立に、50nsごとにCLKの値を反転しています。
つまりCLKは、50nsごとに0→1→0→1→・・・となりますので、
変化の周期は100ns、つまり10MHzのクロック信号、ということになります。
(これは実際に与える1kHzよりは1000倍速いですが、
今回は気にしないことにします)
シミュレーションを実行すると、このようになります。
counterの出力であるLEDの値の波形が現れますが、
FFで変化していません。
これは、LEDはカウンタの上位8ビットだけをつないであったので、
まだ変化が現れていないため、です。
(CLKの16発目ではじめてLEDが変化するはず)
そこで、カウンタの内部にあるカウント値であるQの値も
シミュレーションで確認してみることにしましょう。
左側のSim Hierarchyの画面内で、シミュレーション対象の回路counterを
開き、その中にあるq[11:0]を波形の画面へドラッグしておきます。
それから再度シミュレーションを行うと、qの値が
CLKの立ち上がりごとに増えていっているのがわかります。
これには、1kHzのクロック信号CLKを直接カウンタに与えるのではなく、
それから1秒周期のクロック信号CLK1Sを作り、それを
カウンタに与えるようにしてみます。
CLKのように速いクロックからCLK1Sのように遅いクロックを作る回路を
分周回路(divider)と呼びます。
今回使う分周回路にはdiv1sという名前をつけておくことにします。
まずdiv1sをcomponentとして使い、それから出力されてくる
クロック信号CLK1Sを使ったカウンタ回路をつくっておきます。
先ほどつくったcounterを改造すればよいでしょう。
ついでに、せっかくなので、カウント値Qを、そのまますべてLEDへ
つないでおき、それにあわせてカウント値Qも8ビットにしておきます。
またCLK1Sをsignalとして宣言しておきます。
同様に分周回路div1sを、新しいVHDLファイルとして、
counter.vhdに対して新規に追加をしておきます。
名前はdiv1s.vhdとしておけばよいでしょう。
その中身の分周回路は、上記のように記述しておきます。
分周回路も、実はカウンタです。 ただしカウント値に応じて、分周後のクロック出力であるCLK1Sを 変化させています。 この例では、CLKの立ち上がりごとに、 Q=999ならばQ=0、CLK1S=1とし、 そうでなければQに1を加えてCLK1S=0としています。
これにより、CLKの立ち上がりごとにQは0→1→・・・→999→0→1→・・・ と変化して意気、999→0のときだけCLK1S=1、それ以外ではCLK1S=0と なります。 したがってCLK1Sは、CLKの1000発ごとに0→1となることになり、 CLKの1/1000の周波数となります。 今回はCLKは1kHzでしたので、CLK1Sは1Hz、つまり1秒周期になります。
この調子で行けば、どのような周波数のクロックでも作れそうですね。
ちなみにdiv1sの内部のカウント値Qが10ビットとなっていますが、 その理由を考えておきましょう。
ちなみにdiv1s.vhdを作成すると、counterの中に
インスタンスi0として呼び出されていることが、
Sources画面でも確認できます。
各回路の要点をまめておきます。 (設計例(VHDLファイル・ucfファイル一式))
entity counter is Port ( CLK : in STD_LOGIC; RST : in STD_LOGIC; LED : out STD_LOGIC_VECTOR (7 downto 0); SG : out std_logic_vector(7 downto 0); SA : out std_logic_vector(3 downto 0)); end counter; architecture Behavioral of counter is signal Q: std_logic_vector(3 downto 0); signal CLK1S: std_logic; signal SGb: std_logic_vector(7 downto 0); component div1s port ( CLK: in std_logic; CLK1S: out std_logic; RST: in std_logic ); end component; component dec7seg port ( D: in std_logic_vector(3 downto 0); SG: out std_logic_vector(7 downto 0); SA: out std_logic_vector(3 downto 0) ); end component; begin i0: div1s port map(CLK=>CLK, CLK1S=>CLK1S, RST=>RST); i1: dec7seg port map(D=>Q, SG=>SGb, SA=>SA); process (CLK1S, RST) begin if (RST = '0') then Q <= "0000"; elsif (CLK1S'event and CLK1S = '1') then if (Q = 9) then Q <= "0000"; else Q <= Q + 1; end if; end if; end process; SG <= not SGb; LED <= "1111" & not Q; end Behavioral;
entity dec7seg is Port ( D : in STD_LOGIC_VECTOR (3 downto 0); SG : out STD_LOGIC_VECTOR (7 downto 0); SA : out STD_LOGIC_VECTOR (3 downto 0)); end dec7seg; architecture Behavioral of dec7seg is begin process (D) begin case D is when "0000" => SG <= "00111111"; when "0001" => SG <= "00000110"; when "0010" => SG <= "01011011"; when "0011" => SG <= "01001111"; when "0100" => SG <= "01100110"; when "0101" => SG <= "01101101"; when "0110" => SG <= "01111101"; when "0111" => SG <= "00100111"; when "1000" => SG <= "01111111"; when "1001" => SG <= "01101111"; when others => SG <= "00000000"; end case; end process; SA <= "1110"; end Behavioral;