Ultrasonic sensor interface
最近の超音波センサー基板には、マイコンを実装し
トリガーを与えると、計測後、距離相当のパルス幅
を返すものがあります。
タイミングチャートでは、次のようになります。
超音波センサーは、音波を壁にあてたとして
170m/sという音速を考えます。
壁まで400mm程度あるとして、検出処理を
VHDLコードにしてみます。
利用するCPLDを、Cool Runner IIとすると
5Vで動作する超音波センサーに直に接続
できません。インタフェースを接続します。
インタフェース回路は、以下。
1サイクルを100msとして、この間にトリガーを出力します。
100msを測定するためのカウンタを用意します。
カウンタの値を利用して、トリガーを10usのパルスを生成し
立上り、立下り時のカウント値を記憶します。
パルス生成は、次のように単純にしました。
VHDLコードでは、次のように定義。
-- 100ms counter
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(iSCLK) then
if ( iCNT = CNTMAX ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
-- generate TRIGGER (10us)
iUTRG <= '1' when ( iCNT < TRGMAX ) else '0' ;
シフトレジスタを使い、立上り、立下りをキャッチします。
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iURES_SFT <= "000" ;
elsif rising_edge(iSCLK) then
iURES_SFT <= iURES_SFT(1 downto 0) & URES ;
end if ;
end process ;
iURES_LH <= '1' when ( iURES_SFT = "011" ) else '0' ;
iURES_HL <= '1' when ( iURES_SFT = "110" ) else '0' ;
立上り、立下りのトリガーを利用し、カウント値
を記憶していきます。
process (iSCLK)
begin
if rising_edge(iSCLK) then
-- clear
if ( iCNT = CNTMAX ) then
iBEGINX <= (others => '0') ;
iFINEX <= (others => '0') ;
end if ;
-- measure (L -> H)
if ( iURES_LH = '1' ) then
iBEGINX <= conv_std_logic_vector(iCNT,17) ;
end if ;
-- measure (H -> L)
if ( iURES_HL = '1' ) then
iFINEX <= conv_std_logic_vector(iCNT,17) ;
end if ;
end if ;
end process ;
カウント値の差を求めるために、シーケンサを利用します。
100msを1サイクルとし、99ms経過したときにシーケンサが
起動→記憶カウント値を複写→カウント値の差分計算と続け
ます。
シーケンサは4usで作業を終えるので、99.5msの時点で
結果が出ます。
最終VHDLコードは、次のようにしました。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity tstusen is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ; -- 4MHz
-- sensor handler signal
UTRG : out std_logic ; -- TRG
URES : in std_logic ; -- ECHO
-- gate status (1:close 0:open)
GSTATE : out std_logic ;
-- monitor
DOUT : out std_logic_vector(16 downto 0) ;
LOUT : out std_logic --;
);
end tstusen ;
architecture behavioral of tstusen is
-- values
CONSTANT TRGMAX : integer := 11 ;
CONSTANT CNTMAX : integer := 99999 ; -- 100ms
CONSTANT CNTLAST : integer := 99000 ; -- 99ms
CONSTANT CNTTARGET : integer := 2000 ; -- 2ms => 340mm
-- 1us generator (1MHz)
signal iSCNT : std_logic_vector(1 downto 0) ;
signal iSCLK : std_logic ;
-- 100ms counter
signal iCNT : integer range 0 to CNTMAX ;
-- trigger
signal iUTRG : std_logic ;
-- echo
signal iURES_SFT : std_logic_vector(2 downto 0) ;
signal iURES_HL : std_logic ;
signal iURES_LH : std_logic ;
-- detector
signal iBEGINX : std_logic_vector(16 downto 0) ;
signal iFINEX : std_logic_vector(16 downto 0) ;
-- sequencer
signal iSTATE : std_logic_vector( 1 downto 0) ;
signal iBEGIN : std_logic_vector(16 downto 0) ;
signal iFINE : std_logic_vector(16 downto 0) ;
signal iDIFF : std_logic_vector(16 downto 0) ;
signal iGSTATE : std_logic ;
begin
-- output
UTRG <= iUTRG ;
GSTATE <= iGSTATE ;
LOUT <= not iGSTATE ;
DOUT <= iDIFF ;
-- generate 1MHz (1us)
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSCNT <= "00" ;
elsif rising_edge(CLOCK) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
iSCLK <= '1' when ( iSCNT = "00" ) else '0' ;
-- 100ms counter
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(iSCLK) then
if ( iCNT = CNTMAX ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
-- generate TRIGGER (10us)
iUTRG <= '1' when ( iCNT < TRGMAX ) else '0' ;
-- synchronizer
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iURES_SFT <= "000" ;
elsif rising_edge(iSCLK) then
iURES_SFT <= iURES_SFT(1 downto 0) & URES ;
end if ;
end process ;
iURES_LH <= '1' when ( iURES_SFT = "011" ) else '0' ;
iURES_HL <= '1' when ( iURES_SFT = "110" ) else '0' ;
-- detector
process (iSCLK)
begin
if rising_edge(iSCLK) then
-- clear
if ( iCNT = CNTMAX ) then
iBEGINX <= (others => '0') ;
iFINEX <= (others => '0') ;
end if ;
-- measure (L -> H)
if ( iURES_LH = '1' ) then
iBEGINX <= conv_std_logic_vector(iCNT,17) ;
end if ;
-- measure (H -> L)
if ( iURES_HL = '1' ) then
iFINEX <= conv_std_logic_vector(iCNT,17) ;
end if ;
end if ;
end process ;
-- sequencer
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iDIFF <= (others => '0') ;
iBEGIN <= (others => '0') ;
iFINE <= (others => '0') ;
elsif falling_edge(iSCLK) then
case conv_integer(iSTATE) is
-- clear counter
when 0 => if ( iCNT = CNTLAST ) then
iSTATE <= "01" ;
iDIFF <= (others => '0') ;
else
iSTATE <= "00" ;
end if ;
-- copy
when 1 => iSTATE <= "11" ;
iBEGIN <= iBEGINX ;
iFINE <= iFINEX ;
-- calculate
when 3 => iSTATE <= "10" ;
if conv_integer(iFINE) > conv_integer(iBEGIN) then
iDIFF <= iFINE - iBEGIN ;
end if ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
iGSTATE <= '1' when ( conv_integer(iDIFF) < CNTTARGET ) else '0' ;
end behavioral;
ピンアサインは、以下。
# system
NET "CLOCK" LOC = "P22" ;
NET "nRESET" LOC = "P99" ;
# Ultra sononic sensor interface
NET "UTRG" LOC = "P1" ;
NET "URES" LOC = "P2" ;
NET "GSTATE" LOC = "P3" ;
# monitor LED
NET "LOUT" LOC = "P4" ;
# difference
NET "DOUT<0>" LOC = "P6" ;
NET "DOUT<1>" LOC = "P7" ;
NET "DOUT<2>" LOC = "P8" ;
NET "DOUT<3>" LOC = "P9" ;
NET "DOUT<4>" LOC = "P10" ;
NET "DOUT<5>" LOC = "P11" ;
NET "DOUT<6>" LOC = "P12" ;
NET "DOUT<7>" LOC = "P13" ;
NET "DOUT<8>" LOC = "P14" ;
NET "DOUT<9>" LOC = "P15" ;
NET "DOUT<10>" LOC = "P16" ;
NET "DOUT<11>" LOC = "P17" ;
NET "DOUT<12>" LOC = "P18" ;
NET "DOUT<13>" LOC = "P19" ;
NET "DOUT<14>" LOC = "P23" ;
NET "DOUT<15>" LOC = "P24" ;
NET "DOUT<16>" LOC = "P27" ;
目次
前
次