ultrasonic sensor handler
最近の超音波センサーは、距離を時間に換算して
出力するタイプが出てきている。
制御は簡単で、TRGでスタートパルスを与え
ECHOがHになるまでの時間を計測する。
タイミングチャートで見ると、非常に簡単。
この超音波センサーを利用して、ドアが開いているか
閉じているのかを表示する回路を考える。
ドアのオープン、クローズはLEDの点灯、消灯で
表示してみる。
動作確認には、次のXC9572を実装した基板を利用。
超音波センサーは、60msの間隔をあけてTRGを
与えなければならないので、シーケンサを利用
して、周期処理を実現する。
シーケンスは、以下。
- 60msごとのトリガーを待つ。トリガーが着たら2ステートに遷移
- 外部カウンタリセット、TRGを出力し、3ステートに遷移
- タイムアウトかECHOの到着で、フラグに論理値を設定し、4ステートに遷移
- 1ステートにもどる
60msごとのトリガーは、後で考えるとして
シーケンスをコードで記述。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iGSTATE <= '0' ;
elsif rising_edge(iCLK) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iSTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- reset and send trigger
when 1 => iSTATE <= "11" ;
-- wait trigger
when 3 => if ( iURES = '1' ) then -- answer back
iSTATE <= "10" ;
iGSTATE <= '1' ;
elsif ( iTOUT = '1' ) then -- time out
iSTATE <= "10" ;
iGSTATE <= '0' ;
else
iSTATE <= "11" ;
end if ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
TRGのパルス幅は、10usなので、シーケンサは
この周期で動かす。
利用しているテスト基板のマスタークロックは
4MHzなので、100kHz(10us)を生成しシーケンサ
を動かすクロックとする。
単純な分周回路で実現。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(CLOCK) then
if ( iCNT = 39 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iCNT = 0 ) else '0' ; -- 100kHz(10us)
シーケンサを動かすため、必要になるトリガーは
3種類あるので、個別に考えていく。
60msトリガー
60msは10usを入力するカウンタで実現。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= 0 ;
elsif rising_edge(iCLK) then
if ( iSCNT = 5999 ) then
iSCNT <= 0 ;
else
iSCNT <= iSCNT + 1 ;
end if ;
end if ;
end process ;
iSTRG <= '1' when ( iSCNT = 0 ) else '0' ;
タイムアウトトリガー
音速を340m/sとして、超音波センサーと
ドアの間を200mmとすれば、往復に400mm
必要となり、3msあればECHOが返ってくる。
3msは10usを入力するカウンタで実現。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iTCNT <= 0 ;
elsif rising_edge(iCLK) then
if ( iSTATE = "01" or iTCNT = 300 ) then
iTCNT <= 0 ;
else
iTCNT <= iTCNT + 1 ;
end if ;
end if ;
end process ;
iTOUT <= '1' when ( iTCNT = 299 ) else '0' ;
シーケンサから、カウンタのリセットをかけるため
状態変数とロールフローで判定。
ECHOトリガー
ECHOのL→Hの変化をシフトレジスタを利用し捕捉。
チャタリングを除去する処理と同じように
シフトレジスタを使い、実現。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iURES_SFT <= "000" ;
elsif rising_edge(iCLK) then
iURES_SFT <= iURES_SFT(1 downto 0) & URES ;
end if ;
end process ;
iURES <= '1' when ( iURES_SFT = "001" ) else '0' ;
シーケンサと同期しながら動作すればよいので
シフトレジスタのクロックは、100kHzに。
以上をまとめる。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity usensor 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
MCLK : out std_logic ;
MGSTATE: out std_logic --;
);
end usensor ;
architecture behavioral of usensor is
-- divider
signal iCLK : std_logic ;
signal iCNT : integer range 0 to 39 ;
-- 60ms generator
signal iSTRG : std_logic ;
signal iSCNT : integer range 0 to 5999 ;
-- timer out generator
signal iTOUT : std_logic ;
signal iTCNT : integer range 0 to 300 ;
-- trigger
signal iURES : std_logic ;
signal iURES_SFT : std_logic_vector(2 downto 0) ;
-- sequencer
signal iSTATE : std_logic_vector(1 downto 0) ;
signal iGSTATE : std_logic ;
begin
-- output
UTRG <= '1' when ( iSTATE = "01" ) else '0' ;
GSTATE <= iGSTATE ;
-- monitor
MCLK <= not iCLK ;
MGSTATE <= not iGSTATE ;
-- clock divider CLOCK = 4MHz
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(CLOCK) then
if ( iCNT = 39 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iCNT = 0 ) else '0' ; -- 100kHz(10us)
-- 60ms generator
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= 0 ;
elsif rising_edge(iCLK) then
if ( iSCNT = 5999 ) then
iSCNT <= 0 ;
else
iSCNT <= iSCNT + 1 ;
end if ;
end if ;
end process ;
iSTRG <= '1' when ( iSCNT = 0 ) else '0' ;
-- time out
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iTCNT <= 0 ;
elsif rising_edge(iCLK) then
if ( iSTATE = "01" or iTCNT = 300 ) then
iTCNT <= 0 ;
else
iTCNT <= iTCNT + 1 ;
end if ;
end if ;
end process ;
iTOUT <= '1' when ( iTCNT = 299 ) else '0' ;
-- synchronizer
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iURES_SFT <= "000" ;
elsif rising_edge(iCLK) then
iURES_SFT <= iURES_SFT(1 downto 0) & URES ;
end if ;
end process ;
iURES <= '1' when ( iURES_SFT = "001" ) else '0' ;
-- sequencer
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iGSTATE <= '0' ;
elsif rising_edge(iCLK) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iSTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- reset and send trigger
when 1 => iSTATE <= "11" ;
-- wait trigger
when 3 => if ( iURES = '1' ) then -- answer back
iSTATE <= "10" ;
iGSTATE <= '1' ;
elsif ( iTOUT = '1' ) then -- time out
iSTATE <= "10" ;
iGSTATE <= '0' ;
else
iSTATE <= "11" ;
end if ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
end behavioral;
LEDを点灯、消灯は、正論理、負論理の
どちらも使えるように、2出力を用意。
ピンアサインは、以下
# system
NET "CLOCK" LOC = "P5" ;
NET "nRESET" LOC = "P39" ;
# sensor control
NET "UTRG" LOC = "P1" ;
NET "URES" LOC = "P2" ;
NET "MCLK" LOC = "P9" ; # monitor
# gate state
NET "GSTATE" LOC = "P11" ;
NET "MGSTATE" LOC = "P12" ; # monitor
接続は、次の中継コネクタを利用。
XC9572の最大容量72マクロセルのうち、37マクロ
セルを利用。マスタークロックを4MHzから1MHzに
変更すると、XC9536で充分。
目次
前
次