ステッピングモータを動かしてみます(PIC編)

〔マイコンのトップに戻る〕


前回はサーボモータを動かしてみました、この頁ではPIC16F1827を使ってステッピングモータを動かします。 尚、Arduinoを使ってステッピングモータを動かす記事はこちらを見て下さい。

ステッピングモータは秋月電子のこちらで購入しました。
このモータは、励磁方式が2相ユニポーラで1回転(360度)は288ステップ(1step 1.25度)です、入力電圧は12V程掛けて500mAくらい流れる様です。
なので、この頁ではユニポーラタイプのステッピングモータについて書いています。

※ 2017/01/12現在、ここで使用したステッピングモータは販売終了の様です。
  こちらで実験しましょう、但し、1回転(360度)は200ステップ(1step 1.8度)です。 *4)
  又、モータの線色も異なります、白->赤、黒->白、黄->緑、赤->黄、青->黒、緑->青と読替えます

ステッピングモータとサーボモータの比較

ステッピング モータ RCサーボモー タ
制御 ワンパルス送る度に一定の角度だけ回転します。
例えば、今回のモータならワンパルス(1step)で1.25度回転です。
送るパルスのONさせる幅により回転角度が決まります。
回転 連続回転OK
今回のモータは288ステップで1回転なので、
864パルス送れば3回転して止まります。
また、パルスのONさせる幅を変えると回転速度が変わります。
0〜180度までの回転です。
(360度回転する物もあり)
回転速度は制御不可、モータに依存します。
精度 停止制度は低くモータに依存します。
例えば、今回のモータなら1.25度まいです。
停止制度は高い
内部にエンコーダが有るので常に停止位置をキープする(フィードバック制御)。
トルク 低速域でのトルクが大きい、高回転になればトルクが小さく なり、そのうち回転しなくなる。 低速〜高速域でトルクが安定している。
回路 FET等でドライバーを作る必要がある。
(マイコンへの配線は4本:2相時)
簡単、部品不要
(マイコンへの配線は1本)
価格 安い 高い

《 配線図 》

実態配線図
この左図が実態配線図です。

いつもこのサイトで利用するハーフタイプのブレッドボードは小さすぎて部品が載らないでしょう フルサイズの大きいタイプを利用して下さい。

こちらの「FETをマイコン出力のスイッチとして使う方法」 も合わせて読んでおきましょう。

今回利用するモータには、
接続する為のコネクターケーブルが付属しています、
ブレッドボードにそのまま刺せなくもないのですがヘッダーピンあたりに半田付けしたほうが良いでしょう。

電源としてはPIC用の5V電源と
モータ用の9V-12Vの電源が必要です、ここでは9Vで実験しています。

回路説明図
左図の様にPICのデジタル13(RB7)番端子
からFETを介してモータの白色線に
接続されていますねこれが1回路分です。
デジタル12(RB6)端子からモータの赤色線
デジタル11(RB5)端子からモータの黄色線
デジタル10(RB4)端子からモータの緑色線
と全部で4回路有ります。

モータの黒色線と青色線は+電源(9V)に接続です。


ステッピングモータの制御方法について

制御図 この様に2回路ずつ順次ONさせる方式を2相励磁方式と言います。
ワンパルス1stepあたり1.25度回転します。
パルスのONする幅を短くするとモータの回転速度が上がります。

尚、ステッピングモータの詳しい制御の話は、 「PICで遊ぶ電子工作」さんの「ステッピングモータの制御」や *3)
「エフテック株式会社」さんの「ステッピングモータを廻す」
を参考にして下さい。


下記に、Arduinoで実行させた時の出力波形ですが参考に貼り付けて置きます。 *1)

正転出力(白赤->赤黄->黄緑->白緑 の4step繰り返し)
出力波形(正転)

逆転出力(白緑->黄緑->赤黄->白赤 の4step繰り返し)
出力波形(逆転)


《PICのプログラム1》

@上記配線図画面の様に配線しましょう。

AMPLAB X(v2.15)を起動させます。 *2)

B下記がPIC16F1827でのサンプルのプログラムソースです、
  MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。
  プロジェクトを作成して新規ファイルにコピーペーストして貼り付けて下さい。 *2)
---------------------------------------------------------------------
#include <xc.h>

#define _XTAL_FREQ 8000000    // delay用に必要(クロック8MHzを指定)

