ロータリーエンコーダーの回転をSPモーターへ
実験編で、SPモーターの原理、動かし方を試したので、それを復習してローターリーエンコーダーと組み合わせます。
すでにRエンコーダーの回転を読み取り数値化するものはすでに作ったので少し改良するだけです。
Rエンコーダーは回転を読み取る関数をすでに実験編で作りました。SPモーターもIO出力で回転させる方法も試しました。
これら2つの方法を少し改良して組み合わせます。
- Rエンコーダーは出てくるビット値により、
-
左に回ったか、右に回ったか、判定できます。
- SPモーターはIO出力で
- 1ステップずつ回転させることが出来ます。
- 2つを組み合わせ、
- Rエンコーダーが左か右に回ったとき、SPモーターをIO出力で1ステップ回転させます
SPモーターの回転速度もRエンコーダーにあわせて回ります。
ステッピングモータを動かす のところのとおり
X - Y - x_- y_ の順で通電すれば回転するのがSPモーターでした。
わかりやすく、まずは
Rエンコーダーを回すとその回転を拾い、IOに出力しLEDを点灯させてみます。
SPモーター相 | X | x_ | Y | y_ | ||
LED | P17 | P16 | P15 | P14 | ||
SPcnt=0 | ● | ● | ● | ● | 右 回転 ↓ |
左 回転 ↑ |
SPcnt=1 | ● | ● | ● | ● | ||
SPcnt=2 | ● | ● | ● | ● | ||
SPcnt=3 | ● | ● | ● | ● |
4つのLEDのどれかを点灯させ、SPモーター回転ではそれがSPモーターの4つのコイルで、それに通電することになります。
LEDが光るのでSPモーターのどの相に通電しているかがよくわかるでしょう。
手始めにSPモーターはつながずLEDだけでやってみます。
SPモーターを回す場合には IOの出力をLEDから SPモーターに変えればよいだけです。
回路図
プログラム
Rエンコーダー SPモーター用LED点灯
FQ_adv_Enc_SPmtrLED
/* ロータリーエンコーダーの回転判別
LED点灯 & Rエンコーダー値 LCD表示
*/
#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;
switch(SPcnt){
case 0: IO.PDR1.BIT.B7=1; /* 0001 0010 */
IO.PDR1.BIT.B6=0;
IO.PDR1.BIT.B5=0;
IO.PDR1.BIT.B4=0;
break;
case 1: IO.PDR1.BIT.B7=0; /* 0001 0010 */
IO.PDR1.BIT.B6=0;
IO.PDR1.BIT.B5=1;
IO.PDR1.BIT.B4=0;
break;
case 2: IO.PDR1.BIT.B7=0; /* 0001 0010 */
IO.PDR1.BIT.B6=1;
IO.PDR1.BIT.B5=0;
IO.PDR1.BIT.B4=0;
break;
case 3: IO.PDR1.BIT.B7=0; /* 0001 0010 */
IO.PDR1.BIT.B6=0;
IO.PDR1.BIT.B5=0;
IO.PDR1.BIT.B4=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);
}
}
定期的に呼び出すための割り込み関数に TimerV を使用し、間隔を Rエンコーダーの説明書にあるチャタリングをさける最小の間隔2msにしました。
SPモーターを回転させる関数 SPmtr()
この関数を呼び出すたびに1ステップすすめ回転します。グローバル変数 SPcnt で0~3の相を記憶しておきます。
割り込み関数内で
Rエンコーダーの回転判定で 下の if で左、右回転のときの処理を記述しています。
各if 内に左回転、右回転の時の処理を記述します。
左回転のときに
SPcnt++; で1つ増やして 回転関数を呼ぶ → SPmtr();
SPcntが1つ増えているので SPmtr();で SPモーターは1ステップ左回転する
右回転のときに
SPcnt--; で1つへらして 回転関数を呼ぶ → SPmtr();
SPcntが1つへっているので SPmtr();で SPモーターは1ステップ右回転する(戻る)
同時に LCDに変数を表示させています。
実行
Rエンコーダーを1ステップ回すと、代わりにLCDに通電し、光ってわかります。
にRエンコーダーを回すとLEDが点灯します。
SPモーターへもこのように通電されます。 1-1相励磁 駆動 です。
Pモーター相 | X | x_ | Y | y_ | ||
LED | P17 | P16 | P15 | P14 | ||
SPcnt=0 | ● | ● | ● | ● | 右 回転 ↓ |
左 回転 ↑ |
SPcnt=1 | ● | ● | ● | ● | ||
SPcnt=2 | ● | ● | ● | ● | ||
SPcnt=3 | ● | ● | ● | ● |
同時に
Rエンコーダーのステップ数:cnt
SPモーターの相:SPcnt
1~3 をLCDに表示します。
つづいて、これをステッピングモーターにつなげます。
- twtter
- google+
- hatena