펌웨어디자인(Firmware Design)

AVR로터리엔코더볼륨

arirangled 2008. 12. 9. 01:21

 

로터리 엔코더 http://www.geocities.jp/kuman2600/k5rot-enc.html
로터리 엔코더의 실험을 했습니다. 정회전, 역회전으로 펄스를 내, 이것을 카운트 하는 것에 의해서 회전각(회전 위치)을 조사하는 것이 본래의 사용법이라고 생각합니다만, 전자렌지의 시간 설정과 같이 수치를 결정하는 것으로도 사용되고 있습니다. 타이머의 시간 설정이나 PWM 제어값 설정에 사용할 수 있는 것은 아닌가해서 실험해 보았습니다. 
 오른쪽이 엔코더의 확대 사진입니다. 실험중은 다회전이 편한 것 같아 임시 크랭크를 붙이고 있습니다. ALPS사의 제품으로 EC16B24102의 같습니다. 디지트로 150엔이였습니다. 클릭 없이 1회전으로 24의 펄스를 냅니다. 가게에서 몇 종류인지를 정리한 규격표를 주었으므로 그 중에서 품번을 추정했습니다.
채터링을 막기 위해서 1 ms 마다 엔코더를 읽으러 갑니다. 다음에 데이터 시트를 잘 보면 체터링의 max는 3 ms라고 써 있었습니다. 실험의 목적이 수치 설정만으로 LED로 보이는 것, 손으로 회전해 봐 채터링을 몰랐기 때문에 이것으로 좋은것으로 합니다(각도 측정에서는 안되겠지요).

위의 그림은 엔코더의 파형입니다. A, B단자는 on이 되면 C단자와 도통해, 0 V가 됩니다. off때는 IO단자를 소프트웨어 pull-up 하고 있으므로 5 V가 됩니다. 1 사이클로 4개 상태가 존재해 A단자를 LSB로 하는 2비트를 10진표기하면 0→1→3→2→0···(와)과 변화합니다(CW때). 여기서 2로 3을 바꿔 넣으면 0→1→2→3→0이 되어 1증가하는(또는 3줄어 든다)와 정회전(CW), 1줄어 드는(또는 3증가한다)와 역회전인 것을 압니다.  2로 3의 교체는 if문으로 안이하게 속이고 있습니다(미안). 엔코더의 취급은 ChaN씨의 페이지로 공부했습니다(감사).

 

제로를 결정하기 위해서, 역회전으로 0이 되면 그 이상은 감소 하지 않기로 하고 있습니다. 1회전으로 4×24=96의 카운트를 합니다. 약간 섬세합니다. 크랭크를 붙이면 2~300정도 수치 설정이라면 실용이 될 것 같습니다(그 이상은 돌리는 것을 인내하지 않으면 되지 않습니다).
아키즈키(추월전자)에서 구입한 또 하나의 엔코더는 클릭 첨부였습니다. 1 사이클의 4상중 1개소 밖에 클릭이 없기 때문에 실제로는 4 나는 일에 카운트가 올라갑니다. 이것으로는 사용하기 어렵기 때문에 도중의 계산으로 4로 나누어 4분의 1의 카운트를 하게 됩니다. 1회전 24 카운트가 됩니다. 섬세한 카운트업이 없는 교체에 2 회전해도 48 밖에 카운트 할 수 없습니다. 수치가 작을 때는 사용하기 쉬울지도 모르겠습니다.
각도를 측정한다면 클릭없이 해야 하겠지요. 360÷96=3.75도의 정도로 측정할 수 있습니다.