// コンフィギュレーション1の設定
#pragma config FOSC = INTOSC    // 内部クロックを使用する(INTOSC)
#pragma config WDTE = OFF       // ウオッチドッグタイマー無し(OFF)
#pragma config PWRTE = ON       // 電源ONから64ms後にプログラムを開始する(ON)
#pragma config MCLRE = OFF      // 外部リセット信号は使用せずにデジタル入力(RA5)ピンとする(OFF)
#pragma config CP = OFF         // プログラムメモリーを保護しない(OFF)
#pragma config CPD = OFF        // データメモリーを保護しない(OFF)
#pragma config BOREN = ON       // 電源電圧降下常時監視機能ON(ON)
#pragma config CLKOUTEN = OFF   // CLKOUTピンをRA6ピンで使用する(OFF)
#pragma config IESO = OFF       // 外部・内部クロックの切替えでの起動はなし(OFF)
#pragma config FCMEN = OFF      // 外部クロック監視しない(FCMEN_OFF)

// コンフィギュレーション2の設定
#pragma config WRT = OFF        // Flashメモリーを保護しない(OFF)
#pragma config PLLEN = OFF      // 動作クロックを32MHzでは動作させない(OFF)
#pragma config STVREN = ON      // スタックがオーバフローやアンダーフローしたらリセットをする(ON)
#pragma config BORV = HI        // 電源電圧降下常時監視電圧(2.5V)設定(HI)
#pragma config LVP = OFF        // 低電圧プログラミング機能使用しない(OFF)

// 指定した時間(num x o.1ms)だけウエイトを行う処理関数
void Wait(unsigned int num)
{
     int i ;

     // numで指定した回数だけ繰り返す
     for (i=0 ; i<num ; i++) {
          __delay_us(100) ;     // 100usプログラムの一時停止
     }
}
// ステッピングモータにパルスを出力する処理関数
//   step : 回転させるステップ数を指定する(負数値ならモータは逆回転する)
//   speed: モータの回転速度を指定する、ONさせるパルスの幅を0.1ms単位に指定
//          パルスのONする幅を短くすると速度が上がります。
void StepperOut(int step,long speed)
{
     unsigned char dt[4] = { 0b11000000 , 0b01100000 , 0b00110000 , 0b10010000 } ;
     int c , cnt ;

     cnt = 0 ;
     if (step >= 0) {
          c = 0 ;
          // 指定したステップの数だけ繰り返す、モータは正転する
          while(cnt < step) {
               LATB = (0b00001111 & LATB) | dt[c] ;
               cnt++ ;
               c++ ;
               if (c > 3) c = 0 ;
               Wait(speed) ;       // パルスのONする出力幅(速度)を調整する
          }
     } else {
          step = step * -1 ;
          c = 3 ;
          // 指定したステップの数だけ繰り返す、モータは逆転する
          while(cnt < step) {
               LATB = (0b00001111 & LATB) | dt[c] ;
               cnt++ ;
               c-- ;
               if (c < 0) c = 3 ;
               Wait(speed) ;       // パルスのONする出力幅(速度)を調整する
          }
     }

}
//  メインの処理
void main()
{
     OSCCON = 0b01110010 ;    // 内部クロックは8MHzとする
     ANSELA = 0b00000000 ;    // AN0-AN4は使用しない全てデジタルI/Oとする
     ANSELB = 0b00000000 ;    // AN5-AN11は使用しない全てデジタルI/Oとする
     TRISA  = 0b00000000 ;    // ピン(RA)は全て出力に割当てる(RA5は入力のみとなる)
     TRISB  = 0b00000000 ;    // ピン(RB)は全て出力に割当てる
     PORTA  = 0b00000000 ;    // RA出力ピンの初期化(全てLOWにする)
     PORTB  = 0b00000000 ;    // RB出力ピンの初期化(全てLOWにする)

     Wait(30000) ;            // 3秒後に開始

     while(1) {
          StepperOut(4,100) ; // 4step回転させ、速度のパルス幅は10ms
     }
}
---------------------------------------------------------------------
CコンパイルPIC書き込みを実行して下さい。

DPICをブレッドボードに取付けて下さい、ステッピングモータが連続回転すると思います。
 今回はPICの10−13番端子をモータの出力としたサンプルプログラムです、
 異なる端子を利用する場合はStepperOut()関数を書き換える必要が有ります。

関数について

Wait(num)
  numにて指定した数値だけウエイト動作を行います。
  num :num x 0.1ms(100us)です、10と指定したら1ms、10000なら1秒ですね。

