ラップタイマー作成
軽量マシン、産業用モータ利用マシンが完成したので
どのくらいの時間でコースを1周できるのか、測定を
してみることにしました。
コース横にストップウォッチを用意するよりも
マイコン、CPLD/FPGAを使った計時装置を用意
する方が、いろいろと応用が利くと考えラップ
タイマーを作成しました。
この大型LEDは、秋月電子で販売されていたキットを
流用しました。
本キットの回路図は、以下でした。
ダイナミック点灯でラップタイム表示するため
電源電圧を12Vとしたインタフェース回路を
次のようにしました。
7セグメントLEDは、アノードコモンなので
1けた毎に、電源を与えられるように、小信号
トランジスタを導通させます。
インタフェース回路は、基板に小さくまとめました。
表示回路が完成したので、ラップタイマーのファームウエア
あるいはデジタル回路を考えます。
今回は、デジタル回路で実現します。
デジタル回路を多数入れられる、CPLDを
利用します。
CPLDの中に入れるデジタル回路は、VHDLで
記述します。
表示はダイナミック点灯なので、ビットパターン
を出力後、けた選択信号を出力します。
シーケンスは、以下のようにしました。
- 1000の位の値をデコードし出力
- 1000の位を選択
- 100の位の値をデコードし出力
- 100の位を選択
- 10の位の値をデコードし出力
- 10の位を選択
- 1の位の値をデコードし出力
- 1の位を選択
シーケンサ実現するには、カウンタが必要なので
バイナリカウンタを使います。
カウンタの値を利用して、セレクタとエキサイタを
制御します。
-- display controller
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iDSTATE <= 0 ;
elsif rising_edge(iMCLK) then
-- counter handling
if ( iDSTATE = 8 ) then
iDSTATE <= 0 ;
else
iDSTATE <= iDSTATE + 1 ;
end if ;
end if ;
end process ;
iDIN0 <= conv_std_logic_vector(iA1000,4) ;
iDIN1 <= conv_std_logic_vector(iA100 ,4) ;
iDIN2 <= conv_std_logic_vector(iA10 ,4) ;
iDIN3 <= conv_std_logic_vector(iA1 ,4) ;
-- selector
iDOUT <= iDOUT0 when ( iDSTATE = 0 ) else
iDOUT1 when ( iDSTATE = 2 ) else
iDOUT2 when ( iDSTATE = 4 ) else
iDOUT3 when ( iDSTATE = 6 ) else
(others => '0') ;
-- exciter
iDSPENABLE <= "1000" when ( iDSTATE = 0 or iDSTATE = 1 ) else
"0100" when ( iDSTATE = 2 or iDSTATE = 3 ) else
"0010" when ( iDSTATE = 4 or iDSTATE = 5 ) else
"0001" when ( iDSTATE = 6 or iDSTATE = 7 ) else
"0000" ;
ラップタイマーの最小分解能は、0.1秒として
10の位に小数点を出力します。
10進カウンタの値を、7セグメントLEDの
ビットパターンに変換するコードは、別に
定義しました。
4ビット入力7ビット出力の組合せ回路で
実現しました。
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 <= iDOUT ;
-- conversion
-- abcdefg
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;
100msでラップを刻みますが、スタート/ゴールを横切った
ことをセンシングするためには、10ms周期のクロックを利用
した方が楽です。
複数のクロックを利用するので、クロックを扱うコードを
定義して利用します。
これまで利用してきたクロックジェネレータを利用します。
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;
マシンが、スタート/ゴールを横切ったかどうかは
フォトセンサーでとらえるとします。
センシングには、シフトレジスタを利用した
シンクロナイザで対応します。
シフトレジスタのクロックは、10ms周期として
以下のようにしました。
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iTRG_SFT <= iTRG_SFT(1 downto 0) & iSETRG ;
end if ;
end process ;
iTRG <= '1' when ( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ;
スタートとゴールのトリガーを同じにし
その間、ラップを刻むようにシーケンサ
を定義します。
iENABLE <= iSTATE(0) ;
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
elsif rising_edge(iMCLK) then
case conv_integer(iSTATE) is
-- wait start trigger
when 0 => if ( iTRG = '1' ) then
iSTATE <= "01" ;
end if ;
-- automatic transfer
when 1 => iSTATE <= "11" ;
-- wait exit trigger
when 3 => if ( iTRG = '1' ) then
iSTATE <= "10" ;
end if ;
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
Johnson Counterを利用し、デコーダを不要にしています。
シーケンサの出力信号で、ラップを刻むカウンタを
動かします。
4ビットカウンタを、4つ用意して
カウントアップします。
process (nRESET,iPCLK)
begin
if ( nRESET = '0' ) then
iA1000 <= 0 ;
iA100 <= 0 ;
iA10 <= 0 ;
iA1 <= 0 ;
elsif rising_edge(iPCLK) then
if ( iENABLE = '1' ) then
-- increment 100ms
iA1 <= iA1 + 1 ;
if ( iA1 = 10 ) then
iA1 <= 0 ;
iA10 <= iA10 + 1 ;
end if ;
-- clear 1s
if ( iA10 = 10 ) then
iA10 <= 0 ;
iA100 <= iA100 + 1 ;
end if ;
-- clear 10s
if ( iA100 = 10 ) then
iA100 <= 0 ;
iA1000 <= iA1000 + 1 ;
end if ;
-- clear 100s
if ( iA1000 = 10 ) then
iA1000 <= 0 ;
end if ;
end if ;
end if ;
end process ;
マスタークロックを1.8434MHzとし、CPLDにはXC9572XLを
利用します。全体をまとめると、以下です。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ledc is
generic (
TOPX : integer := 10 ;
RMAX : integer := 922 --;
);
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- input
SETRG : in std_logic ;
-- output
GLED : out std_logic ;
DSPENABLE : out std_logic_vector(3 downto 0) ;
LEDP : out std_logic_vector(7 downto 0) --;
);
end ledc;
architecture Behavioral of ledc is
-- clock 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 ;
-- LED pattern generator
component ledx is
port (
-- input
DIN : in std_logic_vector(3 downto 0);
-- output
DOUT : out std_logic_vector(6 downto 0) --;
);
end component ;
-- clock generator
signal iMCLK : std_logic ;
signal iPCLK : std_logic ;
signal iDCLK : std_logic ;
signal iCNT : integer range 0 to 50 ;
-- latch trigger
signal iSETRG : std_logic ;
signal iTRG : std_logic ;
signal iTRG_SFT : std_logic_vector(2 downto 0) ;
-- run sequencer
signal iSTATE : std_logic_vector(1 downto 0) ;
signal iENABLE : std_logic ;
-- counter
signal iA1000 : integer range 0 to 10 ;
signal iA100 : integer range 0 to 10 ;
signal iA10 : integer range 0 to 10 ;
signal iA1 : integer range 0 to 10 ;
signal iDIN0 : std_logic_vector(3 downto 0) ;
signal iDOUT0 : std_logic_vector(6 downto 0) ;
signal iDIN1 : std_logic_vector(3 downto 0) ;
signal iDOUT1 : std_logic_vector(6 downto 0) ;
signal iDIN2 : std_logic_vector(3 downto 0) ;
signal iDOUT2 : std_logic_vector(6 downto 0) ;
signal iDIN3 : std_logic_vector(3 downto 0) ;
signal iDOUT3 : std_logic_vector(6 downto 0) ;
signal iDOUT : std_logic_vector(6 downto 0) ;
-- 7 segment led controller
signal iDSTATE : integer range 0 to 8 ;
signal iDSPENABLE : std_logic_vector(3 downto 0) ;
signal iLEDP : std_logic_vector(7 downto 0) ;
begin
-- clock generator
CLKP : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iMCLK);
-- LED pattern generator
LEDPX0 : ledx port map (iDIN0,iDOUT0);
LEDPX1 : ledx port map (iDIN1,iDOUT1);
LEDPX2 : ledx port map (iDIN2,iDOUT2);
LEDPX3 : ledx port map (iDIN3,iDOUT3);
-- input
iSETRG <= not SETRG ;
-- output
DSPENABLE <= iDSPENABLE ;
LEDP <= iLEDP ;
GLED <= not iENABLE ;
-- internal handling
iLEDP(7) <= '1' when( iDSTATE = 4 or iDSTATE = 5 ) else '0' ;
iLEDP(6 downto 0) <= iDOUT ;
-- clock divider
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
iPCLK <= '0' ;
elsif rising_edge(iMCLK) then
-- judge
if ( iCNT = 50 ) then
iCNT <= 0 ;
iPCLK <= not iPCLK ;
else
-- increment
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
-- trigger handler
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iTRG_SFT <= iTRG_SFT(1 downto 0) & iSETRG ;
end if ;
end process ;
iTRG <= '1' when ( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ;
-- counter
process (nRESET,iPCLK)
begin
if ( nRESET = '0' ) then
iA1000 <= 0 ;
iA100 <= 0 ;
iA10 <= 0 ;
iA1 <= 0 ;
elsif rising_edge(iPCLK) then
if ( iENABLE = '1' ) then
-- increment 100ms
iA1 <= iA1 + 1 ;
if ( iA1 = 10 ) then
iA1 <= 0 ;
iA10 <= iA10 + 1 ;
end if ;
-- clear 1s
if ( iA10 = 10 ) then
iA10 <= 0 ;
iA100 <= iA100 + 1 ;
end if ;
-- clear 10s
if ( iA100 = 10 ) then
iA100 <= 0 ;
iA1000 <= iA1000 + 1 ;
end if ;
-- clear 100s
if ( iA1000 = 10 ) then
iA1000 <= 0 ;
end if ;
end if ;
end if ;
end process ;
-- run sequencer
iENABLE <= iSTATE(0) ;
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
elsif rising_edge(iMCLK) then
case conv_integer(iSTATE) is
-- wait start trigger
when 0 => if ( iTRG = '1' ) then
iSTATE <= "01" ;
end if ;
-- automatic transfer
when 1 => iSTATE <= "11" ;
-- wait exit trigger
when 3 => if ( iTRG = '1' ) then
iSTATE <= "10" ;
end if ;
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
-- display controller
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iDSTATE <= 0 ;
elsif rising_edge(iMCLK) then
-- counter handling
if ( iDSTATE = 8 ) then
iDSTATE <= 0 ;
else
iDSTATE <= iDSTATE + 1 ;
end if ;
end if ;
end process ;
iDIN0 <= conv_std_logic_vector(iA1000,4) ;
iDIN1 <= conv_std_logic_vector(iA100 ,4) ;
iDIN2 <= conv_std_logic_vector(iA10 ,4) ;
iDIN3 <= conv_std_logic_vector(iA1 ,4) ;
-- selector
iDOUT <= iDOUT0 when ( iDSTATE = 0 ) else
iDOUT1 when ( iDSTATE = 2 ) else
iDOUT2 when ( iDSTATE = 4 ) else
iDOUT3 when ( iDSTATE = 6 ) else
(others => '0') ;
-- exciter
iDSPENABLE <= "1000" when ( iDSTATE = 0 or iDSTATE = 1 ) else
"0100" when ( iDSTATE = 2 or iDSTATE = 3 ) else
"0010" when ( iDSTATE = 4 or iDSTATE = 5 ) else
"0001" when ( iDSTATE = 6 or iDSTATE = 7 ) else
"0000" ;
end Behavioral;
XC9572XLのピンアサインは、以下としました。
NET "nRESET" LOC = "P33" ;
NET "CLOCK" LOC = "P1" ;
# group A
NET "LEDP<7>" LOC = "P36" ;
NET "LEDP<6>" LOC = "P37" ;
NET "LEDP<5>" LOC = "P38" ;
NET "LEDP<4>" LOC = "P39" ;
NET "LEDP<3>" LOC = "P40" ;
NET "LEDP<2>" LOC = "P41" ;
NET "LEDP<1>" LOC = "P42" ;
NET "LEDP<0>" LOC = "P43" ;
# group B
NET "DSPENABLE<0>" LOC = "P34" ;
NET "DSPENABLE<1>" LOC = "P32" ;
NET "DSPENABLE<2>" LOC = "P31" ;
NET "DSPENABLE<3>" LOC = "P30" ;
# group C(7bits)
NET "SETRG" LOC = "P7" ;
NET "GLED" LOC = "P2" ;
動かしてみると、常に4けたに数値を表示しています。
省エネの観点から、ゼロプレス処理を入れました。
最下位けたは常に表示し、他のけたは、0であることを
判定して、エキサイタを動かすかどうかを決めます。
3つのけたが、0かどうかをフラグで設定します。
iZF3 <= '1' when ( iA1000 = 0 ) else '0' ;
iZF2 <= '1' when ( iA100 = 0 ) else '0' ;
iZF1 <= '1' when ( iA10 = 0 ) else '0' ;
エキサイタの各ビットを、判定条件を入れて1か0に
設定します。
iDSPENABLE(3) <= '1' when ( iDSTATE = 1 and iZF3 = '0' ) else
'0' ;
iDSPENABLE(2) <= '1' when ( iDSTATE = 3 and iZF3 = '0' ) else
'1' when ( iDSTATE = 3 and iZF2 = '0' ) else
'0' ;
iDSPENABLE(1) <= '1' when ( iDSTATE = 5 and iZF3 = '0' ) else
'1' when ( iDSTATE = 5 and iZF2 = '0' ) else
'1' when ( iDSTATE = 5 and iZF1 = '0' ) else
'0' ;
iDSPENABLE(0) <= '1' when ( iDSTATE = 7 ) else
'0' ;
まとめると、以下となります。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ledc is
generic (
TOPX : integer := 10 ;
RMAX : integer := 922 --;
);
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- input
SETRG : in std_logic ;
-- output
GLED : out std_logic ;
DSPENABLE : out std_logic_vector(3 downto 0) ;
LEDP : out std_logic_vector(7 downto 0) --;
);
end ledc;
architecture Behavioral of ledc is
-- clock 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 ;
-- LED pattern generator
component ledx is
port (
-- input
DIN : in std_logic_vector(3 downto 0);
-- output
DOUT : out std_logic_vector(6 downto 0) --;
);
end component ;
-- clock generator
signal iMCLK : std_logic ;
signal iPCLK : std_logic ;
signal iDCLK : std_logic ;
signal iCNT : integer range 0 to 50 ;
-- latch trigger
signal iSETRG : std_logic ;
signal iTRG : std_logic ;
signal iTRG_SFT : std_logic_vector(2 downto 0) ;
-- run sequencer
signal iSTATE : std_logic_vector(1 downto 0) ;
signal iENABLE : std_logic ;
-- counter
signal iA1000 : integer range 0 to 10 ;
signal iA100 : integer range 0 to 10 ;
signal iA10 : integer range 0 to 10 ;
signal iA1 : integer range 0 to 10 ;
signal iDIN : std_logic_vector(3 downto 0) ;
signal iDOUT : std_logic_vector(6 downto 0) ;
signal iZF3 : std_logic ;
signal iZF2 : std_logic ;
signal iZF1 : std_logic ;
-- 7 segment led controller
signal iDSTATE : integer range 0 to 8 ;
signal iDSPENABLE : std_logic_vector(3 downto 0) ;
signal iLEDP : std_logic_vector(7 downto 0) ;
begin
-- clock generator
CLKP : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iMCLK);
-- LED pattern generator
LEDPX0 : ledx port map (iDIN,iDOUT);
-- input
iSETRG <= not SETRG ;
-- output
DSPENABLE <= iDSPENABLE ;
LEDP <= iLEDP ;
GLED <= not iENABLE ;
-- internal handling
iLEDP(7) <= '1' when( iDSTATE = 4 or iDSTATE = 5 ) else '0' ;
iLEDP(6 downto 0) <= iDOUT ;
-- clock divider
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
iPCLK <= '0' ;
elsif rising_edge(iMCLK) then
-- judge
if ( iCNT = 50 ) then
iCNT <= 0 ;
iPCLK <= not iPCLK ;
else
-- increment
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
-- trigger handler
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iTRG_SFT <= iTRG_SFT(1 downto 0) & iSETRG ;
end if ;
end process ;
iTRG <= '1' when ( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ;
-- counter
process (nRESET,iPCLK)
begin
if ( nRESET = '0' ) then
iA1000 <= 0 ;
iA100 <= 0 ;
iA10 <= 0 ;
iA1 <= 0 ;
elsif rising_edge(iPCLK) then
if ( iENABLE = '1' ) then
-- increment 100ms
iA1 <= iA1 + 1 ;
if ( iA1 = 10 ) then
iA1 <= 0 ;
iA10 <= iA10 + 1 ;
end if ;
-- clear 1s
if ( iA10 = 10 ) then
iA10 <= 0 ;
iA100 <= iA100 + 1 ;
end if ;
-- clear 10s
if ( iA100 = 10 ) then
iA100 <= 0 ;
iA1000 <= iA1000 + 1 ;
end if ;
-- clear 100s
if ( iA1000 = 10 ) then
iA1000 <= 0 ;
end if ;
end if ;
end if ;
end process ;
iZF3 <= '1' when ( iA1000 = 0 ) else '0' ;
iZF2 <= '1' when ( iA100 = 0 ) else '0' ;
iZF1 <= '1' when ( iA10 = 0 ) else '0' ;
-- run sequencer
iENABLE <= iSTATE(0) ;
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
elsif rising_edge(iMCLK) then
case conv_integer(iSTATE) is
-- wait start trigger
when 0 => if ( iTRG = '1' ) then
iSTATE <= "01" ;
end if ;
-- automatic transfer
when 1 => iSTATE <= "11" ;
-- wait exit trigger
when 3 => if ( iTRG = '1' ) then
iSTATE <= "10" ;
end if ;
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
-- display controller
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iDSTATE <= 0 ;
elsif rising_edge(iMCLK) then
-- counter handling
if ( iDSTATE = 8 ) then
iDSTATE <= 0 ;
else
iDSTATE <= iDSTATE + 1 ;
end if ;
end if ;
end process ;
iDIN <= conv_std_logic_vector(iA1000,4) when ( iDSTATE = 0 or iDSTATE = 1 ) else
conv_std_logic_vector(iA100 ,4) when ( iDSTATE = 2 or iDSTATE = 3 ) else
conv_std_logic_vector(iA10 ,4) when ( iDSTATE = 4 or iDSTATE = 5 ) else
conv_std_logic_vector(iA1 ,4) ;
-- exciter
iDSPENABLE(3) <= '1' when ( iDSTATE = 1 and iZF3 = '0' ) else
'0' ;
iDSPENABLE(2) <= '1' when ( iDSTATE = 3 and iZF3 = '0' ) else
'1' when ( iDSTATE = 3 and iZF2 = '0' ) else
'0' ;
iDSPENABLE(1) <= '1' when ( iDSTATE = 5 and iZF3 = '0' ) else
'1' when ( iDSTATE = 5 and iZF2 = '0' ) else
'1' when ( iDSTATE = 5 and iZF1 = '0' ) else
'0' ;
iDSPENABLE(0) <= '1' when ( iDSTATE = 7 ) else
'0' ;
end Behavioral;
CPLDで動作確認できたので、マイコンでも実現しました。
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define OFF 0
#define ON OFF+1
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
#define SMAX 10
#define TMAX 100
#define MASKF0 0xf0
#define DSPA1000 0x08
#define DSPA100 0x04
#define DSPA10 0x02
#define DSPA1 0x01
#define DLAST 8
volatile UBYTE sft ;
volatile UBYTE sflag ;
volatile UBYTE iflag ;
volatile UBYTE state ;
volatile UBYTE scntx ;
volatile UBYTE tcntx ;
volatile UBYTE tflag ;
volatile UBYTE dflag ;
volatile UBYTE a1 ;
volatile UBYTE a10 ;
volatile UBYTE a100 ;
volatile UBYTE a1000 ;
volatile UBYTE dstate ;
volatile UBYTE ledpat[10] ;
volatile UBYTE izf3 ;
volatile UBYTE izf2 ;
volatile UBYTE izf1 ;
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
void dsp_proc(void);
void trg_proc(void);
void count_proc(void);
/*------*/
/* main */
/*------*/
int main(void)
{
/* initialize monitor */
user_initialize();
/* enable interrupt */
sei() ;
/* endless loop */
while ( ON ) {
/* display */
if ( dflag == ON ) {
/* clear flag */
dflag = OFF ;
/* perform */
dsp_proc();
}
/* trigger handling */
if ( sflag == ON ) {
/* clear flag */
sflag = OFF ;
/* perform */
trg_proc();
}
/* master handling */
switch ( state ) {
/* wait start trigger */
case 0 : if ( iflag ) {
state = 1 ;
PORTD &= ~0x40 ;
}
break ;
/* auto transfer */
case 1 : state = 2 ;
break ;
/* wait goal trigger */
case 2 : if ( iflag ) {
state = 3 ;
PORTD |= 0x40 ;
}
break ;
/* return first state */
case 3 : state = 0 ;
break ;
/* default */
default:
break ;
}
/* count up */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* perform */
if ( state == 2 ) { count_proc(); }
}
}
/* dummy */
return 0 ;
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
/* PORT B */
PORTB = 0b00000000 ; /* 00000000 */
DDRB = 0b11111111 ; /* oooooooo */
/* PORT D */
PORTD = 0b01010000 ; /* 00000000 */
DDRD = 0b11101111 ; /* ooiooooo */
/* initialize timer1 */
{
/* clear counter */
TCNT1 = 0 ;
/* set compare value */
OCR1A = 499 ;
OCR1B = 999 ;
/* inhibit compare match output , select CTC mode */
/* prescaler /8 => 500kHz */
TCCR1B = (1 << CS11) | (1 << WGM12);
/* enable compare match */
TIMSK = (1 << OCIE1A) ;
}
/* clear */
sft = 0 ;
sflag = OFF ;
scntx = 0 ;
state = 0 ;
iflag = OFF ;
dstate = 0 ;
dflag = OFF ;
tflag = OFF ;
tcntx = 0 ;
/* initialize counters */
a1 = 0 ;
a10 = 0 ;
a100 = 0 ;
a1000 = 0 ;
/* pattern */
*(ledpat+0) = 0b1111110 ; /* 0 */
*(ledpat+1) = 0b0110000 ; /* 1 */
*(ledpat+2) = 0b1101101 ; /* 2 */
*(ledpat+3) = 0b1111001 ; /* 3 */
*(ledpat+4) = 0b0110011 ; /* 4 */
*(ledpat+5) = 0b1011011 ; /* 5 */
*(ledpat+6) = 0b1011111 ; /* 6 */
*(ledpat+7) = 0b1110010 ; /* 7 */
*(ledpat+8) = 0b1111111 ; /* 8 */
*(ledpat+9) = 0b1111011 ; /* 9 */
/* set flags */
izf3 = OFF ;
izf2 = OFF ;
izf1 = OFF ;
}
void dsp_proc(void)
{
/* judge */
switch ( dstate ) {
case 0 : PORTB = ledpat[a1000] ;
PORTD &= MASKF0 ;
break ;
case 1 : if ( izf3 == OFF ) { PORTD |= DSPA1000 ; }
break ;
case 2 : PORTB = ledpat[a100] ;
PORTD &= MASKF0 ;
break ;
case 3 : if ( izf3 == OFF || izf2 == OFF ) {
PORTD |= DSPA100 ;
}
break ;
case 4 : PORTB = 0x80 | ledpat[a10] ;
PORTD &= MASKF0 ;
break ;
case 5 : if ( izf3 == OFF || izf2 == OFF || izf1 == OFF ) {
PORTD |= DSPA10 ;
}
break ;
case 6 : PORTB = ledpat[a1] ;
PORTD &= MASKF0 ;
break ;
case 7 : PORTD |= DSPA1 ;
break ;
default:
break ;
}
/* update */
dstate++ ;
if ( dstate == DLAST ) { dstate = 0 ; }
}
void trg_proc(void)
{
/* shift */
sft <<= 1 ;
sft &= 0x07 ;
/* get data */
if ( PIND & 0x10 ) { sft |= ON ; }
/* judge */
iflag = OFF ;
if ( sft == 3 || sft == 1 ) { iflag = ON ; }
}
void count_proc(void)
{
a1++ ;
if ( a1 == 10 ) {
a1 = 0 ;
a10++ ;
}
if ( a10 == 10 ) {
a10 = 0 ;
a100++ ;
}
if ( a100 == 10 ) {
a100 = 0 ;
a1000++ ;
}
if ( a1000 == 10 ) {
a1000 = 0 ;
}
/* judge */
if ( a1000 == 0 ) { izf3 = ON ; }
if ( a100 == 0 ) { izf2 = ON ; }
if ( a10 == 0 ) { izf1 = ON ; }
}
/* timer0 comare match interrupt */
ISR(TIMER1_COMPA_vect)
{
/* display handling (1ms) */
dflag = ON ;
/* 10ms handling */
scntx++ ;
if ( scntx == SMAX ) {
scntx = 0 ;
sflag = ON ;
}
/* 100ms handling */
tcntx++ ;
if ( tcntx == TMAX ) {
tcntx = 0 ;
tflag = ON ;
}
}
4MHzのクロックで動かす仕様にしてあります。
利用したマイコンは、ATMELのATTiny2313で、ピンアサインは
次のようにしました。
Port B
PB7 led_pat7(Dp)
PB6 led_pat6(a)
PB5 led_pat5(b)
PB4 led_pat4(c)
PB3 led_pat3(d)
PB2 led_pat2(e)
PB1 led_pat1(f)
PB0 led_pat0(g)
Port D
PD6 GLED <status green LED>
PD5 (no connection)
PD4 SGTRG <trigger>
PD3 dspenable3 <select A1000>
PD2 dspenable2 <select A100>
PD1 dspenable1 <select A10>
PD0 dspenable0 <select A1>
トリガー入力のデバイスは、以下の光電スイッチを
使います。
目次
前
次