ロータリーエンコーダーの回転をステッピングモーターへ
ロータリーエンコーダーの回転をステッピングモーターへ
Rエンコーダーの回転をステッピングモーター回転用にLED表示をして試したので、それをつないでみます。
単にLEDに出力するところをステッピングモーターにつなぎ変えるだけです。
1-1相励磁、2-2相励磁で回してみましょう。
1-1相励磁 駆動 です。
Pモーター相 | X | x_ | Y | y_ | ||
LED | P17 | P16 | P15 | P14 | ||
SPcnt=0 | ● | ● | ● | ● | 右 回転 ↓ |
左 回転 ↑ |
SPcnt=1 | ● | ● | ● | ● | ||
SPcnt=2 | ● | ● | ● | ● | ||
SPcnt=3 | ● | ● | ● | ● |
STPモーターを回す場合には IOの出力をLEDから STPモーターに変えればよいだけです。
回路図
すでに回路があるので前回のLED点灯のものとIOピンが違いますが、もちろんLED点灯のピンをドライバ入力へつなぎ代えてもOKです。
プログラム
Rエンコーダー SPモーター用1相駆動
FQ_adv_Enc_SPmtr1_1
/* ロータリーエンコーダーの回転判別
STPモーター回転 & Rエンコーダー値
*/
#include<3664.h>
#include"myfunc.h"
#define H8_3664
unsigned char ft; //記憶値
unsigned char cnt=0; //カウンタ
int SPcnt=0;
void SPmtr(){
if(SPcnt>3) SPcnt=0;
else if(SPcnt<0) SPcnt=3;
//1-1相
switch(SPcnt){
case 0: IO.PDR8.BIT.B4=1; /* 0001 0010 */
IO.PDR8.BIT.B3=0;
IO.PDR8.BIT.B2=0;
IO.PDR8.BIT.B1=0;
break;
case 1: IO.PDR8.BIT.B4=0; /* 0001 0010 */
IO.PDR8.BIT.B3=0;
IO.PDR8.BIT.B2=1;
IO.PDR8.BIT.B1=0;
break;
case 2: IO.PDR8.BIT.B4=0; /* 0001 0010 */
IO.PDR8.BIT.B3=1;
IO.PDR8.BIT.B2=0;
IO.PDR8.BIT.B1=0;
break;
case 3: IO.PDR8.BIT.B4=0; /* 0001 0010 */
IO.PDR8.BIT.B3=0;
IO.PDR8.BIT.B2=0;
IO.PDR8.BIT.B1=1;
break;
}
}
unsigned char fD(unsigned char ft0,unsigned char ft1){
/* 回転方向 判別式関数 引数 ft0: 1つ前の状態値 */
/* ft1: 現在地 */
/* 返値 (01=)1 or (10=)2 */
unsigned char D;
ft = ft1; /* ftに保存し 現在値とする */
/* ft と ft0 は 別変数 */
ft0 = ft0 << 1 ; /* 1つ前の状態値 をビットシフト */
ft0 = ft0 & 3 ; // 0000 0011 でマスク(AND)し、下位2ビットだけ取り出す
ft1 = ft1 & 3 ; // 0000 0011 でマスク(AND)、下位2ビットだけ取り出す
D = (ft0 + ft1) & 3 ; //2つを+し判別式の結果、マスク
return(D);
}
void int_timerv(void){
unsigned char pb; //回転判別式 値
unsigned char PD; //Renc現在値
PD=IO.PDR8.BYTE >> 6; //Renc現在値 読み取り
/* 記憶値(ft) と 現在値(PD)=Rencのビット状態(IO.PDR8.BYTE) が違う*/
if(ft != PD){ // → 回転した
pb = fD(ft,PD); //回転判別式
//回転方向によって、LEDでお知らせ#0,#1&カウンタ累積
if(pb>=2){ //左回転のとき
cnt++;
SPcnt++;
SPmtr();
}else{ //右回転のとき
cnt--;
SPcnt--;
SPmtr();
}
}
TV.TCSRV.BIT.CMFB = 0;
}
void main(void){
DI;
IO.PCR8=0x3F; /* Bit0,1だけは0:入力 他は全て1にセットし出力に設定 0011 1111 */
IO.PCR1=0xFF;
// /*タイマーV 約2msごとに割り込み */
TV.TCRV1.BYTE=0x01; // (0000 0001)
TV.TCRV0.BYTE=0x93; //(1001 0011) 1/128 125kHz)
TV.TCORB=250; //500kHz(2ms)
ft= IO.PDR8.BYTE >> 6; /* 初期化 : 現在値をグローバル変数に保存 */
LCD_init( 16 );
EI;
while(1) {
//LCD表示
LCD_disp("cnt=",1);
LCD_dataout(cnt);
LCD_disp("SPcnt=",2);
LCD_dataout(SPcnt);
}
}
LEDへの出力部分をSTPモーターに代えただけです。
IOをP81~P84へ
IO.PDR8.BIT.B4
IO.PDR8.BIT.B3
IO.PDR8.BIT.B2
IO.PDR8.BIT.B1
同時に LCDに変数を表示させています。
2相駆動にする
続いて 2-2相駆動に変更します。少しだけ変更するだけです。
各IOのところの一つを 0→1 に変えるだけです。同時に毎回どれか2ピンに通電します。
Rエンコーダー SPモーター用2相駆動 R2:SP1
FQ_adv_Enc_SPmtr2_2
/* ロータリーエンコーダーの回転判別
Rエンコーダー値 & SP回転 2-2相
1 : 2
*/
#include<3664.h>
#include"myfunc.h"
#define H8_3664
unsigned char ft; //記憶値
unsigned char cnt=0; //カウンタ
int SPcnt=0;
void SPmtr(){
if(SPcnt>6) SPcnt=0;
else if(SPcnt<0) SPcnt=6;
//R:2:SP:1 2-2相
switch(SPcnt){
case 0: IO.PDR8.BIT.B4=1; /* */
IO.PDR8.BIT.B3=0;
IO.PDR8.BIT.B2=0;
IO.PDR8.BIT.B1=1;
break;
case 2: IO.PDR8.BIT.B4=1; /* */
IO.PDR8.BIT.B3=0;
IO.PDR8.BIT.B2=1;
IO.PDR8.BIT.B1=0;
break;
case 4: IO.PDR8.BIT.B4=0; /* */
IO.PDR8.BIT.B3=1;
IO.PDR8.BIT.B2=1;
IO.PDR8.BIT.B1=0;
break;
case 6: IO.PDR8.BIT.B4=0; /* */
IO.PDR8.BIT.B3=1;
IO.PDR8.BIT.B2=0;
IO.PDR8.BIT.B1=1;
break;
}
}
unsigned char fD(unsigned char ft0,unsigned char ft1){
/* 回転方向 判別式関数 引数 ft0: 1つ前の状態値 */
/* ft1: 現在地 */
/* 返値 (01=)1 or (10=)2 */
unsigned char D;
ft = ft1; /* ftに保存し 現在値とする */
/* ft と ft0 は 別変数 */
ft0 = ft0 << 1 ; /* 1つ前の状態値 をビットシフト */
ft0 = ft0 & 3 ; // 0000 0011 でマスク(AND)し、下位2ビットだけ取り出す
ft1 = ft1 & 3 ; // 0000 0011 でマスク(AND)、下位2ビットだけ取り出す
D = (ft0 + ft1) & 3 ; //2つを+し判別式の結果、マスク
return(D);
}
void int_timerv(void){
unsigned char pb; //回転判別式 値
unsigned char PD; //Renc現在値
PD=IO.PDR8.BYTE >> 6; //Renc現在値 読み取り
/* 記憶値(ft) と 現在値(PD)=Rencのビット状態(IO.PDR8.BYTE) が違う*/
if(ft != PD){ // → 回転した
pb = fD(ft,PD); //回転判別式
//回転方向によって、LEDでお知らせ#0,#1&カウンタ累積
if(pb>=2){ //左回転のとき
cnt++;
SPcnt++;
SPmtr();
}else{ //右回転のとき
cnt--;
SPcnt--;
SPmtr();
}
}
TV.TCSRV.BIT.CMFB = 0;
}
void main(void){
DI;
IO.PCR8=0x3F; /* Bit0,1だけは0:入力 他は全て1にセットし出力に設定 0011 1111 */
IO.PCR1=0xFF;
// /*タイマーV 約2msごとに割り込み */
TV.TCRV1.BYTE=0x01; // (0000 0001)
TV.TCRV0.BYTE=0x93; //(1001 0011) 1/128 125kHz)
TV.TCORB=250; //500kHz(2ms)
ft= IO.PDR8.BYTE >> 6; /* 初期化 : 現在値をグローバル変数に保存 */
LCD_init( 16 );
EI;
while(1) {
//LCD表示
LCD_disp("cnt=",1);
LCD_dataout(cnt);
LCD_disp("SPcnt=",2);
LCD_dataout(SPcnt);
}
}
STPモーター相 | X | x_ | Y | y_ | - | - |
SPモーター | P84 | P83 | P82 | P81 | - | - |
SPcnt=0 | ● | ● | ● | ● | 右 回転 ↓ |
左 回転 ↑ |
SPcnt=1 | ● | ● | ● | ● | ||
SPcnt=2 | ● | ● | ● | ● | ||
SPcnt=3 | ● | ● | ● | ● |
case 0:
IO.PDR8.BIT.B4=1;
IO.PDR8.BIT.B3=0;
IO.PDR8.BIT.B2=0;
IO.PDR8.BIT.B1=1
・
・
とIO出力部分を少しだけ変えるだけです。
このようにIO部分を変更して2相駆動にしています。
また、今度は回転数をよりあわせるために、Rエンコーダー2ステップ回転で STPモーター1ステップ回転にしています。
そこは、
if(SPcnt>6) SPcnt=0;
else if(SPcnt<0) SPcnt=6;
caseを2 とびにしています。
実行
Rエンコーダーの回転にあわせて回るので、速く回すほどSTPモーターも速く回転します。
1相駆動では Rエンコーダー 1ステップ回転で STPモーターも1ステップ回ります。
1周のステップ数が違うので、Rエンコーダー半回転でSPモーターが1回転ぐらいになります。
あまり速く回すとSTPモーターが脱調してついていけません。
2相駆動にすると、力強くまわります。ついでに、Rエンコーダー2ステップでSPモーターが1ステップにしています。
Rエンコーダの回転にあわせてSTPモーターを回すという方法でした。
この方法ではパルスのON,OFF時間が手で回した速度によるため、SPモーターの回り方、トルクが操作によって変わることになります。
SPモーター駆動関数void SPmtr() で 各ピン出力のあと ホールド時間を設けるなどしての工夫、変更が必要になるでしょう。
- twtter
- google+
- hatena