StepperOut(int step,long speed)
  この関数で実際にステッピングモータにパルスを出力します。
  step   :何ステップ回転させるか指定します、このモータで1stepあたり1.25度です。
       指定したステップだけ動作完了するまではこの関数は終了しません、注意しましょう。
       例えば StepperOut(864,100) ; としたら3回転するまではこの関数は実行中です。
       それとぉ、StepperOut(-4,100) ; と負数値を指定した場合はモータは逆回転します。
  speed :回転速度の指定です、出力するパルスのONする幅を0.1ms(100us)単位で指定します。
       パルスのONする幅が小さくなると速度が速くなります、
       このモータでは3ms以上にしましょう、これ以上早く回すと回転しなくなります。

  それとぉ、
     while(1) {
          StepperOut(4,100) ; // 4step回転させ、速度のパルス幅は10ms
     }
  の部分を
     StepperOut(288,100) ;
     while(1) ;
  に書き換えて見て下さい
  ステッピングモータは1回転して止まります。

  ※ 停止時は、コイルに電流を流していないのでフリーラン状態でトルクは掛かっていません。

I/OポートBについて

今回のモータへのパルス出力はポートBのRB4〜RB7を使用しています。
 LATB = 0b11110000  右から左へRB0からRB7の順です。
                今回は赤色の部分RB4(10番ピン)〜RB7(13番ピン)を使用します。

 だからぁ、上記載の”ステッピングモータの制御方法”のパルス図で示した様にRB4〜RB7へ出力する
 には下の様なデータでstep1〜step4を順次繰り返して出力すればモータは回転します。
               step1        step2        step3        step4
 dt[4] = { 0b11000000 , 0b01100000 , 0b00110000 , 0b10010000 } ;
 また、step4〜step1と逆に順次繰り返して出力すればモータは逆回転します。

《PICのプログラム2》

実験風景  こんどは上図の配線図に半固定抵抗(ボリューム)を
 追加配線して下さい。
 PICのアナログ1番端子(AN2)に半固定抵抗を接続
 しています。

 下のプログラムを動かしてみましょう、
 半固定抵抗を右に回せば回した分だけモータが
 右に回転します、
 半固定抵抗を左に回せばモータも左へ回転です、
 半固定抵抗の回転を止めればモータも停止します。
 (モータ停止状態で微妙にフルフルしていますが、
 これは半固定抵抗の読取り値がふらついている
 からです)

 半固定抵抗とモータの回す方向が逆の場合は、
 半固定抵抗の+電源とGND線を入れ替えて下さい。

---------------------------------------------------------------------
#include <xc.h>

#define _XTAL_FREQ 8000000    // delay用に必要(クロック8MHzを指定)

int PreVal ;                  // 前回読み込んだ可変抵抗の値を保存する変数

// コンフィギュレーション1の設定
#pragma config FOSC = INTOSC    // 内部クロックを使用する(INTOSC)
#pragma config WDTE = OFF       // ウオッチドッグタイマー無し(OFF)
#pragma config PWRTE = ON       // 電源ONから64ms後にプログラムを開始する(ON)
#pragma config MCLRE = OFF      // 外部リセット信号は使用せずにデジタル入力(RA5)ピンとする(OFF)
#pragma config CP = OFF         // プログラムメモリーを保護しない(OFF)
#pragma config CPD = OFF        // データメモリーを保護しない(OFF)
#pragma config BOREN = ON       // 電源電圧降下常時監視機能ON(ON)
#pragma config CLKOUTEN = OFF   // CLKOUTピンをRA6ピンで使用する(OFF)
#pragma config IESO = OFF       // 外部・内部クロックの切替えでの起動はなし(OFF)
#pragma config FCMEN = OFF      // 外部クロック監視しない(FCMEN_OFF)

// コンフィギュレーション2の設定
#pragma config WRT = OFF        // Flashメモリーを保護しない(OFF)
#pragma config PLLEN = OFF      // 動作クロックを32MHzでは動作させない(OFF)
#pragma config STVREN = ON      // スタックがオーバフローやアンダーフローしたらリセットをする(ON)
#pragma config BORV = HI        // 電源電圧降下常時監視電圧(2.5V)設定(HI)
#pragma config LVP = OFF        // 低電圧プログラミング機能使用しない(OFF)

