FPGAによる機械式ロータリエンコーダのチャタリング除去付カウンタ
  2005/03/08 舞鶴高専 電子制御工学科 町田秀和



←写真をクリックすると動画が見れます。

 最近、秋葉原の秋月電子通商や、大阪日本橋のデジットなどの部品屋さんに 安価な機械式のロータリエンコーダ が売っています。  ロータリエンコーダのカウンタはFPGAで簡単に実現 できますので、値の設定が楽にできそうです。
 ところがデータシートのスペック上、チャタリング期間が最大5msecもあって、 なかなかキレイにカウントすることが難しいようです。 もちろん、RC積分回路(R=1MΩ、C=0.1uF くらいがスイッチのチャタリング防止 にはよいらしい:トランジスタ技術の回路100選とかいう記事にある由)を入れますが、 シユミットトリガ・バッファICを通すまでは面倒なところです。 また、ロータリエンコーダカウンタでは回転方向を判定するために 0,1(ロー/ハイ)ともにチャタリングを除去しなければなりません。

 そこで、下の付録に示すチャタリング除去回路をVHDL言語で記述してみました。 チャタリング除去では定番のシフトレジスタ(3bit)の値が全て0あるいは1になれば、 出力をその値にすると言うことで、0,1両レベルのチャタリングを除去しています。 また、シフトレジスタを駆動するタイミングはシステムクロック(20MHz)を多段分周(11bit) することにより与えています。だいたいこの位でうまくチャタリングが除去できるようです。 ロータリエンコーダの種類によってこのあたりを調整すればよいでしょう。


 さて、このようにロータリエンコーダカウンタをハードウェア(FPGA)で実現するのと、 マイコンのソフトウェアで実現 (例えば、 AVRロータリーエンコーダの処理方法)するのと、どちらが良いのでしょうか?
 PICやAVRなどの1チップマイコンは大変安価で開発環境もフリーで簡単ですから非常に 取り付きやすいでしょう。またFPGAで実現しても結局マイコンとのインターフェースを考えねば ならないかもしれません。
 しかしながら、FPGAならば例えばカウンタ長さを何ビットでも設定可能ですし、また 大変高速(100kHz以上など)でも問題なく対応できます。それに、最近のFPGAはますます 大規模になり、SOPC(System on Programmable Chip)といってマイコンを埋め込んでしまう ということも現実的ですので、柔軟な取り組みが可能になります。



QuartusIIのソースファイル(LZH形式:450kbytes)←右クリックして保存してください。



付録:0,1両レベルのチャタリング除去回路
------------------------------------------------
-- Mechanical Rotary Encoder Chattering Reducer
-- System clk 20MHz
------------------------------------------------
library ieee; 
use ieee.STD_LOGIC_1164.all;
use ieee.std_logic_unsigned.all;

entity chatredp is
  port( clk,rst : in std_logic;
          dirty : in std_logic;
          fresh : out std_logic  );
end;
-----------------------------------------
architecture  RTL  of  chatredp  is

signal cnt : std_logic_vector(10 downto 0);
signal que : std_logic_vector(2 downto 0);
signal tmp : std_logic;

begin
  fresh <= tmp;
  process (clk) begin
    if(clk'event and clk='1') then
      if(rst='1') then 
        cnt <= (others => '0');
        que <= (others => '0');
      else
        cnt <= cnt + '1';
        if(cnt = "00000000000") then
          que(2)<=que(1); que(1)<=que(0); que(0)<=dirty;
        end if;
        if(   que = "111") then tmp<='1';
        elsif(que = "000") then tmp<='0';
        end if;
      end if;
    end if;
  end process;
end RTL;
メインページに戻る