ラベル ロータリーエンコーダ の投稿を表示しています。 すべての投稿を表示
ラベル ロータリーエンコーダ の投稿を表示しています。 すべての投稿を表示

2017年2月21日火曜日

16桁x2行のキャラクタLCD(HD44780互換)のフォントの互換性

以前、aitendoのキャラクタLCDは上位バイトがおかしいというようなことを書きましたが、Arduinoでテストしたところ秋月、共立、aitendoのものでほとんど差異はなかった。

ブレッドボード図


左が秋月、右がaitendo

ロータリーエンコーダーで文字コードを選択して、キャラクタLCDに表示する。2系統用意して、同一のロータリーエンコーダーで2系統とも同じ文字コードを選択できるようにした。

ロータリーエンコーダーの読み取りがずれるので、タクトスイッチを押すと0x00に戻るようにした。

Arduinoのスケッチ LCD_FontTest.ino

/*
   LCD RS pin to digital pin 12
   LCD Enable pin to digital pin 11
   LCD D4 pin to digital pin 5
   LCD D5 pin to digital pin 4
   LCD D6 pin to digital pin 3
   LCD D7 pin to digital pin 2
   LCD R/W pin to ground
   LCD VSS pin to ground
   LCD VCC pin to 5V
   10K resistor:
   ends to +5V and ground
   wiper to LCD VO pin (pin 3)

   RotaryEncoder A 9
   RotaryEncoder B 8
   RotaryEncoder C GND

   TactSW 10
*/

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int clearBtn = 10;
const int RE_A = 9;
const int RE_B = 8;

uint8_t charCode = 0x00;

// Rotary Encoderの読み取り akizuki/Alps
int readRE()
{
  static uint8_t index;
  int retVal = 0;
  index = (index << 2) | (digitalRead(RE_B) << 1) | (digitalRead(RE_A));
  index &= 0b1111;
  switch (index) {
  // 時計回り
  case 0b0111:  // 01 -> 11
    retVal = 1;
    break;
  // 反時計回り
  case 0b1101:  // 11 -> 01
    retVal = -1;
    break;
  }
  delay(1);  // (とりあえず)チャタリング防止
  return retVal;
}