// 指定した時間(num x o.1ms)だけウエイトを行う処理関数
void Wait(unsigned int num)
{
     int i ;

     // numで指定した回数だけ繰り返す
     for (i=0 ; i<num ; i++) {
          __delay_us(100) ;     // 100usプログラムの一時停止
     }
}
// アナログ値の変換と読込み処理
unsigned int adconv()
{
     unsigned int temp;

     GO_nDONE = 1 ;	      // アナログ値読取り開始指示
     while(GO_nDONE) ;        // 読取り完了まで待つ
     temp = ADRESH ;          // PICは読取った値をADRESHとADRESLのレジスターにセットする
     temp = ( temp << 8 ) | ADRESL ;

     return temp ;
}
// ステッピングモータにパルスを出力する処理関数
//   step : 回転させるステップ数を指定する(負数値ならモータは逆回転する)
//   speed: モータの回転速度を指定する、ONさせるパルスの幅を0.1ms単位に指定
//          パルスのONする幅を短くすると速度が上がります。
void StepperOut(int step,long speed)
{
     unsigned char dt[4] = { 0b11000000 , 0b01100000 , 0b00110000 , 0b10010000 } ;
     int c , cnt ;

     cnt = 0 ;
     if (step >= 0) {
          c = 0 ;
          // 指定したステップの数だけ繰り返す、モータは正転する
          while(cnt < step) {
               LATB = (0b00001111 & LATB) | dt[c] ;
               cnt++ ;
               c++ ;
               if (c > 3) c = 0 ;
               Wait(speed) ;       // パルスのONする出力幅(速度)を調整する
          }
     } else {
          step = step * -1 ;
          c = 3 ;
          // 指定したステップの数だけ繰り返す、モータは逆転する
          while(cnt < step) {
               LATB = (0b00001111 & LATB) | dt[c] ;
               cnt++ ;
               c-- ;
               if (c < 0) c = 3 ;
               Wait(speed) ;       // パルスのONする出力幅(速度)を調整する
          }
     }

}
//  メインの処理
void main()
{
     int num , i ;

     OSCCON = 0b01110010 ;    // 内部クロックは8MHzとする
     ANSELA = 0b00000100 ;    // AN2のみアナログ使用、他のAN0,1,3,4は使用しないデジタルI/Oとする
     ANSELB = 0b00000000 ;    // AN5-AN11は使用しない全てデジタルI/Oとする
     TRISA  = 0b00000100 ;    // RA2のみ入力、他のピン(RA)は出力に割当てる(RA5は入力のみとなる)
     TRISB  = 0b00000000 ;    // ピン(RB)は全て出力に割当てる
     PORTA  = 0b00000000 ;    // RA出力ピンの初期化(全てLOWにする)
     PORTB  = 0b00000000 ;    // RB出力ピンの初期化(全てLOWにする)
     // A/Dの設定
     ADCON1 = 0b10010000 ;    // 読取値は右寄せ、A/D変換クロックはFOSC/8、VDDをリファレンスとする
     ADCON0 = 0b00001001 ;    // アナログ変換情報設定(AN2から読込む)
     __delay_us(5) ;          // アナログ変換情報が設定されるまでとりあえず待つ

     PreVal = 0 ;             // 前回値は0として初期化

     Wait(30000) ;            // 3秒後に開始

     while(1) {
          // 1番ピン(AN2)から可変抵抗の値を30回読み込み平均化する
          num = 0 ;
          for (i=0 ; i < 30 ; i++) {
               num = num + adconv() ;
          }
          num = num / 30 ;                   // 可変抵抗からの値を今回値とする
          // ステッピングモータに出力する
          StepperOut(num - PreVal,100) ;     // 今回値−前回値の値だけ回転させる
          PreVal = num ;                     // 今回値を前回値として保存する
     }
}
---------------------------------------------------------------------

アナログ入力について

半固定抵抗からのアナログ入力についての詳しい話はこちらを参考にして下さい。

尚、
          num = 0 ;
          for (i=0 ; i < 30 ; i++) {
               num = num + adconv() ;
          }
          num = num / 30 ;                   // 可変抵抗からの値を今回値とする
と、半固定抵抗の値を30回読み込み平均化していますが、
これは半固定抵抗からの読み込み値がふらついているので、少しでもふらつきを抑える為です。
ちなみに下の様に書き換えて実行して見て下さい。
          num = adconv() ;
どうでしょう?、だいぶんモータの回転がフルフルしていて操作しにくいと思います。

《 その他 》

実験風景

左は実験風景の写真です。

モータの回転が判り易い様に、軸にはテープが巻いて有ります、適当な回転数で回さないとモータは
結構振動が有ります。

外部電源12Vでも行ってみました、回転速度も上がり安定して制御しやすい様に感じます、
また、4.5Vでも行いましたが回るには回ります、何かに組み込む場合は12V電源が良いかもね。


バイポーラステッピングモータ
ドライバのL6470を使った記事は
こちらを参照下さい。*3)




リンク切れ見直し(*4) 2017/01/12
追記(*3) 2016/09/27
MPLAB X用に記事変更(*2) 2015/10/27
追記(*1) 2014/06/22


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2017 Shigehiro Kimura All Rights Reserved.