電子サイコロ
スイッチと7セグメントLEDが載ったボードで、HDLの応用例が
ないか、考えていました。
TV番組でサイコロを振る場面を見て、電子サイコロを設計します。
利用ボードは、下のモノです。
ブロック図を作成し、動作を考えます。
サイコロは、1〜6の目で表現しますが、7セグメントLEDが
ボード上にあるので、0〜9で賽の目を出力します。
0〜9の賽の目を出すため、10進カウンタを利用します。
10進カウンタを動かす、止めるのトリガーを利用します。
10進カウンタの出力を、7セグメントLEDの出力ビット
パターンに変換するため、デコーダを用意します。
利用ボードには、7セグメントLEDが6個あるので
ダイナミック点灯で、1個だけを点灯するための
セレクタを設けます。
ボードでは50MHzクロックがあるので、1kHz程度まで
周波数を下げて利用します。そのために、クロック
ジェネレータを使います。
各処理ブロックを定義していきます。
10進カウンタ
10進カウンタを定義します。
カウントアップ、停止を2つのトリガーBTRG、STRGで
担当させることにし、entityを考えます。
上図から、entityを定義します。
entity dcntx is
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
BTRG : in std_logic ; -- begin trigger
STRG : in std_logic ; -- stop trigger
-- output
COUT : out std_logic_vector(3 downto 0) --;
);
end dcntx ;
トリガーを利用しているので、内部にシフトレジスタを
用意した、シンクロナイザーを定義します。
-- trigger
iBTRG <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ;
iSTRG <= '1' when ( iSTRG_SFT = "011" or iSTRG_SFT = "001" ) else '0' ;
-- shift register
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iBTRG_SFT <= "000" ;
iSTRG_SFT <= "000" ;
elsif rising_edge( CLOCK ) then
iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ;
iSTRG_SFT <= iSTRG_SFT(1 downto 0) & STRG ;
end if ;
end process ;
トリガーが出来たので、カウンタを動かすか止めるかを
指定するフラグをシーケンサで規定します。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iDSTATE <= "00" ;
elsif rising_edge( CLOCK ) then
case conv_integer(iDSTATE) is
-- wait begin trigger
when 0 => if ( iBTRG = '1' ) then
iDSTATE <= "01" ;
else
iDSTATE <= "00" ;
end if ;
-- skip
when 1 => iDSTATE <= "11" ;
-- wait stop trigger
when 3 => if ( iSTRG = '1' ) then
iDSTATE <= "10" ;
else
iDSTATE <= "11" ;
end if ;
-- return first state
when 2 => iDSTATE <= "00" ;
-- default
when others =>
iDSTATE <= "00" ;
end case ;
end if ;
end process ;
シーケンサでフラグを作成したので、カウンタを定義します。
単純に、10進カウンタをフラグを利用して動かします。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCOUT <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iENABLE = '1' ) then
if ( iCOUT = 10 ) then
iCOUT <= 0 ;
else
iCOUT <= iCOUT + 1 ;
end if ;
end if ;
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 dcntx is
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
BTRG : in std_logic ; -- begin trigger
STRG : in std_logic ; -- stop trigger
-- output
COUT : out std_logic_vector(3 downto 0) --;
);
end dcntx ;
architecture Behavioral of dcntx is
-- internal counter
signal iCOUT : integer range 0 to 10 ;
-- enable counter flag
signal iENABLE : std_logic ;
-- shift register
signal iBTRG_SFT : std_logic_vector(2 downto 0) ;
signal iSTRG_SFT : std_logic_vector(2 downto 0) ;
-- internal trigger
signal iBTRG : std_logic ;
signal iSTRG : std_logic ;
-- sequencer
signal iDSTATE : std_logic_vector(1 downto 0) ;
begin
-- output
COUT <= conv_std_logic_vector(iCOUT,4) ;
-- enable counter flag
iENABLE <= iDSTATE(0) ;
-- counter
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iCOUT <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iENABLE = '1' ) then
if ( iCOUT = 10 ) then
iCOUT <= 0 ;
else
iCOUT <= iCOUT + 1 ;
end if ;
end if ;
end if ;
end process ;
-- trigger
iBTRG <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ;
iSTRG <= '1' when ( iSTRG_SFT = "011" or iSTRG_SFT = "001" ) else '0' ;
-- shift register
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iBTRG_SFT <= "000" ;
iSTRG_SFT <= "000" ;
elsif rising_edge( CLOCK ) then
iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ;
iSTRG_SFT <= iSTRG_SFT(1 downto 0) & STRG ;
end if ;
end process ;
-- sequencer
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iDSTATE <= "00" ;
elsif rising_edge( CLOCK ) then
case conv_integer(iDSTATE) is
-- wait begin trigger
when 0 => if ( iBTRG = '1' ) then
iDSTATE <= "01" ;
else
iDSTATE <= "00" ;
end if ;
-- skip
when 1 => iDSTATE <= "11" ;
-- wait stop trigger
when 3 => if ( iSTRG = '1' ) then
iDSTATE <= "10" ;
else
iDSTATE <= "11" ;
end if ;
-- return first state
when 2 => iDSTATE <= "00" ;
-- default
when others =>
iDSTATE <= "00" ;
end case ;
end if ;
end process ;
end Behavioral;
デコーダ
10進カウンタの出力を、7セグメントLEDのビットパターンに
変更すればよいので、4入力7出力の組合せ回路で実現します。
4入力7出力のentityを考えて、まとめます。
10進数の0〜9を判断して、それ以外はデフォルト値を
出力します。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ledx is
port (
-- input
DIN : in std_logic_vector(3 downto 0);
-- output
DOUT : out std_logic_vector(6 downto 0) --;
);
end ledx ;
architecture Behavioral of ledx is
signal iDOUT : std_logic_vector(6 downto 0) ;
begin
-- output
DOUT <= not iDOUT ;
-- conversion
iDOUT <= "1111110" when ( conv_integer(DIN) = 0 ) else
"0110000" when ( conv_integer(DIN) = 1 ) else
"1101101" when ( conv_integer(DIN) = 2 ) else
"1111001" when ( conv_integer(DIN) = 3 ) else
"0110011" when ( conv_integer(DIN) = 4 ) else
"1011011" when ( conv_integer(DIN) = 5 ) else
"1011111" when ( conv_integer(DIN) = 6 ) else
"1110010" when ( conv_integer(DIN) = 7 ) else
"1111111" when ( conv_integer(DIN) = 8 ) else
"1111011" when ( conv_integer(DIN) = 9 ) else
"1111111" ;
end Behavioral;
セレクタ
6けた分の7セグメントLEDがあるので、ダイナミック点灯する
ために、カウンタで0のとき、イネーブル信号を出します。
上のタイミングチャートをコードに変換します。
SEGOUT <= iLOUT ;
SEGSEL <= "111110" when ( iLCNT = 0 ) else "111111" ;
DP <= '1' ;
ドットポイントは常に消灯するため、論理値を'1'とします。
イネーブル信号を扱うためのカウンタを定義します。
process (nRESET,iCLOCK)
begin
if ( nRESET = '0' ) then
iLCNT <= 0 ;
elsif rising_edge( iCLOCK ) then
if ( iLCNT = 6 ) then
iLCNT <= 0 ;
else
iLCNT <= iLCNT + 1 ;
end if ;
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 clkgenx is
generic (
TOPX : integer ;
RMAX : integer --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLKOUT : out std_logic -- ;
);
end clkgenx;
architecture Behavioral of clkgenx is
signal iSCNT : std_logic_vector(TOPX-1 downto 0);
signal iCLK : std_logic ;
begin
-- output
CLKOUT <= iCLK ;
-- divider
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSCNT <= (others => '0') ;
iCLK <= '0' ;
elsif rising_edge(CLOCK) then
if ( conv_integer(iSCNT) = RMAX ) then
iSCNT <= (others => '0') ;
iCLK <= not iCLK ;
else
iSCNT <= iSCNT + '1' ;
end if ;
end if ;
end process ;
end Behavioral;
全体
各コンポーネントを活用し、電子サイコロとしてまとめます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity dice is
generic (
TOPX : integer := 15 ;
RMAX : integer := 25000 ;
TOPY : integer := 5 ;
CMAX : integer := 27 --;
);
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
BTRG : in std_logic ;
STRG : in std_logic ;
-- output
DP : out std_logic ;
SEGSEL : out std_logic_vector(5 downto 0) ;
SEGOUT : out std_logic_vector(6 downto 0) --;
);
end dice;
architecture Behavioral of dice is
-- clock generate component
component clkgenx is
generic (
TOPX : integer ;
RMAX : integer --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLKOUT : out std_logic -- ;
);
end component;
-- digit counter component
component dcntx is
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
BTRG : in std_logic ; -- begin trigger
STRG : in std_logic ; -- stop trigger
-- output
COUT : out std_logic_vector(3 downto 0) --;
);
end component ;
-- 7 segment LED component
component ledx is
port (
-- input
DIN : in std_logic_vector(3 downto 0);
-- output
DOUT : out std_logic_vector(6 downto 0) --;
);
end component ;
-- internal clock
signal iCLOCK : std_logic ;
signal iCLOCK2 : std_logic ;
-- trigger
signal iBTRG : std_logic ;
signal iSTRG : std_logic ;
-- counter
signal iCOUNT : std_logic_vector(3 downto 0) ;
-- 7 segment LED
signal iLOUT : std_logic_vector(6 downto 0) ;
signal iLCNT : integer range 0 to 6 ;
begin
-- internal clock (1kHz)
XCLK : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iCLOCK);
YCLK : clkgenx generic map (TOPY,CMAX) port map (nRESET,iCLOCK,iCLOCK2);
-- internal digit counter
XCOUNTER : dcntx port map (nRESET,iCLOCK2,iBTRG,iSTRG,iCOUNT);
-- internal decoder
XSLED : ledx port map (iCOUNT,iLOUT);
-- input
iBTRG <= not BTRG ;
iSTRG <= not STRG ;
-- output
SEGOUT <= iLOUT ;
SEGSEL <= "111110" when ( iLCNT = 0 ) else "111111" ;
DP <= '1' ;
-- LED selector
process ( nRESET , iCLOCK )
begin
if ( nRESET = '0' ) then
iLCNT <= 0 ;
elsif rising_edge( iCLOCK ) then
if ( iLCNT = 6 ) then
iLCNT <= 0 ;
else
iLCNT <= iLCNT + 1 ;
end if ;
end if ;
end process ;
end Behavioral;
ピン割当て
ボードで動かすためには、FPGAのI/Oボードと接続している
信号のピンをUCFファイルの中に記述します。
# system
NET "CLOCK" LOC = "P56" ;
NET "nRESET" LOC = "P107" ;
# trigger
NET "STRG" LOC = "P6" ;
NET "BTRG" LOC = "P10" ;
# 7 segment LED charactor
NET "DP" LOC = "P91" ;
NET "SEGOUT<0>" LOC = "P92" ;
NET "SEGOUT<1>" LOC = "P87" ;
NET "SEGOUT<2>" LOC = "P88" ;
NET "SEGOUT<3>" LOC = "P85" ;
NET "SEGOUT<4>" LOC = "P86" ;
NET "SEGOUT<5>" LOC = "P81" ;
NET "SEGOUT<6>" LOC = "P82" ;
# 7 segment LED selector
NET "SEGSEL<0>" LOC = "P98" ;
NET "SEGSEL<1>" LOC = "P83" ;
NET "SEGSEL<2>" LOC = "P75" ;
NET "SEGSEL<3>" LOC = "P74" ;
NET "SEGSEL<4>" LOC = "P77" ;
NET "SEGSEL<5>" LOC = "P76" ;
実動作
BEGINとSTOPをプッシュボタンに割当てたので
この2ボタンで、電子サイコロ動作するのか
確認しました。
右端をSTOPに、その左側にBEGINを割当てます。
BEGINを押すと、7セグメントLEDが、目まぐるしく
点灯します。
STOPを押すと、賽の目が確定します。
賽の目を振る場合は、またBEGINを押します。