目次

最終VHDLコード

 BCS(Bar Code Scanner)、モータ制御、マイクロ
 コントローラに分割して、VHDLコードを説明する。


BCS(Bar Code Scanner)  BCSは、次の信号線で接続する。
  1. Vcc(5V)
  2. SH(START)
  3. φ1(CLKA)
  4. φ2(CLKB)
  5. Vout(DOS)
  6. GND
 CLKA、CLKBは、論理和回路に接続しCLKABとする。  また、センサーデータは4ビットで出力する。  カウンタを2つ用意し、CLKABによりインクリメントする。  iSCNTは、START信号でリセットし、インクリメントする。  iSCNTXは、出力されてくるセンサーデータ数をカウント。  2カウンタの動作をタイミングチャートと整合するよう  VHDLコードを記述すると、以下となる。 process (nRESET,CLKAB) begin if ( nRESET = '0' ) then iSCNT <= 0 ; iSCNTX <= 0 ; elsif rising_edge(CLKAB) then -- total counter if ( iSTART = '1' or iSCNT = SCNTMAX ) then iSCNT <= 0 ; else iSCNT <= iSCNT + 1 ; end if ; -- sensing counter if ( iSTART = '1' or iSCNT < SCNTFIRST ) then iSCNTX <= 0 ; else iSCNTX <= iSCNTX + 1 ; end if ; end if ; end process ;  iSCNTXを利用し、データ記憶のタイミングを決定。 iSTRG <= '1' when ( iSCNTX = SCNTLATCH0 ) else '1' when ( iSCNTX = SCNTLATCH1 ) else '1' when ( iSCNTX = SCNTLATCH2 ) else '1' when ( iSCNTX = SCNTLATCH3 ) else '1' when ( iSCNTX = SCNTLATCH4 ) else '1' when ( iSCNTX = SCNTLATCH5 ) else '1' when ( iSCNTX = SCNTLATCH6 ) else '1' when ( iSCNTX = SCNTLATCH7 ) else '0' ;  センサーデータを8ビットにすれば  MCRで作成したファームウエアを活用  できる。  データを記憶するためにシフトレジスタを利用。 process (nRESET,CLKAB) begin if ( nRESET = '0' ) then iREG_SFT <= X"00" ; elsif falling_edge(CLKAB) then if ( iSTRG = '1' ) then iREG_SFT <= iREG_SFT(6 downto 0) & iDOS ; end if ; end if ; end process ;  1スキャンが終わり、データ更新されるまでは  センサーデータを保持しなくてはならないので  シーケンサでスキャン開始とデータ取得完了を  を監視する。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; iREG <= X"00" ; elsif rising_edge(CLOCK) then case conv_integer(iSTATE) is -- wait trigger when 0 => if ( iSTART_TRG = '1' ) then iSTATE <= "01" ; else iSTATE <= "00" ; end if ; -- complete data store when 1 => if ( iSCNT = SCNTFINE ) then iSTATE <= "11" ; else iSTATE <= "01" ; end if ; -- copy when 3 => iSTATE <= "10" ; iREG <= iREG_SFT ; -- return first state when 2 => iSTATE <= "00" ; -- default when others => iSTATE <= "00" ; end case ; end if ; end process ;  スキャン開始を検出するため、シンクロナイザを定義。 process (nRESET,CLKAB) begin if ( nRESET = '0' ) then iSTART_SFT <= "000" ; elsif rising_edge(CLKAB) then iSTART_SFT <= iSTART_SFT(1 downto 0) & iSTART ; end if ; end process ; iSTART_TRG <= '1' when ( iSTART_SFT = "011" ) else '0' ;  まとめると以下。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity tstbcs is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- BCS START : in std_logic ; CLKAB : in std_logic ; DOS : in std_logic ; -- selector SEL : in std_logic ; -- register output REGOUT : out std_logic_vector(3 downto 0) --; ); end tstbcs ; architecture behavioral of tstbcs is -- values CONSTANT SCNTMAX : integer := 2081 ; CONSTANT SCNTXMAX : integer := 2048 ; CONSTANT SCNTFINE : integer := 2080 ; CONSTANT SCNTFIRST : integer := 33 ; -- latch location CONSTANT SCNTLATCH0 : integer := 128 ; CONSTANT SCNTLATCH1 : integer := 384 ; CONSTANT SCNTLATCH2 : integer := 640 ; CONSTANT SCNTLATCH3 : integer := 896 ; CONSTANT SCNTLATCH4 : integer := 1152 ; CONSTANT SCNTLATCH5 : integer := 1408 ; CONSTANT SCNTLATCH6 : integer := 1664 ; CONSTANT SCNTLATCH7 : integer := 1920 ; -- BUS interface signal iSTART : std_logic ; signal iDOS : std_logic ; -- internal counter signal iSCNT : integer range 0 to SCNTMAX ; signal iSCNTX : integer range 0 to SCNTXMAX ; signal iSTRG : std_logic ; -- synchronizer signal iSTART_SFT : std_logic_vector(2 downto 0) ; signal iSTART_TRG : std_logic ; -- internal shift register signal iREG_SFT : std_logic_vector(7 downto 0) ; -- internal register signal iSEL : std_logic ; signal iREG : std_logic_vector(7 downto 0) ; -- sequencer signal iSTATE : std_logic_vector(1 downto 0) ; begin -- input iSTART <= START ; iDOS <= DOS ; iSEL <= SEL ; -- output REGOUT <= iREG(7 downto 4) when ( iSEL = '1' ) else iREG(3 downto 0) ; -- internal counter process (nRESET,CLKAB) begin if ( nRESET = '0' ) then iSCNT <= 0 ; iSCNTX <= 0 ; elsif rising_edge(CLKAB) then -- total counter if ( iSTART = '1' or iSCNT = SCNTMAX ) then iSCNT <= 0 ; else iSCNT <= iSCNT + 1 ; end if ; -- sensing counter if ( iSTART = '1' or iSCNT < SCNTFIRST ) then iSCNTX <= 0 ; else iSCNTX <= iSCNTX + 1 ; end if ; end if ; end process ; iSTRG <= '1' when ( iSCNTX = SCNTLATCH0 ) else '1' when ( iSCNTX = SCNTLATCH1 ) else '1' when ( iSCNTX = SCNTLATCH2 ) else '1' when ( iSCNTX = SCNTLATCH3 ) else '1' when ( iSCNTX = SCNTLATCH4 ) else '1' when ( iSCNTX = SCNTLATCH5 ) else '1' when ( iSCNTX = SCNTLATCH6 ) else '1' when ( iSCNTX = SCNTLATCH7 ) else '0' ; -- synchronizer process (nRESET,CLKAB) begin if ( nRESET = '0' ) then iSTART_SFT <= "000" ; elsif rising_edge(CLKAB) then iSTART_SFT <= iSTART_SFT(1 downto 0) & iSTART ; end if ; end process ; iSTART_TRG <= '1' when ( iSTART_SFT = "011" ) else '0' ; -- internal register process (nRESET,CLKAB) begin if ( nRESET = '0' ) then iREG_SFT <= X"00" ; elsif falling_edge(CLKAB) then if ( iSTRG = '1' ) then iREG_SFT <= iREG_SFT(6 downto 0) & iDOS ; end if ; end if ; end process ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; iREG <= X"00" ; elsif rising_edge(CLOCK) then case conv_integer(iSTATE) is -- wait trigger when 0 => if ( iSTART_TRG = '1' ) then iSTATE <= "01" ; else iSTATE <= "00" ; end if ; -- complete data store when 1 => if ( iSCNT = SCNTFINE ) then iSTATE <= "11" ; else iSTATE <= "01" ; end if ; -- copy when 3 => iSTATE <= "10" ; iREG <= iREG_SFT ; -- return first state when 2 => iSTATE <= "00" ; -- default when others => iSTATE <= "00" ; end case ; end if ; end process ; end behavioral;