void setup() {
  pinMode(clearBtn, INPUT_PULLUP);
  pinMode(RE_A, INPUT_PULLUP);
  pinMode(RE_B, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("LCD Char Font");

  delay(1000);
  lcd.clear();
}

void loop() {
  if (digitalRead(clearBtn) == 0) {
    charCode = 0;
  }
  charCode += readRE() * 16;

  lcd.home();
  lcd.print(charCode, HEX);
  lcd.print(":");
  lcd.print(charCode + 15, HEX);
  lcd.print("      ");
  
  lcd.setCursor(0, 1);
  for (int i = 0; i < 16; i++) {
    lcd.write(charCode + i);
  }
}

0x00~0x0Fで表示されるキャラクタは違うが(←ユーザー指定フォント用?)、秋月共立aitendoとも秋月のDATASHEETに記載されているフォントが表示された。


2016年5月25日水曜日

NucleoF401REでQEIライブラリを使う。

QEIというQuadrature Encoderのライブラリがあったのでロータリーエンコーダーで使ってみた。

QEI:
https://developer.mbed.org/cookbook/QEI

Rotary Encoderと書いてあるが手で回すロータリーエンコーダーではなく、タイヤとかの回転角度・回転数を計測する用みたいだ。

手回しのロータリーエンコーダでも一応使える。

配線図

#include "QEI.h"

Serial pc(USBTX, USBRX);
//Use X4 encoding.
//QEI wheel(p29, p30, NC, 624, QEI::X4_ENCODING);
//Use X2 encoding by default.
//QEI wheel (p29, p30, NC, 624);
QEI wheel (PB_4, PB_5, NC, 624, QEI::X2_ENCODING);

int main() {

    while(1){
        wait(0.1);
        pc.printf("Pulses is: %i\r\n", wheel.getPulses());
    }

}

QEIクラスはピンの変化の検知に外部割り込み(InterruputIn)を使っていて、これがprivateなのでInterruptIn::mode()で内部プルアップの設定ができない。仕方がないので、ロータリーエンコーダーのA/Bピンをブレッドボード上でプルアップしている。

秋月で売っているAlpsのロータリーエンコーダーは1デテント(クリック感のあるところ)で数値が2個進む感じなので、QEI::X2_ENCODINGを指定するとデテント1個でPulsesが2つずつ増減する。(QEI::X4_ENCODINGだと4つずつ増減する)

624という指定は1回転数当たりのパルス数で、Exampleのデフォルトのままで特に意味は無い。

NucleoF401REの外部割り込み


mbed公式のInterrutptInのページを見るとmbed NXP LPC1768の外部割り込みで使えるピンの注意書きがあるが、NucleoF401REは16本の割り込みをPinに割り当てて使うようになっているようだ。

Port はバラバラでもいいが、Pin番号がかぶるとダメ。

参考:
http://letanphuc.net/2015/03/stm32f0-tutorial-3-external-interrupts/

STMicroelectronics RM0368 Reference manual

なので、紛れがないように今回はPB_4、PB_5に割り当てた。

ちなみにArduino Uno/ATMega328Pの外部割り込みは固定でINT0、INT1の2本しかない。

メモ:


QEIライブラリは手回しのロータリーエンコーダでも使えるが、使いにくいかな。

2015年11月3日火曜日

PSoC 4でロータリーエンコーダを使う

PSoC 4 Pioneer Kitでロータリーエンコーダを使うテストをしてみた。


PSoC Creator TopDesign


cy_pinコンポーネントはピンの配列にできて、こうすると1本1本のピンではなくてuint8タイプで一気に読み取り書き取りができるようだ。普通のマイコンのGPIOみたく。Configureで内部Pull Upを指定した。

DWRエディタもP1[1:0]のように連続したピンしか指定できなくなる。

Debouncerコンポーネントを使ってチャタリング対策をした。Clock_1が1kHzなので1ms(0.5msか?)のH/Lの変動は読み飛ばすようになる。

ロータリーエンコーダの読み取り方はAVRで使ったのと同じです。(「AVRでロータリーエンコーダーを使う実験」)

PSoC Creatorのプロジェクト
https://github.com/ryood/PSoC_Rotary_Encoder_Test

メモ:


  • ロータリーエンコーダにはPSoCのQuadrature Decoder(直交位相デコーダ?)コンポーネントが使えるかと思ったがよくわからない(^q^;
  • Debouncerコンポーネントもbit数を指定するパラメータがあるがよくわからん。
  • PSoC 4 Pioneer KitでUARTを使う場合の配線図を追加した。「PSoC 4 Pioneer Kit: USB-USRT Bridgeをやってみた&前回までの補足


2015年9月4日金曜日

AVRでロータリーエンコーダーを使う(チャタリング対策)

AVRはPin Change Interruptという割り込みがサポートされていて(「AVRのPin Change Interruptとチャタリング対策」でテストした)ロータリーエンコーダーもこれを使うことを考えてみたが、いざコーディングしてテストしてみると処理がかなり煩雑になったのであきらめた。

Pin Change InterruptはPORTごとに割り込みベクタが分かれているので、ロータリーエンコーダー用のポートとスイッチの列のポートを分けられれば少しは話は簡単になりそうだが、製作中のシーケンス入力用のデバイスは配線の都合で贅沢にポートを分けている余裕がない。

Pin Change Interrupt以外に普通の外部割込み(INT0、INT1)を使うことも一瞬考えたが、これはPD2、PD3に割り当てられていてPORTDはスイッチの列の入力に使う予定なのでこれもやめることにした。

しかたなくポーリングで処理することにした。(どうしても割り込みでというならタイマー・カウンターという手も残されているが・・・)

ブレッドボード図

表記はATMega168になっているがATMega88Vを使用。

ロータリーエンコーダーのABはPB2、PB3に、軸の押し下げのSWはPB1につないだ。
PD0..PD7につないだLEDでロータリーエンコーダーで入力した8bitの値を表示する。PC2、PC3につないだLED(左上あたりの2個)は割り込みごとにトグル表示する等デバッグ用に使った。

PB5につないだ黄色LEDはロータリーエンコーダーの軸の押し下げのSWでトグル表示する。


Atmel StudioのプロジェクトはGithubにあげました。
https://github.com/ryood/Rotary_Encoder_Debounce_Test

ロータリーエンコーダーのプラス・マイナスの読み取り値で、8bitのカウンタの値を増減して赤色LEDx8でそのまま表示している。

ロータリーエンコーダーの軸の押し下げスイッチで黄色LEDがトグル表示される。

PC2、PC3につないだLEDはそれぞれpin change interruptとTimer0オーバー・フロー割り込みでトグル動作するので、2chオシロで位相差を見ればチャタリング防止用のディレイ・タイムが確認できる。


Timer0とTimer2のプリスケーラ-


またいらんことでハマってしまった。Timer0とTimer2のプリスケーラーの値はTCCR0B/TCCR2BのCS20..CS22 bitで設定するが、設定する値が違う。

Timer2では0b111で1/1024になるが、Timer0で0b111を設定するとクロック・ソースを外部から与える設定になる。

最初Timer2でやっていて、Timer0に変更したらTimerが起動しなくなって相当悩んでしまった(^q^;;;

AVRのPin Change Interruptとチャタリング対策」で設定したTimerの遅延時間の設定も間違えてた。忘れなかったら直します。


あとADCを割り込みで処理するテストをしたら、基板を作っていきたいと思う。

回路図

基板図

プリント基板なら2層でおさまりそうだが、手配線する予定なので変な感じの図になっています。

I2Cでの本体側とのやりとりは下記のようなものを想定中。


ロータリーエンコーダーは基本的にトラック切り替え(kick、snare、hihat等)に使う予定だが、軸の押し下げSWの切り替えでロータリーエンコーダーをどういう動作に変更するか考え中。



2015年5月7日木曜日

AVRでロータリーエンコーダーを使う実験

Arduinoではロータリーエンコーダーのテストをしたが
「ロータリーエンコーダーを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);  
   }  
 }  


