「ロータリーエンコーダーをArduinoで使ってみた」(http://dad8893.blogspot.jp/2015/03/arduino.html)AVR直ではまだだったので単体でテストしてみた
ブレッドボード配線図
下のユニバーサル基板に乗っけているのが前にやったPanasonicのロータリーエンコーダーだ
型番は忘れたが、京都のマルツで購入(400円ぐらいだったような)
ブレッドボードに乗せているのはaitendoの基板付きで150円のやつ(http://www.aitendo.com/product/7443)
回した感じは、Panasonicの方がきっちりしていて、aitendoの方は若干遊びがある
<RotaryEncoder_Test.c>
#include <avr/io.h>
#define F_CPU 8000000UL
#include <util/delay.h>
#define RE_DIR DDRD
#define RE_PORT PORTD
#define RE_PIN PIND
#define RE_A 0
#define RE_B 1
#define RE_SW 2
#define LED_DIR DDRB
#define LED_PORT PORTB
#define LED_RED 1
#define LED_GREEN 2
#define LED_BLUE 6
int main(void)
{
// Rotary Encoder
RE_DIR = 0;
// PullUp
RE_PORT = _BV(RE_A) | _BV(RE_B) | _BV(RE_SW);
// LED
LED_DIR = _BV(LED_RED) | _BV(LED_GREEN) | _BV(LED_BLUE);
while(1)
{
int rotA, rotB, sw;
rotA = RE_PIN & _BV(RE_A);
rotB = RE_PIN & _BV(RE_B);
sw = RE_PIN & _BV(RE_SW);
if (rotA)
LED_PORT |= _BV(LED_RED);
else
LED_PORT &= ~_BV(LED_RED);
if (rotB)
LED_PORT |= _BV(LED_GREEN);
else
LED_PORT &= ~_BV(LED_GREEN);
if (sw)
LED_PORT |= _BV(LED_BLUE);
else
LED_PORT &= ~_BV(LED_BLUE);
}
}
プログラムはロータリーエンコーダーのカウントとかはしないで、A、B端子とスイッチのON/OFFを拾ってLEDをON/OFFしているだけ
機能的にはPanasonicもaitendoのも同じだった(クリックの中点でA、Bが逆相になる)
位相の変化のタイミングの確認
ロータリーエンコーダーをガチャガチャ早回しして、A、B端子の状態を見てみた
aitendo 反時計まわり
赤色がA端子、黄色がB端子
これだけ横軸を10ms/divにしてた(^q^;
aitendo 時計回り
Panasonic 反時計回り
Panasonic 時計回り
aitendoの方はON/OFFの切り替わりの間隔に若干ムラがあるが動作としては問題ないかな
A、B逆位相になるのは20ms / 5 = 4msより少なそうなので、1msぐらいで考えないといけないか・・・
チャタリング
ロータリーエンコーダー自体ではなくて、軸を押し込むスイッチの方はかなりチャタリングが出るようなのでこれは対策しないとだめっぽい
チャタリング対策にタイマー割り込みを使うとすると、矩形波を生成するPWMに影響があるのかないのか
う~ん
<追記>
ELMさんの「ロータリー・エンコーダの使い方(http://elm-chan.org/docs/tec/te04.html)」を参考に、プログラムを変更してロータリーエンコーダーの回転をLEDで見れるようにした
回路は上記と同じです
デテント位置でA、Bが同相、中点で逆相になるタイプのロータリーエンコーダーならOK(たぶん)
時計回りに回すと緑のLEDが点滅、反時計回りに回すと赤のLEDが点滅します
<RotaryEncoder_Test.c>
#include <avr/io.h>
#define F_CPU 8000000UL
#include <util/delay.h>
#define RE_DIR DDRD
#define RE_PORT PORTD
#define RE_PIN PIND
#define RE_A 0
#define RE_B 1
#define RE_SW 2
#define LED_DIR DDRB
#define LED_PORT PORTB
#define LED_RED 1
#define LED_GREEN 2
#define LED_BLUE 6
int readRE(void)
{
static uint8_t index;
int retVal = 0;
index = (index << 2) | (RE_PIN & _BV(RE_A)) | (RE_PIN & _BV(RE_B));
index &= 0b1111;
switch (index) {
// 時計回り
case 0b0001: // 00 -> 01
case 0b1110: // 11 -> 10
retVal = -1;
break;
// 反時計回り
case 0b0010: // 00 -> 10
case 0b1101: // 11 -> 01
retVal = 1;
break;
}
_delay_ms(5); // (とりあえず)チャタリング防止
return retVal;
}
int main(void)
{
// Rotary Encoder
RE_DIR = 0;
// PullUp
RE_PORT = _BV(RE_A) | _BV(RE_B) | _BV(RE_SW);
// LED
LED_DIR = _BV(LED_RED) | _BV(LED_GREEN) | _BV(LED_BLUE);
while(1)
{
int sw;
switch (readRE()) {
case 1:
LED_PORT = 0;
_delay_ms(50);
LED_PORT |= _BV(LED_GREEN);
LED_PORT &= ~_BV(LED_RED);
break;
case -1:
LED_PORT = 0;
_delay_ms(50);
LED_PORT |= _BV(LED_RED);
LED_PORT &= ~_BV(LED_GREEN);
break;
}
sw = RE_PIN & _BV(RE_SW);
if (sw)
LED_PORT |= _BV(LED_BLUE);
else
LED_PORT &= ~_BV(LED_BLUE);
_delay_ms(5);
}
}
0 件のコメント:
コメントを投稿