目次
前
次
2LED方向指示器作成
自動車やバイクで利用されている、左右にぞれぞれ
ランプを用意して、点滅することで、方向指示する
装置をエミュレートしてみます。
ブレッドボードにLEDと抵抗をのせると、次のようになります。
回路は、次のように負論理を利用。
点滅は、論理値の'1'と'0'を交互に出力すればよいので
マスタークロックを分周したクロックを生成して利用と
考えます。
左右のボタンを使うことを考えて、マスタークロック
から、1kHzと1Hzを生成します。
分周に利用するVHDLコードは、以下。
-- divider
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iACNT <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iACNT = ACNT_MAX ) then
iACNT <= 0 ;
else
iACNT <= iACNT + 1 ;
end if ;
end if ;
end process ;
iACLK <= '1' when ( iACNT < ACNT_HALF ) else '0' ;
process ( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iBCNT <= 0 ;
elsif rising_edge( iACLK ) then
if ( iBCNT = BCNT_MAX ) then
iBCNT <= 0 ;
else
iBCNT <= iBCNT + 1 ;
end if ;
end if ;
end process ;
iBCLK <= '1' when ( iBCNT < BCNT_HALF ) else '0' ;
分周した1Hzを、LEDに出力するか否かを論理積で
制御すればよいので、出力を次のように定義。
Lout <= iBCLK when ( ????? ) else '1' ;
Rout <= iBCLK when ( ????? ) else '1' ;
ボタンが押されたことを検出して、左右のLEDに
クロックを出力するか否か処理を、シーケンサ
でまとめます。
シーケンサの状態遷移図を描いて考えます。
状態がwaitの間に、クロックを出力すればよいので
状態値で、クロックをLEDに与えるよう工夫します。
Lout <= iBCLK when ( iSTATE = "11" ) else '1' ;
Rout <= iBCLK when ( iSTATE = "11" ) else '1' ;
トリガーを受けてからシーケンサが動作するので
左ボタン、右ボタンのトリガーを受けて動作する
と考えれば、次のように、ステートマシンのVHDL
コードを作成すればよいでしょう。
process( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
elsif rising_edge( iACLK ) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iLTRG = '1' or iRTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- enable
when 1 => iSTATE <= "11" ;
-- wait
when 3 => -- ????? --
-- disable and return first state
when 2 => iSTATE <= "00" ;
-- default
when others => iSTATE <= "00" ;
end case ;
end if ;
end process;
トリガー生成とwaitをどう実現するかまで
処理を分けたので、個別に考えていきます。
ボタンは、次のように正論理で扱います。
ボタンには、チャタリングがあるので
シフトレジスタを使って除去。
iLTRG <= '1' when ( iLSFT = "01" ) else '0' ;
iRTRG <= '1' when ( iRSFT = "01" ) else '0' ;
process( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iLSFT <= "00" ;
iRSFT <= "00" ;
elsif rising_edge( iACLK ) then
iLSFT <= iLSFT(0) & LSWT ;
iRSFT <= iRSFT(0) & RSWT ;
end if ;
end process;
トリガーを片付けたので、waitを考えます。
ボタンを押したなら、15秒間LEDを点滅させる
とするします。
シーケンサは1kHzで動作しているので、1msの
インターバルをもっています。15秒はmsでの
換算で15000カウントですから、このカウント
を、シーケンサに任せます。
シーケンサの中で、イネーブル処理のときに
カウンタを設定し、waitでデクリメントして
いきます。
process( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iWCNT <= 0 ;
elsif rising_edge( iACLK ) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iLTRG = '1' or iRTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- enable and set counter
when 1 => iSTATE <= "11" ;
iWCNT <= 15000 ;
-- wait and decrement
when 3 => if ( iWCNT = 0 ) then
iSTATE <= "10" ;
else
iSTATE <= "11" ;
iWCNT <= iWCNT - 1 ;
end if ;
-- disable and return first state
when 2 => iSTATE <= "00" ;
-- default
when others => iSTATE <= "00" ;
end case ;
end if ;
end process;
まとめます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity bflash is
Port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ; -- 4MHz
-- clock monitor
ACLK : out std_logic ;
BCLK : out std_logic ;
-- button inputs
LSWT : in std_logic ;
RSWT : in std_logic ;
-- output
Lout : out std_logic ;
Rout : out std_logic --;
);
end bflash;
architecture Behavioral of bflash is
--
CONSTANT ACNT_MAX : integer := 3999 ;
CONSTANT BCNT_MAX : integer := 999 ;
CONSTANT ACNT_HALF : integer := 2000 ;
CONSTANT BCNT_HALF : integer := 500 ;
CONSTANT LAST : integer := 15000 ;
-- divider
signal iACNT : integer range 0 to ACNT_MAX ;
signal iACLK : std_logic ;
signal iBCNT : integer range 0 to BCNT_MAX ;
signal iBCLK : std_logic ;
-- synchronizer
signal iLSFT : std_logic_vector(1 downto 0) ;
signal iRSFT : std_logic_vector(1 downto 0) ;
signal iLTRG : std_logic ;
signal iRTRG : std_logic ;
-- sequencer
signal iSTATE : std_logic_vector(1 downto 0) ;
signal iWCNT : integer range 0 to LAST ;
begin
-- output
Lout <= iBCLK when ( iSTATE = "11" ) else '1' ;
Rout <= iBCLK when ( iSTATE = "11" ) else '1' ;
-- monitor
ACLK <= iACLK ;
BCLK <= iBCLK ;
-- divider
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iACNT <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iACNT = ACNT_MAX ) then
iACNT <= 0 ;
else
iACNT <= iACNT + 1 ;
end if ;
end if ;
end process ;
iACLK <= '1' when ( iACNT < ACNT_HALF ) else '0' ;
process ( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iBCNT <= 0 ;
elsif rising_edge( iACLK ) then
if ( iBCNT = BCNT_MAX ) then
iBCNT <= 0 ;
else
iBCNT <= iBCNT + 1 ;
end if ;
end if ;
end process ;
iBCLK <= '1' when ( iBCNT < BCNT_HALF ) else '0' ;
-- synchronizer
iLTRG <= '1' when ( iLSFT = "01" ) else '0' ;
iRTRG <= '1' when ( iRSFT = "01" ) else '0' ;
process( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iLSFT <= "00" ;
iRSFT <= "00" ;
elsif rising_edge( iACLK ) then
iLSFT <= iLSFT(0) & LSWT ;
iRSFT <= iRSFT(0) & RSWT ;
end if ;
end process;
-- sequencer
process( nRESET , iACLK )
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iWCNT <= 0 ;
elsif rising_edge( iACLK ) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iLTRG = '1' or iRTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- enable and set counter
when 1 => iSTATE <= "11" ;
iWCNT <= LAST ;
-- wait and decrement
when 3 => if ( iWCNT = 0 ) then
iSTATE <= "10" ;
else
iSTATE <= "11" ;
iWCNT <= iWCNT - 1 ;
end if ;
-- disable and return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process;
end Behavioral;
ピンアサインは、以下としました。
# system
NET "nRESET" loc = "P39" ;
NET "CLOCK" loc = "P5" ;
# monitor
NET "ACLK" loc = "P1" ;
NET "BCLK" loc = "P2" ;
# LED
NET "Rout" loc = "P3" ;
NET "Lout" loc = "P4" ;
# button
NET "RSWT" loc = "P8" ;
NET "LSWT" loc = "P9" ;
目次
前
次