2015年3月11日水曜日

ロータリーエンコーダーをArduinoで使ってみた

オシロスコープのプローブが初期不良だったみたいなので交換してもらうことにした。
プローブが1本しかなくてオシロで2入力の位相を計測できないのでLEDで動作チェックしてみた


クリック位置(デテント?)では、00、11しか出力されないのは仕様の様だ

データーシートの位相差の項


クリック位置とクリック位置の中間で01や10になる
時計回り→
AB: 00 (10) 11 (01) 00
              ←反時計回り
()はクリックの中間位置
10 → 11または00
01 → 11または00
の変化を読み取るようにしてArduinoでスケッチを書いてみた

 //PINアサイン  
 int rotAPin = 2;  
 int rotBPin = 3;  
 volatile int rotA = 0;  
 volatile int rotB = 0;  
 volatile int oldRotA = 0;  
 volatile int oldRotB = 0;  
 void setup() {  
  pinMode(rotAPin, INPUT_PULLUP);  
  pinMode(rotBPin, INPUT_PULLUP);  
  Serial.begin(115200);  
  Serial.println("Start Rotary Encoder Test.");  
 }  
 void loop() {  
  oldRotA = rotA;  
  oldRotB = rotB;  
  rotA = digitalRead(rotAPin);  
  rotB = digitalRead(rotBPin);  
  if ((oldRotA != rotA) || (oldRotB != rotB)){  
   int oldRot = ((oldRotA << 1) | oldRotB);  
   int rot = ((rotA << 1) | rotB);  
   Serial.print(oldRotA);  
   Serial.print(" ");  
   Serial.print(oldRotB);  
   Serial.print(" -> ");  
   Serial.print(rotA);  
   Serial.print(" ");  
   Serial.print(rotB);  
   Serial.print(" ");  
   if (oldRot == 0b10) {  
    if (rot == 0b11) Serial.print(" >>");  
    else if (rot == 0b00) Serial.print(" <<");  
   } else if (oldRot == 0b01) {  
    if (rot == 0b00) Serial.print(" >>");  
    else if (rot == 0b11) Serial.print(" <<");  
   }  
   Serial.println("");  
  }  
 }  

ちょっと冗長ぎみですが(^q^;

シリアル出力例


時々読み取り値がおかしくなる(読みこぼし?)

オシロで(片チャンネルだけ)波形をとってみたが


そんなにチャタリングは出てないような感じです

読み取りエラーは出力用のシリアル通信の遅延が影響しているのかな?

2015年3月10日火曜日

ロリコンなのにBBA

こないだ仕入れたロータリーエンコーダーを使ってみたがうまく動かない


DATASHEET(http://www.marutsu.co.jp/contents/shop/marutsu/datasheet/atc0000cj15.pdf)を
見ると基板にマーキングしてある通り上がCOMと押し下げ時のSW

下がBBA(笑)

ArduinoやテスタでチェックしたがAとBが互い違いにスイッチングするはずなんだが
AもBも一緒に切り替わってしまう

押し下げのスイッチはうまくいく

そんな複雑な機構ではないはずなので

ロータリーエンコーダーをもう一個仕入れてAB位相のテストするしかないか

ロータリーエンコーダーのカチカチいう感触が好きなんだが中途半端にデジタルなので
もはやすたれ行く運命かもしれない