モータ制御  モータ制御は、5MHzクロックを入力し分周して  PWM波形生成のクロックにします。左右のDUTY比  を与えて、PWM波形を生成します。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity pout is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- 5MHz -- sensor handler LEFTV : in std_logic_vector(6 downto 0) ; RIGHTV : in std_logic_vector(6 downto 0) ; -- pulse out LPOUT : out std_logic ; RPOUT : out std_logic --; ); end pout ; architecture behavioral of pout is -- CONSTANT CNTMAX : integer := 499 ; CONSTANT CNTHALF : integer := 250 ; CONSTANT PCNTMAX : integer := 99 ; -- counter signal iPCNT : integer range 0 to 99 ; signal iLEFTX : integer range 0 to 99 ; signal iRIGHTX : integer range 0 to 99 ; -- clock divider signal iCNT : integer range 0 to CNTMAX ; signal iPCLK : std_logic ; begin -- output LPOUT <= '1' when ( iPCNT < iLEFTX ) else '0' ; RPOUT <= '1' when ( iPCNT < iRIGHTX ) else '0' ; -- clock divider (generate 10kHz) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= 0 ; elsif rising_edge(CLOCK) then if ( iCNT = CNTMAX ) then iCNT <= 0 ; else iCNT <= iCNT + 1 ; end if ; end if ; end process ; iPCLK <= '1' when ( iCNT < CNTHALF ) else '0' ; -- counter process (nRESET,iPCLK) begin if ( nRESET = '0' ) then iPCNT <= 0 ; iLEFTX <= 0 ; iRIGHTX <= 0 ; elsif rising_edge(iPCLK) then if ( iPCNT = PCNTMAX ) then iPCNT <= 0 ; iLEFTX <= conv_integer(LEFTV) ; iRIGHTX <= conv_integer(RIGHTV) ; else iPCNT <= iPCNT + 1 ; end if ; end if ; end process ; end behavioral;
マイクロコントローラ  マイクロコントローラのVHDLコードを備忘録として  記す前に、走行モードの状態遷移を確認します。  状態遷移を見れば、マイクロコントローラの動作で  不要な部分があるかも知れないとわかります。また  使わないレジスタも出てくることも。  走行モードは5状態あり、次の動作をさせます。  各状態遷移は、次のように設定。  IDLE→BLIND   スタートスイッチを押したなら、状態を   IDLEからBLINDにします。   状態遷移のトリガーは、スタートスイッチにします。  BLIND→NORMAL   BLINDでは、順を追って左右のDUTY比を変更します。   指定回DUTY比を変更後、NORMALに遷移します。  NORMAL→CRANK   NORMALモードで走行中、センターラインではなく   すべて白を検出したなら、CRANKモードに遷移します。  NORMAL→LANE   NORMALモードで走行中、センターラインではなく   片側によった白を検出したなら、LANEモードに   遷移します。  CRANK→NORMAL   CRANKモードで旋回中、センターラインを検出   したなら、NORMALモードに遷移します。  LANE→NORMAL   LANEモードですべて黒のコース面を移動中、センター   ラインを検出したなら、NORMALモードに遷移します。 (under constrcution)
目次

inserted by FC2 system