ロータリーエンコーダ   http://www.geocities.jp/kuman2600/k5rot-enc.html
 ロータリーエンコーダの実験をしました。正回転、逆回転でパルスを出し、これをカウントすることによって回転角(回転位置)を調べることが本来の使い方だと思うのですが、電子レンジの時間設定のように数値を決めるだけにも使われています。タイマーの時間設定やPWM制御の値設定に使えるのではないかと思い実験してみました。 
 右 右ががエンコーダの拡大写真です。実験中は多回転が楽なように臨時のクランクを付けています。ALPSの製品でEC16B24102の様です。デジットで150円でした。クリックなしで1回転で24のパルスを出します。お店で幾種類かをまとめた規格表をくれましたので、その中から品番を推定しました。
チャタリングを防ぐために、1msごとにエンコーダを読みに行きます。後でデータシートをよく見るとチャタリングのmaxは3msと書いてありました。実験の目的が数値設定だけで、LEDで見えること、手で回転してみてチャタリングが分からなかったのでこれでよしとします(角度測定ではダメでしょう)。

上の図はエンコーダの波形です。A,B端子はonになるとC端子と導通し、0Vになります。offの時はIO端子をソフトウエアプルアップしているので、5Vになります。1サイクルで4つの状態が存在し、A端子をLSBとする2ビットを10進表記すると 0→1→3→2→0・・・と変化します(CWの時)。ここで2と3を入れ替えると 0→1→2→3→0 となり、1増える(または3減る)と正回転(CW)、1減る(または3増える)と逆回転であることが分かります。 2と3の入れ替えはif文で安易にごまかしています(ごめん)。エンコーダの扱いはChaNさんのページで勉強しました(感謝)。
回路図  プログラム

ゼロを決めるために、逆回転で0になるとそれ以上はデクリメントしないことにしています。1回転で 4×24=96 のカウントをします。ややデリケートです。クランクを付けると、2~300くらいの数値設定なら実用になりそうです(それ以上は回すことを辛抱せねばなりません)。
秋月で購入したもう一つのエンコーダはクリック付きでした。1サイクルの4相の内、1カ所しかクリックがないので実際には4飛びにカウントがアップします。これでは使いにくいので途中の計算で4で割り、4分の1のカウントをすることになります。1回転24カウントになります。デリケートなカウントアップが無い替わりに2回転しても48しかカウントできません。数値が小さいときは使いやすいかもしてません。
角度を測定するなら、クリックなしにすべきでしょう。360÷96=3.75度の精度で測定できます。

 

 

 

/********************로터리엔코더실험******************************  

         2004.10.11 im
         WinAVR20050214대응으로 수정  05.03.01
    rot_enc.c
    LED:portA 0~7(seg) a=A0,dp=A7
             portB 0(MSB)~3(LSB)
    엔코더출력값(변수)의 inc,dec 를 한다.
    결과를 숫자표시기에 표시한다.
**********************************************************************/
#include<avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>

void wait(void);

volatile char s1,s0,t1,t0;
volatile uint16_t cnt,cnt4;

