目次

8LED方向指示器作成

 8LEDを利用して、左右の方向指示器を
 作成してみます。

 8個のLEDを横一列に並べて、左右それぞれ
 4個を使い、点滅させます。

 LED基板は、次の基板を使います。



 左右の方向指示なので、点灯パターンを考えて
 それをVHDLコードに変換。

 左方向指示

  中央から左にむけて、LEDを点灯。



 右方向指示

  中央から右にむけて、LEDを点灯。




 点灯は0から4の5状態になっているので
 5進数カウンタがあるとして、デコードで
 左右の点灯を決定。

 デコーダをVHDLコードで記述してみます。

 左方向指示

  デコーダ出力は、他の部位からの指示で
  LEDに転送するとしておきます。

    -- output
    Lout <= iLout when ( ??? ) else X"0" ;

    -- decode
    iLout <= X"1" when ( iSCNT = 1 ) else
             X"3" when ( iSCNT = 2 ) else
             X"7" when ( iSCNT = 3 ) else
             X"F" when ( iSCNT = 4 ) else
             X"0" ;


 右方向指示

  他の部位からの指示で、デコード出力を
  LEDに転送と仮定。

    -- output
    Rout <= iRout when ( ??? ) else X"0" ;

    -- decode
    iRout <= X"8" when ( iSCNT = 1 ) else
             X"C" when ( iSCNT = 2 ) else
             X"E" when ( iSCNT = 3 ) else
             X"F" when ( iSCNT = 4 ) else
             X"0" ;

 デコーダは、シーケンサの出力値iSCNTで
 値を決めているので、バイナリカウンタ
 を利用して記述できます。

    -- binary counter
    process (nRESET,iBCLK)
    begin
      if ( nRESET = '0' ) then
        iSCNT <= 0 ;
      elsif rising_edge(iBCLK) then
        if ( iSCNT = 4 ) then
          iSCNT <= 0 ;
        else
          iSCNT <= iSCNT + 1 ;
        end if ; 
      end if ;
    end process ;

 カウンタを動かすには、クロックが必要なので
 マスタークロックからシーケンサとカウンタの
 ためのクロックを生成。



 ブロック図から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' ;

 方向を指示するには、ボタンを利用。
 回路は、次のようになっているとします。



 ボタンには、チャタリングがあるので
 シフトレジスタを使って除去しておき
 シーケンサにトリガーを与えます。

  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;

 トリガーを受けたなら、15秒間だけ
 LEDに点灯パターンを出力することに
 します。
 シーケンサの状態遷移は、以下。



 状態遷移図を2ビットのジョンソンカウンタを
 ベースにして、VHDLコードに変換。

  -- 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  <= 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 dflash 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_vector(3 downto 0) ;
    Rout   : out std_logic_vector(3 downto 0) --;
  );
end dflash;

architecture Behavioral of dflash 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 ;
  -- decoder
  signal iLout : std_logic_vector(3 downto 0) ;
  signal iRout : std_logic_vector(3 downto 0) ;
  signal iSCNT : integer range 0 to 4 ;
  -- sequencer
  signal iSTATE : std_logic_vector(1 downto 0) ;
  signal iWCNT  : integer range 0 to LAST ;
begin
  -- output
  Lout <= iLout when ( iSTATE = "11" ) else X"0" ;
  Rout <= iRout when ( iSTATE = "11" ) else X"0" ;

  -- left decode
  iLout <= X"1" when ( iSCNT = 1 ) else
           X"3" when ( iSCNT = 2 ) else
           X"7" when ( iSCNT = 3 ) else
           X"F" when ( iSCNT = 4 ) else
           X"0" ;

  -- right decode
  iRout <= X"8" when ( iSCNT = 1 ) else
           X"C" when ( iSCNT = 2 ) else
           X"E" when ( iSCNT = 3 ) else
           X"F" when ( iSCNT = 4 ) else
           X"0" ;

  -- monitor
  ACLK <= iACLK ;
  BCLK <= iBCLK ;

  -- binary counter
  process (nRESET,iBCLK)
  begin
    if ( nRESET = '0' ) then
      iSCNT <= 0 ;
    elsif rising_edge(iBCLK) then
      if ( iSCNT = 4 ) then
        iSCNT <= 0 ;
      else
        iSCNT <= iSCNT + 1 ;
      end if ; 
    end if ;
  end process ;

  -- 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" ;

# button
NET "RSWT"   loc = "P8" ;
NET "LSWT"   loc = "P9" ;

# right LED
NET "Rout<0>" loc = "P11" ;
NET "Rout<1>" loc = "P12" ;
NET "Rout<2>" loc = "P13" ;
NET "Rout<3>" loc = "P14" ;

# left LED
NET "Lout<0>" loc = "P18" ;
NET "Lout<1>" loc = "P19" ;
NET "Lout<2>" loc = "P20" ;
NET "Lout<3>" loc = "P22" ;


目次

inserted by FC2 system