目次

移動ブロック

 MCR_VCでは、マイコン、モータ等の種別は自由なので
 今回は、パルスモータを利用します。



 大阪にあるデジットで、1個¥100(税別)で入手して
 あったものを、利用します。
 データシートは、次のような紙が入っていただけでした。



 特性を調べるために、ドライブ回路を半田付けです。



 コイルの抵抗が300Ωと書かれていたので、+5Vから+12V
 を印加時に、ドライブ回路に流れる電流は、1相あたり
 最大でも40mAです。ドライブ回路起動で3倍近くの電流が
 流れたとしても120mAなので、小信号トランジスタで充分
 対応できると判断しました。

 小信号トランジスタを8本並べると、コイルの逆起電力による
 破損防止に、8本のフライホイールダイオードが必要です。

 基板に多くの部品を実装すると、動かない場合の原因を見つける
 のが面倒と考え、トランジスタアレイを利用し、内蔵ダイオード
 を活用します。

 トランジスタアレイを利用すると、回路は以下のように単純に
 なりました。



 パルスモータには、パルスを与えなければならないので
 CPLDを利用し、簡単な試験回路を構成しました。



 仕様は、単純にしてあります。

 仕様から、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ビットデータと内部レジスタが  あるとして、次のようにビットを割り当てします。  パラメータを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番目のレジスタとして用意  します。マイコンから見ると、レジスタ番号と  機能割当ては、以下となります。  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内に収容されたパルスモータドライブ回路を  動かすファームウエアは、別途説明します。

目次

inserted by FC2 system