/*   타이머0의 새치기 루틴 1ms로 엔코더를 읽어 채터링을 회피*/
SIGNAL(SIG_OVERFLOW0) {         // 1MHz/64 = 16kHz
  TCNT0=241;                  // 타이머의 카운터세트256-16=241→1000Hz
s0=s1;                        // sw를 조사한다.
신데이터를 구데이터 변수에 넣어서
  s1=((PINB & 0x30)>>4);        // 신데이터를 읽어 넣고 bit4:5 에서sw가 있을 때 까지off=1 on=0
  if(s1==3){s1=2;               // 2와3을 교체
  }else if(s1==2){s1=3;
  }
  if(((s1-s0==1)||(s1-s0==-3))&&(cnt<39997)){cnt++;}  // 3→0도 정회전(CW)
  if(((s1-s0==-1)||(s1-s0==3))&&(cnt>0)){cnt--;}      // 0→3도 역회전(CCW)
  cnt4=cnt;                                           // 클릭붙음  cnt4=cnt/4에서변경;
}
int main(void){         //***********메인루틴 **********************
  uint8_t d1,d10,d100,d1000,j;    // 부호없음8bit변수선언
  uint16_t cnt1;
  uint8_t s[10];                  // 부호없음8bit배열변수선언
  DDRA=255;                      // portA를output로 설정 255d=0xff=11111111b
  DDRB=0x0f;                     // portB4:6뿐input로 설정 PB0:3=out
  PORTB=0xf0;                    // 소프트웨어 풀업 f0=11110000b  PB4:5=rot_enc

  TCCR0=3;                       // 타이머의 0의분주비=1/64
  TIMSK=(1<<TOIE0);              // 타이머0 새치기 허가
  TCNT0=241;                     // 타이머의 카운터세트
  sei();                         // 새치기 총원허가
  cnt=0;

// LED표시용     dp g f e d c b a --segment 0로 점등
  s[0]=192;    //   1  1 0 0 0 0 0 0 =192
  s[1]=249;    //   1  1 1 1 1 0 0 1 =249
  s[2]=164;    //   1  0 1 0 0 1 0 0
  s[3]=176;    //   1  0 1 1 0 0 0 0
  s[4]=153;    //   1  0 0 1 1 0 0 1
  s[5]=146;    //   1  0 0 1 0 0 1 0
  s[6]=130;    //   1  0 0 0 0 0 1 0
  s[7]=248;    //   1  1 1 1 1 0 0 0
  s[8]=128;    //   1  0 0 0 0 0 0 0
  s[9]=152;    //   1  0 0 1 1 0 0 0

  d1=0; d10=0;d100=0;d1000=0;
  for(;;){              /* 무한루프의 시작 */
    for(j=1;j<250;j++){
      PORTB&=~_BV(PB0);      //PB0=0로 애노드on 최상위 항 표시
      PORTA=s[d1000];
      wait();
      PORTB|=_BV(PB0);      //PB0=1로 애노드 off 전 표시 소등

      PORTB&=~_BV(PB1);      //100의 항
      PORTA=s[d100];
      wait();
      PORTB|=_BV(PB1);

      PORTB&=~_BV(PB2);      //10의 항
      PORTA=s[d10];
      wait();
      PORTB|=_BV(PB2);

      PORTB&=~_BV(PB3);     //최하위 항 1의 항
      PORTA=s[d1];
      wait();
      PORTB|=_BV(PB3);

    }
    cnt1=cnt4;                            //표시숫자의 카운트 업
    d1000=cnt1/1000; cnt1=cnt1-d1000*1000;
    d100=cnt1/100; cnt1=cnt1-d100*100;
    d10=cnt1/10;   cnt1=cnt1-d10*10;
    d1=cnt1;

  }                     /* 무한루프의 마침 무한루프의 마침*/
}                       /* main루틴(main관계수의 마침    */

