今回は PIC で ロータリーエンコーダ を使ってみたので、使い方や制御するためのポイントを紹介します。
ロータリーエンコーダとは
まずはじめに ロータリーエンコーダ について軽く紹介したいと思います。
今回使用したのは、秋月電子で販売されている ALPS社のロータリーエンコーダ(24クリックタイプ)です。
見た目やサイズは可変抵抗とよく似ていますが、違いとしては以下の点が挙げられます。
- 回転角に制限がなく 360° 何周でも回せる。
- 角度の情報は絶対値ではなく相対値で取得できる。
可変抵抗の場合は回転角に応じたアナログ電圧が取得できるので、最大値と最小値の決まっているボリュームなどに使用されます。
一方ロータリーエンコーダは軸を回すたびに、(反)時計回りに 1ステップ分回転したという情報が得られるので、+, ー のボタンのようにして使えます。
一番身近な例としてはマウスのホイールなどに利用されています。
信号
続いてロータリーエンコーダの信号について解説します。
ロータリーエンコーダには 3つの端子がついていて、図のように C端子は GND に接続し、A, B 端子はプルアップしておきます。
このとき、軸を時計回りに回すと次のような信号が出力されます。
すなわち、B に対して A のほうが 90° 進んだパルスが出力されます。
逆に、反時計回りに回すと A のほうが 90° 遅れたパルスが出力されます。
このパルスの位相差をマイコンで検出することで回転情報を取得できます。
具体的にどうするかというと、B が H → L に変化した瞬間に、A が L なら時計回り、A が H なら反時計回りと判定します。
チャタリング
ロータリーエンコーダやスイッチなど、物理的な接点を持つ部品には必ずチャタリングという問題が付随します。
接点が切り替わるときに、一定時間高速で出力が振動するのです。
これは、スイッチを押したときに微小にバウンドしているようなイメージです。
ロータリーエンコーダは、出力が H → L に切り替わったら1ステップ回転したとカウントするのでした。
つまり、チャタリングの対策をしていないと、本当は1ステップしか回転していないのに何ステップも回転したように誤検出してしまうのです。
チャタリングの対策としてはソフトウェア的な対策とハードウェア的な対策があります。
ソフトウェアの場合、最初の変化を受け付けてから一定時間待ってから処理をすることでチャタリングを回避することができます。
実際に PIC マイコンで試してみたところ、タクトスイッチのチャタリングはこれで上手く回避できたのですが、ロータリーエンコーダのチャタリングは強烈なのか、多少マシにはなっても完全に回避することはできませんでした。
なので、今回はハードウェア的な対策を紹介します。
使用するのはシュミットトリガインバータです。
ここでいうインバータとは NOT 回路のことで、入力の H と L を反転させて出力します。
普通の NOT 回路の場合、入力が微妙な電圧だと出力が不安定になってしまいます。
しかしシュミットトリガの場合は、下図のように H → L の場合と L → H の場合で閾値が異なるため不安定になりません。
このシュミットトリガインバータを2個繋げ、入力に C と R をつけることで高周波成分をカットすれば、チャタリングが解消されます。
なのですが今回実験してみると、C を入れると何故か PIC の動作が不安定になってしまいました。原因は不明ですが、C を抜くと上手くいったのでヨシとします。
実験
ロータリーエンコーダの回転値を読み取って、I2C で LCD に表示させる実験を行いました。
使用した部品はこちらです。
ロータリーエンコーダはそのままではブレッドボードで使用することができないので、こんな感じにピン付きのケーブルを端子にはんだ付けして使用しました。
プログラム全体はこちらに載せておくので、ここでは主要部だけ載せます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
void Init(){ TRISC = 0b00110011; IOCCN = 0b00010000; //Negative (H->L)割り込み ANSELC = 0b00000000; IOCIE = 1; //IOC割り込み許可 PEIE = 1; GIE = 1; } void __interrupt isr(){ GIE = 0; if(IOCCF4){ //RC4:B H->Lの変化 IOCCF4 = 0; if(A == 1) //RC5:A rot--; else rot++; rotFlag = 1; } GIE = 1; } void main(void) { Init(); //省略// while(1){ if(rotFlag){ rotFlag = 0; lcd_SetCursor(1, 0); printf("%d ",rot); } } } |
回路図はこんな感じです。
結果
時計回りに回すとカウントが増加し、反時計回りに回すと減少することが確認できました。
回転速度が速かったりすると信号を拾いきれなかったりするので、信号を累積して回転量を推定するのにはこのままだと厳しいですが、+とーの入力装置としては十分に使用できます。
あとがき
コンデンサの謎は残るものの、とりあえずロータリーエンコーダを使用することができました。
この記事がロータリーエンコーダを使ってみたいというあなたに届いたならば幸いです。
最後までご覧いただきありがとうございました。