目次

電子サイコロ

 スイッチと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を押します。


目次 inserted by FC2 system