void wait(void){
  uint16_t k;                 /* 부호없음16bit변수선언   */
  for(k=1;k<500;k++){k=k;}

/* ********************************************************************
    ロータリーエンンコーダの実験  2004.10.11 im
         WinAVR20050214対応のため修正  05.03.01
    rot_enc.c
    LED:portA 0~7(seg) a=A0,dp=A7
             portB 0(MSB)~3(LSB)
    エンコーダの出力により値(変数)の inc,dec をする。
    結果をLEDに表示する。
******************************************************************** */
#include<avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
void wait(void);
volatile char s1,s0,t1,t0;
volatile uint16_t cnt,cnt4;
/*    タイマー0の割り込みルーチン  1msでエンコーダを読みチャタリングを回避*/
SIGNAL(SIG_OVERFLOW0) {         // 1MHz/64 = 16kHz
  TCNT0=241;                    // タイマーのカウンタセット 256-16=241  →1000Hz
  s0=s1;                        // swを調べる 新データを旧データ変数に入れて
  s1=((PINB & 0x30)>>4);        // 新データを読み込む bit4:5 にswがあるから off=1 on=0
  if(s1==3){s1=2;               // 2と3を入れ替える
  }else if(s1==2){s1=3;
  }
  if(((s1-s0==1)||(s1-s0==-3))&&(cnt<39997)){cnt++;}  // 3→0も正回転(CW)
  if(((s1-s0==-1)||(s1-s0==3))&&(cnt>0)){cnt--;}      // 0→3も逆回転(CCW)
  cnt4=cnt;                                           // クリック付きは  cnt4=cnt/4に変更;
}
int main(void){         //************************* メイン ルーチン **********************
  uint8_t d1,d10,d100,d1000,j;    // 符号なし8bit変数宣言
  uint16_t cnt1;
  uint8_t s[10];                  // 符号なし8bit配列変数宣言
  DDRA=255;                      // portAをoutputに設定  255d=0xff=11111111b
  DDRB=0x0f;                     // portB4:6だけinputに設定 PB0:3=out
  PORTB=0xf0;                    // ソフトウエア プルアップ f0=11110000b  PB4:5=rot_enc
  TCCR0=3;                       // タイマ0の分周比=1/64
  TIMSK=(1<<TOIE0);              // タイマ0 割り込み許可
  TCNT0=241;                     // タイマーのカウンタセット
  sei();                         // 割り込み総元許可
  cnt=0;
// LED表示用     dp g f e d c b a --segment 0で点灯
  s[0]=192;    //   1  1 0 0 0 0 0 0 =192
  s[1]=249;    //   1  1 1 1 1 0 0 1 =249
  s[2]=164;    //   1  0 1 0 0 1 0 0
  s[3]=176;    //   1  0 1 1 0 0 0 0
  s[4]=153;    //   1  0 0 1 1 0 0 1
  s[5]=146;    //   1  0 0 1 0 0 1 0
  s[6]=130;    //   1  0 0 0 0 0 1 0
  s[7]=248;    //   1  1 1 1 1 0 0 0
  s[8]=128;    //   1  0 0 0 0 0 0 0
  s[9]=152;    //   1  0 0 1 1 0 0 0
  d1=0; d10=0;d100=0;d1000=0;
  for(;;){              /* 無限ループの始まり     */
    for(j=1;j<250;j++){
      PORTB&=~_BV(PB0);      //PB0=0でアノードon 最上位桁表示
      PORTA=s[d1000];
      wait();
      PORTB|=_BV(PB0);      //PB0=1でアノードoff 全表示消灯
      PORTB&=~_BV(PB1);      //100の桁
      PORTA=s[d100];
      wait();
      PORTB|=_BV(PB1);
      PORTB&=~_BV(PB2);      //10の桁
      PORTA=s[d10];
      wait();
      PORTB|=_BV(PB2);
      PORTB&=~_BV(PB3);     //最下位桁 1の桁
      PORTA=s[d1];
      wait();
      PORTB|=_BV(PB3);
    }
    cnt1=cnt4;                            //表示数字のカウントアップ
    d1000=cnt1/1000; cnt1=cnt1-d1000*1000;
    d100=cnt1/100; cnt1=cnt1-d100*100;
    d10=cnt1/10;   cnt1=cnt1-d10*10;
    d1=cnt1;
  }                     /* 無限ループの終わり    */
}                       /* mainルーチン(main関数)の終わり    */
void wait(void){
  uint16_t k;                 /* 符号なし16bit変数宣言   */
  for(k=1;k<500;k++){k=k;}
}

 

제조회사

http://www.postec.co.kr/ 
 www.alps.com

 

반응형

'펌웨어디자인(Firmware Design)' 카테고리의 다른 글

PIC마이컴  (0) 2009.09.18
적외선통신  (0) 2009.07.19
초음파거리측정  (0) 2008.11.11
AVR 마이크로컨트롤러설계도구  (0) 2008.11.11
AVR USB AT90USB162 마이크로컨트롤러  (0) 2008.11.11