目次
前
次
移動ブロック
MCR_VCでは、マイコン、モータ等の種別は自由なので
今回は、パルスモータを利用します。
大阪にあるデジットで、1個¥100(税別)で入手して
あったものを、利用します。
データシートは、次のような紙が入っていただけでした。
特性を調べるために、ドライブ回路を半田付けです。
コイルの抵抗が300Ωと書かれていたので、+5Vから+12V
を印加時に、ドライブ回路に流れる電流は、1相あたり
最大でも40mAです。ドライブ回路起動で3倍近くの電流が
流れたとしても120mAなので、小信号トランジスタで充分
対応できると判断しました。
小信号トランジスタを8本並べると、コイルの逆起電力による
破損防止に、8本のフライホイールダイオードが必要です。
基板に多くの部品を実装すると、動かない場合の原因を見つける
のが面倒と考え、トランジスタアレイを利用し、内蔵ダイオード
を活用します。
トランジスタアレイを利用すると、回路は以下のように単純に
なりました。
パルスモータには、パルスを与えなければならないので
CPLDを利用し、簡単な試験回路を構成しました。
仕様は、単純にしてあります。
- パルスモータを2個ドライブ
- 励磁方式は、1相
- 各パルスモータには、回転方向指定、パルスカットの制御ピンを用意
- パルスモータを左右に配置するので、左右の回転方向を配線で入れ替える
- パルス周波数は、100Hz固定
仕様から、CPLDの内部ブロックは、以下としています。
このブロック図からVHDLコードを記述し、XilinxのXC9572
CPLD基板に回路情報を転送します。
VHDLコードは、以下。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pmtstx is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ; -- 4MHz
-- pulse enable
PENA : in std_logic_vector(1 downto 0) ;
CCW : in std_logic_vector(1 downto 0) ;
-- motor control
RDECOUT : out std_logic_vector(3 downto 0) ;
LDECOUT : out std_logic_vector(3 downto 0) ;
CLKOUT : out std_logic_vector(1 downto 0) -- ;
);
end pmtstx ;
architecture behavioral of pmtstx is
-- divider
signal iCNT : integer range 0 to 39999 ;
signal iCLK : std_logic ;
-- decoder
signal iDECOUTR : std_logic_vector(3 downto 0) ;
signal iDECOUTL : std_logic_vector(3 downto 0) ;
-- iREG
signal iREGR : std_logic_vector(3 downto 0) ;
signal iREGL : std_logic_vector(3 downto 0) ;
-- counter
signal iSCNT : std_logic_vector(1 downto 0) ;
begin
-- outputs
RDECOUT <= iREGR when ( PENA(0) = '1' ) else (others => 'Z') ;
LDECOUT <= iREGL when ( PENA(1) = '1' ) else (others => 'Z') ;
CLKOUT <= iSCNT ;
-- divider
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(CLOCK) then
if ( iCNT = 39999 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iCNT = 0 ) else '0' ;
-- decoder
iDECOUTR <= X"8" when ( iSCNT = "00" ) else
X"4" when ( iSCNT = "01" ) else
X"2" when ( iSCNT = "11" ) else
X"1" when ( iSCNT = "10" ) else
X"0" ;
iDECOUTL <= X"1" when ( iSCNT = "00" ) else
X"2" when ( iSCNT = "01" ) else
X"4" when ( iSCNT = "11" ) else
X"8" when ( iSCNT = "10" ) else
X"0" ;
iREGR <= iDECOUTR when ( CCW(0) = '1' ) else iDECOUTL ;
iREGL <= iDECOUTR when ( CCW(1) = '1' ) else iDECOUTL ;
-- counter
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= "00" ;
elsif rising_edge(iCLK) then
case conv_integer(iSCNT) is
when 0 => iSCNT <= "01" ;
when 1 => iSCNT <= "11" ;
when 3 => iSCNT <= "10" ;
when 2 => iSCNT <= "00" ;
when others =>
iSCNT <= "00" ;
end case ;
end if ;
end process ;
end behavioral;
左右のパルスモータの回転方向は、逆になるので
使う場合には、配線を逆にして対応します。
配線は、次のように定義しました。
# system
NET "CLOCK" LOC = "P5" ;
NET "nRESET" LOC = "P39" ;
# pulse outputs
NET "RDECOUT<3>" LOC = "P1" ;
NET "RDECOUT<2>" LOC = "P2" ;
NET "RDECOUT<1>" LOC = "P3" ;
NET "RDECOUT<0>" LOC = "P4" ;
NET "LDECOUT<0>" LOC = "P6" ;
NET "LDECOUT<1>" LOC = "P7" ;
NET "LDECOUT<2>" LOC = "P8" ;
NET "LDECOUT<3>" LOC = "P9" ;
# pulse control
NET "PENA<0>" LOC = "P11" ;
NET "PENA<1>" LOC = "P12" ;
NET "CCW<0>" LOC = "P13" ;
NET "CCW<1>" LOC = "P14" ;
# monitor
NET "CLKOUT<0>" LOC = "P43" ;
NET "CLKOUT<1>" LOC = "P44" ;
利用したマクロセル数は、26/72で半分以下です。
この中には分周器も含まれているので、16マクロ
セル程度で、回転を制御できると考えられます。
2相励磁試験
パルスモータは、1相励磁の他に2相励磁も可能ですが
手持ちのデバイスで2相励磁できるか試験します。
2相励磁のデコーダを定義します。
1相励磁の場合は、4ピンのうちのどれか1ピンを
Hレベルとして、コイルと接続されたトランジスタ
のひとつをオン状態にします。
A 1 0 0 0
B 0 1 0 0
nA 0 0 1 0
nB 0 0 0 1
2相励磁では、4つのトランジスタのうち
2つをオン状態にします。
A 1 0 0 1
B 1 1 0 0
nA 0 1 1 0
nB 0 0 1 1
VHDLで記述しているデコーダ部分を変更します。
iDECOUTR <= X"C" when ( iSCNT = "00" ) else
X"6" when ( iSCNT = "01" ) else
X"3" when ( iSCNT = "11" ) else
X"9" when ( iSCNT = "10" ) else
X"0" ;
iDECOUTL <= X"C" when ( iSCNT = "00" ) else
X"9" when ( iSCNT = "01" ) else
X"3" when ( iSCNT = "11" ) else
X"6" when ( iSCNT = "10" ) else
X"0" ;
2相励磁は1相励磁に比べ、トルクが大きくなり
振動が少なくなります。
1相励磁はトルクが小さいので、クローラを使う
場面では、利用しません。
1−2相励磁試験
パルスモータは、1相励磁、2相励磁に加えて
1−2相励磁も可能です。
1相励磁の間に、2相励磁を挟みます。
1相励磁、2相励磁ともに4状態をもつので
1−2相励磁の場合、8状態のために3ビット
カウンタを使います。
デコーダは、次のように定義します。
iDECOUTR <= X"8" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"6" when ( iSCNT = "011" ) else
X"2" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"9" when ( iSCNT = "111" ) else
X"0" ;
iDECOUTL <= X"2" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"9" when ( iSCNT = "011" ) else
X"8" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"6" when ( iSCNT = "111" ) else
X"0" ;
8状態を作るには、3ビットのカウンタを使います。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= "000" ;
elsif rising_edge(iCLK) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
1−2相励磁のVHDLコードは、以下となります。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pmtst is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- pulse enable
PENA : in std_logic_vector(1 downto 0) ;
CCW : in std_logic_vector(1 downto 0) ;
-- motor control
RDECOUT : out std_logic_vector(3 downto 0) ;
LDECOUT : out std_logic_vector(3 downto 0) ;
CLKOUT : out std_logic_vector(2 downto 0) -- ;
);
end pmtst ;
architecture behavioral of pmtst is
-- divider
signal iCNT : integer range 0 to 39999 ;
signal iCLK : std_logic ;
-- decoder
signal iDECOUTR : std_logic_vector(3 downto 0) ;
signal iDECOUTL : std_logic_vector(3 downto 0) ;
-- iREG
signal iREGR : std_logic_vector(3 downto 0) ;
signal iREGL : std_logic_vector(3 downto 0) ;
-- counter
signal iSCNT : std_logic_vector(2 downto 0) ;
begin
-- outputs
RDECOUT <= iREGR when ( PENA(0) = '1' ) else (others => 'Z') ;
LDECOUT <= iREGL when ( PENA(1) = '1' ) else (others => 'Z') ;
CLKOUT <= iSCNT ;
-- divider
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(CLOCK) then
if ( iCNT = 39999 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iCNT = 0 ) else '0' ;
-- decoder
iDECOUTR <= X"8" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"6" when ( iSCNT = "011" ) else
X"2" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"9" when ( iSCNT = "111" ) else
X"0" ;
iDECOUTL <= X"2" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"9" when ( iSCNT = "011" ) else
X"8" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"6" when ( iSCNT = "111" ) else
X"0" ;
iREGR <= iDECOUTR when ( CCW(0) = '1' ) else iDECOUTL ;
iREGL <= iDECOUTR when ( CCW(1) = '1' ) else iDECOUTL ;
-- counter
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= "000" ;
elsif rising_edge(iCLK) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
end behavioral;
カウンタ値のモニタを変更しておきます。
# system
NET "CLOCK" LOC = "P5" ;
NET "nRESET" LOC = "P39" ;
# pulse outputs
NET "RDECOUT<3>" LOC = "P1" ;
NET "RDECOUT<2>" LOC = "P2" ;
NET "RDECOUT<1>" LOC = "P3" ;
NET "RDECOUT<0>" LOC = "P4" ;
NET "LDECOUT<0>" LOC = "P6" ;
NET "LDECOUT<1>" LOC = "P7" ;
NET "LDECOUT<2>" LOC = "P8" ;
NET "LDECOUT<3>" LOC = "P9" ;
# pulse control
NET "PENA<0>" LOC = "P11" ;
NET "PENA<1>" LOC = "P12" ;
NET "CCW<0>" LOC = "P13" ;
NET "CCW<1>" LOC = "P14" ;
# monitor
NET "CLKOUT<0>" LOC = "P42" ;
NET "CLKOUT<1>" LOC = "P43" ;
NET "CLKOUT<2>" LOC = "P44" ;
実用に即して、1−2相励磁を採用します。
パルス数による制御
オープンループ制御で動作させるには、パルス数を
与えて、回転が停止するまで待つ方が楽です。
CPLD内部に12ビットのカウンタを用意し、このカウンタに
与えたパルス数だけ回転後、自動停止するデジタル回路を
定義していきます。
マイクロコンピュータとのインタフェースは、8ビットx2
程度に抑えたいので、8ビットのポートを2つ利用します。
マイコンから見て、ライトとリードの専用ポートを使う仕様で
考えていきます。
ライト専用ポートは、4ビットデータと内部レジスタが
あるとして、次のようにビットを割り当てします。
- B7 trigger
- B6 register number 2
- B5 register number 1
- B4 register number 0
- B3 register data 3
- B2 register data 2
- B1 register data 1
- B0 register data 0
パラメータを4ビットのデータとして
CPLD内部のカウンタに分割転送します。
また、回転方向と回転開始を指定します。
レジスタ番号と内部レジスタのビット割当ては
次のように定義します。
controlレジスタは、左右のモータの回転方向と
パルス出力トリガーで使います。
最上位ビットが出力トリガー、中間ビットが左
モータの回転方向、最下位ビットが右モータの
回転方向を指定します。
リード専用ポートは、2ビットで左、右のモータ回転中
を示すフラグとします。
マイコンとのインタフェースを定義したので、CPLD内部
のブロック図を作成し、VHDLコードに変換します。
内部ブロック図は、以下としました。
バスインタフェースを利用し、左右のカウント値をレジスタに
転送しておきます。カウンタ値の他に、回転方向と回転開始の
トリガーを担当する3ビットレジスタを用意します。
バスインタフェースは、3ビットのレジスタ番号、4ビットの
データ値、トリガーを含めて8ビットで対応です。
回転開始のトリガーを受けると、1−2相励磁のビットパターン
を出力していきます。同時にカウンタをデクリメントし、ゼロに
なったなら、4ビットの励磁パターンを0000にします。
カウンタデクリメントは、ビットパターン生成用の
3ビットカウンタを駆動しているクロックのエッジ
を使います。
ビットパターン生成用クロックのエッジをシフトレジスタ
を使い、判断します。
CPLDのX9572では、収容しきれないと判断し、XC95018を
利用します。VHDLコードは、以下。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pmtst is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- BUS interface
BTRG : in std_logic ;
BADR : in std_logic_vector(2 downto 0) ;
BDAT : in std_logic_vector(3 downto 0) ;
BSTA : out std_logic_vector(1 downto 0) ;
-- motor control
RDECOUT : out std_logic_vector(3 downto 0) ;
LDECOUT : out std_logic_vector(3 downto 0) ;
CLKOUT : out std_logic_vector(2 downto 0) -- ;
);
end pmtst ;
architecture behavioral of pmtst is
-- divider
signal iCNT : integer range 0 to 39999 ;
signal iCLK : std_logic ;
signal iCLK_SFT : std_logic_vector(1 downto 0) ;
signal iSTRG : std_logic ;
-- decoder
signal iDECOUTR : std_logic_vector(3 downto 0) ;
signal iDECOUTL : std_logic_vector(3 downto 0) ;
-- iREG
signal iREGR : std_logic_vector(3 downto 0) ;
signal iREGL : std_logic_vector(3 downto 0) ;
-- counter
signal iSCNT : std_logic_vector(2 downto 0) ;
signal iPENA : std_logic_vector(1 downto 0) ;
-- internal registers
signal iBTRG_SFT : std_logic_vector(2 downto 0) ;
signal iBTRGX : std_logic ;
signal iMLCNT : std_logic_vector(11 downto 0) ;
signal iMRCNT : std_logic_vector(11 downto 0) ;
signal iMCON : std_logic_vector(2 downto 0) ;
signal iMLCNTX : integer range 0 to 4095 ;
signal iMSTATEL : std_logic_vector(1 downto 0) ;
signal iMRCNTX : integer range 0 to 4095 ;
signal iMSTATER : std_logic_vector(1 downto 0) ;
begin
-- outputs
RDECOUT <= iREGR when ( iPENA(0) = '1' ) else (others => 'Z') ;
LDECOUT <= iREGL when ( iPENA(1) = '1' ) else (others => 'Z') ;
CLKOUT <= iSCNT ;
BSTA <= iPENA ;
-- BUS interface
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iMLCNT <= (others => '0') ;
iMRCNT <= (others => '0') ;
iMCON <= "000" ;
elsif rising_edge(CLOCK) then
if ( iBTRGX = '1' ) then
-- reg 0
if ( BADR = "000" ) then
iMRCNT(11 downto 8) <= BDAT ;
end if ;
-- reg 1
if ( BADR = "001" ) then
iMRCNT(7 downto 4) <= BDAT ;
end if ;
-- reg 2
if ( BADR = "010" ) then
iMRCNT(3 downto 0) <= BDAT ;
end if ;
-- reg 3
if ( BADR = "011" ) then
iMCON <= BDAT(2 downto 0) ;
end if ;
-- reg 4
if ( BADR = "100" ) then
iMLCNT(11 downto 8) <= BDAT ;
end if ;
-- reg 5
if ( BADR = "101" ) then
iMLCNT(7 downto 4) <= BDAT ;
end if ;
-- reg 6
if ( BADR = "110" ) then
iMLCNT(3 downto 0) <= BDAT ;
end if ;
end if ;
end if ;
end process ;
-- clock detect
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCLK_SFT <= "00" ;
elsif rising_edge(CLOCK) then
iCLK_SFT <= iCLK_SFT(0) & iCLK ;
end if ;
end process ;
iSTRG <= '1' when ( iCLK_SFT = "01" ) else '0' ;
-- left motor control
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iMLCNTX <= 0 ;
iMSTATEL <= "00" ;
elsif rising_edge(CLOCK) then
case conv_integer(iMSTATEL) is
-- wait trigger and set counter
when 0 => if ( iMCON(2) = '1' ) then
iMLCNTX <= conv_integer(iMLCNT) ;
iMSTATEL <= "01" ;
else
iMSTATEL <= "00" ;
end if ;
-- detect pulse
when 1 => if ( iSTRG = '1' ) then
iMLCNTX <= iMLCNTX - 1 ;
iMSTATEL <= "11" ;
else
iMSTATEL <= "01" ;
end if ;
-- judge
when 3 => if ( iMLCNTX = 0 ) then
iMSTATEL <= "10" ;
else
iMSTATEL <= "01" ;
end if ;
-- return first state
when 2 => iMSTATEL <= "00" ;
-- default
when others =>
iMSTATEL <= "00" ;
end case ;
end if ;
end process ;
iPENA(1) <= '1' when ( iMSTATEL(0) = '1' ) else '0' ;
-- right motor control
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iMRCNTX <= 0 ;
iMSTATER <= "00" ;
elsif rising_edge(CLOCK) then
case conv_integer(iMSTATER) is
-- wait trigger and set counter
when 0 => if ( iMCON(2) = '1' ) then
iMRCNTX <= conv_integer(iMRCNT) ;
iMSTATER <= "01" ;
else
iMSTATER <= "00" ;
end if ;
-- detect pulse
when 1 => if ( iSTRG = '1' ) then
iMRCNTX <= iMRCNTX - 1 ;
iMSTATER <= "11" ;
else
iMSTATER <= "01" ;
end if ;
-- judge
when 3 => if ( iMRCNTX = 0 ) then
iMSTATER <= "10" ;
else
iMSTATER <= "01" ;
end if ;
-- return first state
when 2 => iMSTATER <= "00" ;
-- default
when others =>
iMSTATER <= "00" ;
end case ;
end if ;
end process ;
iPENA(0) <= '1' when ( iMSTATER(0) = '1' ) else '0' ;
-- divider
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
iBTRG_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ;
if ( iCNT = 39999 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iBTRGX <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ;
iCLK <= '1' when ( iCNT = 0 ) else '0' ;
-- decoder
iDECOUTR <= X"8" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"6" when ( iSCNT = "011" ) else
X"2" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"9" when ( iSCNT = "111" ) else
X"0" ;
iDECOUTL <= X"2" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"9" when ( iSCNT = "011" ) else
X"8" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"6" when ( iSCNT = "111" ) else
X"0" ;
iREGR <= iDECOUTR when ( iMCON(0) = '1' ) else iDECOUTL ;
iREGL <= iDECOUTR when ( iMCON(1) = '1' ) else iDECOUTL ;
-- counter
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= "000" ;
elsif rising_edge(iCLK) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
end behavioral;
ピンアサインは、以下としました。
# system
NET "CLOCK" LOC = "P9" ;
NET "nRESET" LOC = "P74" ;
# motor control
NET "RDECOUT<0>" LOC = "P17" ;
NET "RDECOUT<1>" LOC = "P18" ;
NET "RDECOUT<2>" LOC = "P19" ;
NET "RDECOUT<3>" LOC = "P20" ;
NET "LDECOUT<0>" LOC = "P21" ;
NET "LDECOUT<1>" LOC = "P23" ;
NET "LDECOUT<2>" LOC = "P24" ;
NET "LDECOUT<3>" LOC = "P25" ;
NET "CLKOUT<0>" LOC = "P31" ;
NET "CLKOUT<1>" LOC = "P32" ;
NET "CLKOUT<2>" LOC = "P33" ;
# BUS interface
NET "BDAT<0>" LOC = "P1" ;
NET "BDAT<1>" LOC = "P2" ;
NET "BDAT<2>" LOC = "P3" ;
NET "BDAT<3>" LOC = "P4" ;
NET "BADR<0>" LOC = "P5" ;
NET "BADR<1>" LOC = "P6" ;
NET "BADR<2>" LOC = "P7" ;
NET "BTRG" LOC = "P13" ;
NET "BSTA<0>" LOC = "P14" ;
NET "BSTA<1>" LOC = "P15" ;
周波数可変
パルスモータは、パルスで動かすので、周波数を可変にした
方が制御が楽になります。
デジタル回路で周波数を可変するには、元になるクロックを
分周するのが最も簡単です。分周で周波数を2倍まで変化
させてみます。
元の周波数を250kHzとして、125〜250分周した場合どのくらい
の周波数になるのかを、Tcl/Tkを利用して計算してみました。
Tcl/Tkスクリプトは、以下。
for {set i 125} {$i < 251} {incr i} {
# calculate
set j [expr 250000 / $i]
# show
puts "$i $j (Hz)"
}
分周比と周波数の関係は、次のようになります。
125 2000 (Hz)
126 1984 (Hz)
127 1968 (Hz)
128 1953 (Hz)
129 1937 (Hz)
130 1923 (Hz)
131 1908 (Hz)
132 1893 (Hz)
133 1879 (Hz)
134 1865 (Hz)
135 1851 (Hz)
136 1838 (Hz)
137 1824 (Hz)
138 1811 (Hz)
139 1798 (Hz)
140 1785 (Hz)
141 1773 (Hz)
142 1760 (Hz)
143 1748 (Hz)
144 1736 (Hz)
145 1724 (Hz)
146 1712 (Hz)
147 1700 (Hz)
148 1689 (Hz)
149 1677 (Hz)
150 1666 (Hz)
151 1655 (Hz)
152 1644 (Hz)
153 1633 (Hz)
154 1623 (Hz)
155 1612 (Hz)
156 1602 (Hz)
157 1592 (Hz)
158 1582 (Hz)
159 1572 (Hz)
160 1562 (Hz)
161 1552 (Hz)
162 1543 (Hz)
163 1533 (Hz)
164 1524 (Hz)
165 1515 (Hz)
166 1506 (Hz)
167 1497 (Hz)
168 1488 (Hz)
169 1479 (Hz)
170 1470 (Hz)
171 1461 (Hz)
172 1453 (Hz)
173 1445 (Hz)
174 1436 (Hz)
175 1428 (Hz)
176 1420 (Hz)
177 1412 (Hz)
178 1404 (Hz)
179 1396 (Hz)
180 1388 (Hz)
181 1381 (Hz)
182 1373 (Hz)
183 1366 (Hz)
184 1358 (Hz)
185 1351 (Hz)
186 1344 (Hz)
187 1336 (Hz)
188 1329 (Hz)
189 1322 (Hz)
190 1315 (Hz)
191 1308 (Hz)
192 1302 (Hz)
193 1295 (Hz)
194 1288 (Hz)
195 1282 (Hz)
196 1275 (Hz)
197 1269 (Hz)
198 1262 (Hz)
199 1256 (Hz)
200 1250 (Hz)
201 1243 (Hz)
202 1237 (Hz)
203 1231 (Hz)
204 1225 (Hz)
205 1219 (Hz)
206 1213 (Hz)
207 1207 (Hz)
208 1201 (Hz)
209 1196 (Hz)
210 1190 (Hz)
211 1184 (Hz)
212 1179 (Hz)
213 1173 (Hz)
214 1168 (Hz)
215 1162 (Hz)
216 1157 (Hz)
217 1152 (Hz)
218 1146 (Hz)
219 1141 (Hz)
220 1136 (Hz)
221 1131 (Hz)
222 1126 (Hz)
223 1121 (Hz)
224 1116 (Hz)
225 1111 (Hz)
226 1106 (Hz)
227 1101 (Hz)
228 1096 (Hz)
229 1091 (Hz)
230 1086 (Hz)
231 1082 (Hz)
232 1077 (Hz)
233 1072 (Hz)
234 1068 (Hz)
235 1063 (Hz)
236 1059 (Hz)
237 1054 (Hz)
238 1050 (Hz)
239 1046 (Hz)
240 1041 (Hz)
241 1037 (Hz)
242 1033 (Hz)
243 1028 (Hz)
244 1024 (Hz)
245 1020 (Hz)
246 1016 (Hz)
247 1012 (Hz)
248 1008 (Hz)
249 1004 (Hz)
250 1000 (Hz)
生成された周波数のうち、2kHz、1.7kHz、1.5kHz、1.2kHzを使うと
すれば、分周比は125、147、166、208とすればよいとわかります。
4種類の周波数の中のひとつを選択できるように
しておくと便利です。
250kHzを入力し分周クロックを生成するVHDLコードを考えます。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
elsif rising_edge(iCLK) then
if ( iPCNT = iMAX ) then
iPCNT <= 0 ;
else
iPCNT <= iPCNT + 1 ;
end if ;
end if ;
end process ;
iCCLK <= '1' when ( iPCNT = 0 ) else '0';
iMAX <= 125 when ( iSEL = "01" ) else
147 when ( iSEL = "10" ) else
166 when ( iSEL = "11" ) else
208 ;
マイコンから利用する周波数を制御できるように
2ビットレジスタを7番目のレジスタとして用意
します。マイコンから見ると、レジスタ番号と
機能割当ては、以下となります。
- reg0 right pulse counter(11-8)
- reg1 right pulse counter(7-4)
- reg2 right pulse counter(3-0)
- reg3 pulse control
- reg4 left pulse counter(11-8)
- reg5 left pulse counter(7-4)
- reg6 left pulse counter(3-0)
- reg7 select pulse clock
XC95108に入れてテストしたVHDLコードは、以下です。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pmtst is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- BUS interface
BTRG : in std_logic ;
BADR : in std_logic_vector(2 downto 0) ;
BDAT : in std_logic_vector(3 downto 0) ;
BSTA : out std_logic_vector(1 downto 0) ;
-- motor control
RDECOUT : out std_logic_vector(3 downto 0) ;
LDECOUT : out std_logic_vector(3 downto 0) ;
CLKOUT : out std_logic_vector(2 downto 0) -- ;
);
end pmtst ;
architecture behavioral of pmtst is
-- divider
signal iCNT : integer range 0 to 15 ;
signal iCLK : std_logic ;
signal iCLK_SFT : std_logic_vector(1 downto 0) ;
signal iSTRG : std_logic ;
-- decoder
signal iDECOUTR : std_logic_vector(3 downto 0) ;
signal iDECOUTL : std_logic_vector(3 downto 0) ;
-- iREG
signal iREGR : std_logic_vector(3 downto 0) ;
signal iREGL : std_logic_vector(3 downto 0) ;
-- counter
signal iSCNT : std_logic_vector(2 downto 0) ;
signal iPENA : std_logic_vector(1 downto 0) ;
-- internal registers
signal iBTRG_SFT : std_logic_vector(2 downto 0) ;
signal iBTRGX : std_logic ;
signal iMLCNT : std_logic_vector(11 downto 0) ;
signal iMRCNT : std_logic_vector(11 downto 0) ;
signal iMCON : std_logic_vector(2 downto 0) ;
signal iMSEL : std_logic_vector(1 downto 0) ;
signal iMLCNTX : integer range 0 to 4095 ;
signal iMSTATEL : std_logic_vector(1 downto 0) ;
signal iMRCNTX : integer range 0 to 4095 ;
signal iMSTATER : std_logic_vector(1 downto 0) ;
-- frequency control
signal iPCNT : integer range 0 to 208 ;
signal iMAX : integer range 0 to 208 ;
signal iCCLK : std_logic ;
begin
-- outputs
RDECOUT <= iREGR when ( iPENA(0) = '1' ) else (others => 'Z') ;
LDECOUT <= iREGL when ( iPENA(1) = '1' ) else (others => 'Z') ;
CLKOUT <= iSCNT ;
BSTA <= iPENA ;
-- BUS interface
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iMLCNT <= (others => '0') ;
iMRCNT <= (others => '0') ;
iMCON <= "000" ;
iMSEL <= "00" ;
elsif rising_edge(CLOCK) then
if ( iBTRGX = '1' ) then
-- reg 0
if ( BADR = "000" ) then
iMRCNT(11 downto 8) <= BDAT ;
end if ;
-- reg 1
if ( BADR = "001" ) then
iMRCNT(7 downto 4) <= BDAT ;
end if ;
-- reg 2
if ( BADR = "010" ) then
iMRCNT(3 downto 0) <= BDAT ;
end if ;
-- reg 3
if ( BADR = "011" ) then
iMCON <= BDAT(2 downto 0) ;
end if ;
-- reg 4
if ( BADR = "100" ) then
iMLCNT(11 downto 8) <= BDAT ;
end if ;
-- reg 5
if ( BADR = "101" ) then
iMLCNT(7 downto 4) <= BDAT ;
end if ;
-- reg 6
if ( BADR = "110" ) then
iMLCNT(3 downto 0) <= BDAT ;
end if ;
-- reg 7
if ( BADR = "111" ) then
iMSEL <= BDAT(1 downto 0) ;
end if ;
end if ;
end if ;
end process ;
-- clock detect
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCLK_SFT <= "00" ;
elsif rising_edge(CLOCK) then
iCLK_SFT <= iCLK_SFT(0) & iCCLK ;
end if ;
end process ;
iSTRG <= '1' when ( iCLK_SFT = "01" ) else '0' ;
-- left motor control
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iMLCNTX <= 0 ;
iMSTATEL <= "00" ;
elsif rising_edge(CLOCK) then
case conv_integer(iMSTATEL) is
-- wait trigger and set counter
when 0 => if ( iMCON(2) = '1' ) then
iMLCNTX <= conv_integer(iMLCNT) ;
iMSTATEL <= "01" ;
else
iMSTATEL <= "00" ;
end if ;
-- detect pulse
when 1 => if ( iSTRG = '1' ) then
iMLCNTX <= iMLCNTX - 1 ;
iMSTATEL <= "11" ;
else
iMSTATEL <= "01" ;
end if ;
-- judge
when 3 => if ( iMLCNTX = 0 ) then
iMSTATEL <= "10" ;
else
iMSTATEL <= "01" ;
end if ;
-- return first state
when 2 => iMSTATEL <= "00" ;
-- default
when others =>
iMSTATEL <= "00" ;
end case ;
end if ;
end process ;
iPENA(1) <= '1' when ( iMSTATEL(0) = '1' ) else '0' ;
-- right motor control
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iMRCNTX <= 0 ;
iMSTATER <= "00" ;
elsif rising_edge(CLOCK) then
case conv_integer(iMSTATER) is
-- wait trigger and set counter
when 0 => if ( iMCON(2) = '1' ) then
iMRCNTX <= conv_integer(iMRCNT) ;
iMSTATER <= "01" ;
else
iMSTATER <= "00" ;
end if ;
-- detect pulse
when 1 => if ( iSTRG = '1' ) then
iMRCNTX <= iMRCNTX - 1 ;
iMSTATER <= "11" ;
else
iMSTATER <= "01" ;
end if ;
-- judge
when 3 => if ( iMRCNTX = 0 ) then
iMSTATER <= "10" ;
else
iMSTATER <= "01" ;
end if ;
-- return first state
when 2 => iMSTATER <= "00" ;
-- default
when others =>
iMSTATER <= "00" ;
end case ;
end if ;
end process ;
iPENA(0) <= '1' when ( iMSTATER(0) = '1' ) else '0' ;
-- divider
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
iBTRG_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ;
if ( iCNT = 15 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iBTRGX <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ;
iCLK <= '1' when ( iCNT = 0 ) else '0' ;
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
elsif rising_edge(iCLK) then
if ( iPCNT = iMAX ) then
iPCNT <= 0 ;
else
iPCNT <= iPCNT + 1 ;
end if ;
end if ;
end process ;
iCCLK <= '1' when ( iPCNT = 0 ) else '0' ;
iMAX <= 125 when ( iMSEL = "01" ) else
147 when ( iMSEL = "10" ) else
166 when ( iMSEL = "11" ) else
208 ;
-- decoder
iDECOUTR <= X"8" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"6" when ( iSCNT = "011" ) else
X"2" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"9" when ( iSCNT = "111" ) else
X"0" ;
iDECOUTL <= X"2" when ( iSCNT = "000" ) else
X"C" when ( iSCNT = "001" ) else
X"4" when ( iSCNT = "010" ) else
X"9" when ( iSCNT = "011" ) else
X"8" when ( iSCNT = "100" ) else
X"3" when ( iSCNT = "101" ) else
X"1" when ( iSCNT = "110" ) else
X"6" when ( iSCNT = "111" ) else
X"0" ;
iREGR <= iDECOUTR when ( iMCON(0) = '1' ) else iDECOUTL ;
iREGL <= iDECOUTR when ( iMCON(1) = '1' ) else iDECOUTL ;
-- counter
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= "000" ;
elsif rising_edge(iCLK) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
end behavioral;
CPLD内に収容されたパルスモータドライブ回路を
動かすファームウエアは、別途説明します。
目次
前
次