PICマイコンでSDカード上のWAVを再生して音の出るプラモデルの飾り台を作ろうとしている作業。音の部分はできたので、今度はスピーカーを組み込んだ箱の部分を作ってみた。
ポイントマシン用ステッピングモーターの動作確認 (その3)
PICマイコンとステッピングモーターを使ってスローアクションのNゲージ用ポイントマシンを作ろう・・として細々と準備してきたが、レイアウトの台枠が出来上がりつつあるのでボチボチ制御用の基盤とプログラムの準備も開始。
レイアウト上のポイントマシンは18個。
・制御用のPICマイコンはなるべくポイントマシンのそばに配置して配線は極力短くしたい。
・PICマイコンの数も極力少なくして無駄な電力消費は押さえたい。
・ひとまずより多くのポイントマシンを制御するためにはポート数の多いPICマイコンを。
等々の理由から、ポイントマシンが集まる部分には40ピンのPIC16F887を使用することにした。
2相ユニポーラのステッピングモーターを制御するにはPICマイコンから4ポート分の出力が必要になる。
そのPICマイコンからの出力の先には8chダーリントンシンクドライバであるトランジスタアレイ・TD62083APGを配置。
TD62083APG は1つのパッケージに8回路あるので、2個のステッピングモーターを接続できることになる。
この先にステッピングモーター。
つまり、PIC16F887が1個、TD62083APGが2個あれば4個のステッピングモーター(4個のポイントマシン)を制御できることになる。
今回は、次の2点を主眼に作業してみた。
・ステッピングモーターの正転、逆転という基本的な動作ができるプログラムの作成
・基板上にPICマイコンとトランジスタアレイを配置した回路の作成
基板
基板自体は絶縁も兼ねて3mm厚のプラダンに取り付けた。
プラダンとしたのは軽量化のため。
これをレイアウトの線路を引く板の裏側に逆さまにして取り付ける。
右上の基板は電源部とI2Cマスターと通信するためのLANケーブルを接続するコネクタを配したもの。
右下の基板は踏切警報器の音とLED、交通信号機のカッコー音を出すためのもの。
この部分の踏切警報器、交通信号機は駅構内に配置するものなので、手動でON/OFFする。
・・構内以外に配置するものはセンサー等で制御してON/OFFしたり、プログラムで制御したり。
左側の基板が今回の記事のメインとなるポイントマシン制御用。
ポイントマシン制御用PICマイコンを配置する基板
現在作り込んでいるこの部分のパーツで4つのポイントマシンが制御できる。
40ピンのPIC16F887が1個とトランジスタアレイTD62083APGが2個。
コネクタから先はLANケーブルを利用してステッピングモーターを接続。
空いている右側の部分にはもう1セット。
つまり、この基板上に8つのポイントマシンを制御するパーツを配置。
下の空いた部分には2色現示の信号機のLEDを制御するためPICマイコンを作り込む予定。
基板とステッピングモーターの間は0.5/4PのLANケーブルを使って接続する。
細いかな?という感じがしないわけでもないが、元々ステッピングモーターについていた配線もかなり細い物。
写真の上側が0.5のLANケーブルの心線、下側がステッピングモーターについていたケーブル。
どっこいどっこいかと思っていたが、実は0.5のLANケーブルの方が太そう。
ポイント転換に要する時間も2秒程度ではなかろうかと思われるし、ポイントなんかそんなにしょっちゅう転換することはない。
0.5のLANケーブルで大丈夫だと思う。
・・最近はやりの細いケーブルは無理・・かな。
動作確認用プログラム
基本的にはI2Cのマスターからのどのポイントを定位にするか反位にするかのコマンドを受信して動作させることになるが、I2Cのマスターが接続されていないときには押し釦スイッチでも転換できる仕様とする予定。
手元に用意してあるステッピングモーターはPG27-1601、SPG20-1362の2種類。
左:PG27-1601
右:SPG20-1362
こんな感じで使う予定。
共に日本電産コパル電子のものであるが、基本ステップ角度など若干仕様が異なっている部分がある。
ただ、今回使用する上では回路上は特に留意する部分はなく、同一でも大丈夫そう。
ソフトで若干留意すれば良さそうかな、という感じ。
参考までに、ステッピングモーターを回転させるための作成したプログラムを・・・
//*********************************************** // ポイントマシン転換用PICマイコン制御ボード用プログラム // // このソースは4つのステッピングモーターに関する基板の配線が正しくなされ、 // ステッピングモーターが回転することを確認するフェーズ // // 順次、次のフェーズのコーディングを追加することを想定。そのため、現時点では不要の定義もある // //*********************************************** // PIC16F887 // ステッピングモーターポイントマシン(4回路) // // PIC16F887 voltage range (2.0V-5.5V) // TD62083APGが5Vであるため、PIC16F887の動作電圧も5Vとする // // ピンアサイン // #1 RE3/MCLR MCLR(内部pullup) // #2 RA0 OUT TD62083APG 1 #8 -> #11 -> モーター1 ny(nφ2) 緑 // #3 RA1 OUT TD62083APG 1 #7 -> #12 -> モーター1 nx(nφ1) 黄 // #4 RA2 OUT TD62083APG 1 #6 -> #13 -> モーター1 y(φ2) 赤 // #5 RA3 OUT TD62083APG 1 #5 -> #14 -> モーター1 x(φ1) 白 // #6 RA4 OUT TD62083APG 1 #4 -> #15 -> モーター2 ny(nφ2) 緑 // #7 RA5 OUT TD62083APG 1 #3 -> #16 -> モーター2 nx(nφ1) 黄 // #8 RE0 OUT TD62083APG 2 #2 -> #17 -> モーター4 y(φ2) 赤 // #9 RE1 OUT TD62083APG 2 #1 -> #18 -> モーター4 x(φ1) 白 // #10 RE2 OUT 動作確認LED -> 抵抗 -> GND // #11 Vdd + // #12 Vss - // #13 RA7 OUT TD62083APG 1 #1 -> #18 -> モーター2 y(φ2) 赤 // #14 RA6 OUT TD62083APG 1 #2 -> #17 -> モーター2 x(φ1) 白 // #15 RC0 OUT TD62083APG 2 #8 -> #11 -> モーター3 ny(nφ2) 緑 // #16 RC1 OUT TD62083APG 2 #7 -> #12 -> モーター3 nx(nφ1) 黄 // #17 RC2 OUT TD62083APG 2 #6 -> #13 -> モーター3 y(φ2) 赤 // #18 RC3 I2C CLOCK // #19 RD0 IN P1 定位検出スイッチ アクティブロー 外部pullup(VDD - 10k - PIN - SW - GND) // #20 RD1 IN P1 反位検出スイッチ アクティブロー 外部pullup // #21 RD2 IN P2 定位検出スイッチ アクティブロー 外部pullup // #22 RD3 IN P2 反位検出スイッチ アクティブロー 外部pullup // #23 RC4 I2C DATA // #24 RC5 OUT TD62083APG 2 #5 -> #14 -> モーター3 x(φ1) 白 // #25 RC6 OUT TD62083APG 2 #4 -> #15 -> モーター4 ny(nφ2) 緑 // #26 RC7 OUT TD62083APG 2 #3 -> #16 -> モーター4 nx(nφ1) 黄 // #27 RD4 IN P3 定位検出スイッチ アクティブロー 外部pullup // #28 RD5 IN P3 反位検出スイッチ アクティブロー 外部pullup // #29 RD6 IN P4 定位検出スイッチ アクティブロー 外部pullup // #30 RD7 IN P4 反位検出スイッチ アクティブロー 外部pullup // #31 Vss - // #32 Vdd + // #33 RB0 IN P1 定位移動スイッチ アクティブロー 内部pullup // #34 RB1 IN P1 反位移動スイッチ アクティブロー 内部pullup // #35 RB2 IN P2 定位移動スイッチ アクティブロー 内部pullup // #36 RB3 IN P2 反位移動スイッチ アクティブロー 内部pullup // #37 RB4 IN P3 定位移動スイッチ アクティブロー 内部pullup // #38 RB5 IN P3 反位移動スイッチ アクティブロー 内部pullup // #39 RB6/ICSPCLK IN P4 定位移動スイッチ アクティブロー 内部pullup // #40 RB7/ICSPDAT IN P4 反位移動スイッチ アクティブロー 内部pullup // ステッピングモーター PG27-1601、SPG20-1362の場合 // 基本ステップ角度=3° // コネクタ ケース背面から軸方向に向かって左から // φ1 φ2 φ1c φ2c nφ1 nφ2 // 白 赤 黒 青 黄 緑 // φ1c φ2cは+5Vへ // TD62083APG // TD62083APG #1 PIC16F887 // 未接続 | 10 9 | GND | // モーター1 ny(nφ2) 緑 | 11 8 | | 2 RA0 // モーター1 nx(nφ1) 黄 | 12 7 | | 3 RA1 // モーター1 y(φ2) 赤 | 13 6 | | 4 RA2 // モーター1 x(φ1) 白 | 14 5 | | 5 RA3 // モーター2 ny(nφ2) 緑 | 15 4 | | 6 RA4 // モーター2 nx(nφ1) 黄 | 16 3 | | 7 RA5 // モーター2 y(φ2) 赤 | 17 2 | | 14 RA6 // モーター2 x(φ1) 白 | 18 1 | | 13 RA7 // TD62083APG #2 PIC16F887 // 未接続 | 10 9 | GND | // モーター3 ny(nφ2) 緑 | 11 8 | | 15 RC0 // モーター3 nx(nφ1) 黄 | 12 7 | | 16 RC1 // モーター3 y(φ2) 赤 | 13 6 | | 17 RC2 // モーター3 x(φ1) 白 | 14 5 | | 24 RC5 // モーター4 ny(nφ2) 緑 | 15 4 | | 25 RC6 // モーター4 nx(nφ1) 黄 | 16 3 | | 26 RC7 // モーター4 y(φ2) 赤 | 17 2 | | 8 RE0 // モーター4 x(φ1) 白 | 18 1 | | 9 RE1 // コンパイラ XC8 #include #include #include #include "../n-gauge-layout-v1.h" // PIC16F887 Configuration Bit Settings // 'C' source line config statements // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. // CONFIG1 #pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = ON // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR) #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Reset Selection bits (BOR enabled) #pragma config IESO = ON // Internal External Switchover bit (Internal/External Switchover mode is enabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) #pragma config LVP = OFF // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming) // CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) #pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off) // クロック #define _XTAL_FREQ 8000000L // クロック 8MHz ボーレート、__delay_ms用 //*********************************************** // ステッピングモーターの定義 //*********************************************** // モーターの型 #define PG271601 0 // PG27-1601 #define SPG201362 1 // SPG20-1362 //*********************************************** // このポイントマシン転換用PICマイコン制御ボードの定義 // // このボードは・・ //*********************************************** #define BOARD_1 1 // 1 P20~P21の4個を制御 //#define BOARD_2 2 // 2 P22~P24の4個を制御 //#define BOARD_3 3 // 3 P25~P26の4個を制御 //#define BOARD_4 4 // 4 P120~P121の2個を制御 //#define BOARD_5 5 // 5 P220を制御 //#define BOARD_6 6 // 6 P251~P253の3個を制御 #ifdef BOARD_1 // P20~P21の4個のポイントマシンを制御 // I2Cアドレス // unsigned char i2c_address = I2CADDR_P_BOARD_1; // 制御ボードが管理するモーターの数 #define MOTORS 4 // 使用モーター unsigned char motortype[MOTORS] = { PG271601, // P20 PG27-1601 SPG201362, // P21 SPG20-1362 SPG201362, // P22 SPG20-1362 SPG201362 // P23 SPG20-1362 }; // 定位への回転方法 // unsigned char teii_direction[MOTORS] = { // P_R_RIGHT, // P20 右回転で定位に到達 // P_R_RIGHT, // P21 右回転で定位に到達 // P_R_LEFT, // P22 左回転で定位に到達 // P_R_LEFT // P23 左回転で定位に到達 // }; #endif //*********************************************** // モーターを接続するポートの定義 // // pulseMxxxにパルスパターンの値を設定することでモーターが回転する //*********************************************** // モーター1: RA3,RA2,RA1,RA0 // モーター2: RA7,RA6,RA5,RA4 typedef union pulseportbit_RA_M1M2{ struct { unsigned pulseM1 :4; // RA3,RA2,RA1,RA0 unsigned pulseM2 :4; // RA7,RA6,RA5,RA4 }; } union_RA_M1M2; union pulseportbit_RA_M1M2 *pulseportRA_M1M2; // モーター3のその1 // RC2,RC1,RC0 typedef union pulseportbit_RC_M3P1{ struct { unsigned pulseM3P1 :3; // RC2,RC1,RC0 }; } union_RC_M3P1; union pulseportbit_RC_M3P1 *pulseportRC_M3P1; // モーター3のその2 // RC5 typedef union pulseportbit_RC_M3P2{ struct { unsigned :5; // RC4,RC3,RC2,RC1,RC0 unsigned pulseM3P2 :1; // RC5 }; } union_RC_M3P2; union pulseportbit_RC_M3P2 *pulseportRC_M3P2; // モーター4のその1 // RC6,RC7 typedef union pulseportbit_RC_M4P1{ struct { unsigned :6; // RC5,RC4,RC3,RC2,RC1,RC0 unsigned pulseM4P1 :2; // RC7,RC6 }; } union_RC_M4P1; union pulseportbit_RC_M4P1 *pulseportRC_M4P1; // モーター4のその2 // RE1,RE0 typedef union pulseportbit_RE_M4P2{ struct { unsigned pulseM4P2 :2; // RE1,RE0 }; } union_RE_M4P2; union pulseportbit_RE_M4P2 *pulseportRE_M4P2; //*********************************************** // パルスパターン(2相励磁) // // モーターを接続するポートpulseMxxにこのパターンを設定することでモーターが回転する // 配列の昇順に出力すると軸面から見て左回りとなる //*********************************************** #define PATMAX 4 // パルスパターン最大数 // モーター1(RA0~RA3)とモーター2(RA4~RA7)へ設定するパルスパターン // 下位4ビットがモーターへの出力、上位4ビットは意味なし unsigned char pulsepattern_m1m2[PATMAX] = { 0b00001100, 0b00000110, 0b00000011, 0b00001001 }; // モーター3(RC0~RC2)へ設定するパルスパターン その1 // 下位3ビットがモーターへの出力、上位5ビットは意味なし // 続いて(RC5)へpulsepattern_m3_2を設定すること unsigned char pulsepattern_m3_1[PATMAX] = { 0b00000100, 0b00000110, 0b00000011, 0b00000001 }; // モーター3(RC5)へ設定するパルスパターン その2 // 下位1ビットがモーターへの出力、上位7ビットは意味なし // pulsepattern_m3_11に引き続いて設定する unsigned char pulsepattern_m3_2[PATMAX] = { 0b00000001, 0b00000000, 0b00000000, 0b00000001 }; // モーター4(RC6,RC7)へ設定するパルスパターン その1 // 下位2ビットがモーターへの出力、上位6ビットは意味なし // 続いて((RE1,RE0)へpulsepattern_m4_2を設定すること unsigned char pulsepattern_m4_1[PATMAX] = { 0b00000000, 0b00000010, 0b00000011, 0b00000001 }; // モーター4(RE1,RE0)へ設定するパルスパターン その2 // 下位2ビットがモーターへの出力、上位6ビットは意味なし // pulsepattern_m4_2に引き続いて設定する unsigned char pulsepattern_m4_2[PATMAX] = { 0b00000011, 0b00000001, 0b00000000, 0b00000010 }; //*********************************************** // 軸面から見ての回転方向 //*********************************************** #define LEFTROTATION 0 // 軸面から見て左回り #define RIGHTROTATION 1 // 軸面から見て右回り //*********************************************** // 最大回転回数 // この回転数以上モーターを回転させても定位/反位の検出スイッチが動作しなければ // スイッチ異常としてそれ以上回転させない //*********************************************** #define MAXROTATIONS 5 // 最大回転回数 #define STEPANGLE_PG271601 3 // モーター1ステップ当りの角度(PG27-1601の場合) #define STEPANGLE_SPG201362 1 // モーター1ステップ当りの角度(SPG20-1362の場合) #define MAXPAT_PG271601 (MAXROTATIONS * (360 / STEPANGLE_PG271601)) // 最大回転回数までのパターン出力回数 #define MAXPAT_SPG201362 (MAXROTATIONS * (360 / STEPANGLE_SPG201362)) // 最大回転回数までのパターン出力回数 //*********************************************** // 関数定義 //*********************************************** //モーターを回転させる void rotate(unsigned char,unsigned char); // パルス送出時の待ち void delay_pulseout(unsigned char); // メイン void main(int, char**); /* * メイン */ void main(int argc, char** argv) { OSCCONbits.IRCF =0b111; // IRCF<2:0>=111 内臓クロックは8MHz CM1CON0bits.C1ON =CM2CON0bits.C2ON = 0;// コンパレータオフ ANSEL = ANSELH = 0x00; // ポートI/Oはすべてデジタル TRISA = 0x00; //RAポート 全て出力 (0:出力 1:入力) TRISB = 0xff; //RBポート 全て入力 (0:出力 1:入力) OPTION_REGbits.nRBPU = 0; //PORTB pull-up 0:enable 1:disabled WPUB = 0xff; //1:pull-up有効 TRISC = 0b00011000; //RCポート I2C(RC3,RC4)入力、以外全て出力 TRISD = 0xff; //RDポート 全て入力 (0:出力 1:入力) TRISE = 0x00; //REポート 全て出力 (0:出力 1:入力) // モーター1,モーター2用初期化 pulseportRA_M1M2 = (union pulseportbit_RA_M1M2 *)&PORTA; PORTA = 0; // モーター3用初期化 pulseportRC_M3P1 = (union pulseportbit_RC_M3P1 *)&PORTC; pulseportRC_M3P2 = (union pulseportbit_RC_M3P2 *)&PORTC; pulseportRC_M3P1->pulseM3P1 = 0; pulseportRC_M3P2->pulseM3P2 = 0; // モーター4用初期化 pulseportRC_M4P1 = (union pulseportbit_RC_M4P1 *)&PORTC; pulseportRE_M4P2 = (union pulseportbit_RE_M4P2 *)&PORTE; pulseportRC_M4P1->pulseM4P1 = 0; pulseportRE_M4P2->pulseM4P2 = 0; //動作確認LED RE2 = 1; // 点灯 // 動作確認 while(1){ RE2 = 1; // 動作確認LED点灯 rotate(0, LEFTROTATION); //モーター1 左回転 RE2 = 0; // 動作確認LED消灯 rotate(0, RIGHTROTATION); //モーター1 右回転 RE2 = 1; // 動作確認LED点灯 rotate(1, LEFTROTATION); //モーター2 左回転 RE2 = 0; // 動作確認LED消灯 rotate(1, RIGHTROTATION); //モーター2 右回転 RE2 = 1; // 動作確認LED点灯 rotate(2, LEFTROTATION); //モーター3 左回転 RE2 = 0; // 動作確認LED消灯 rotate(2, RIGHTROTATION); //モーター3 右回転 RE2 = 1; // 動作確認LED点灯 rotate(3, LEFTROTATION); //モーター4 左回転 RE2 = 0; // 動作確認LED消灯 rotate(3, RIGHTROTATION); //モーター4 右回転 } } /* * モーターを回転させる * * unsigned char motornumber 使用モーター等の配列参照用添字 0~4 * unsigned char direction 回転方向 0:軸面から見て左回り * 1:軸面から見て右回り * */ void rotate(unsigned char motornumber,unsigned char direction){ int numberofoutputs; // パルスパターン出力回数 int i,j; // パターン出力回数の設定 // (モーターによって基本ステップ角度が異なるため) switch(motortype[motornumber]){ case PG271601: // PG27-1601 numberofoutputs = MAXPAT_PG271601; break; case SPG201362: // SPG20-1362 numberofoutputs = MAXPAT_SPG201362; break; // 使用するモーターが増えたらここに追加 } // パルスパターン出力 for(i = j = 0; j < numberofoutputs; j++){ switch(motornumber){ case 0: // モーター1 pulseportRA_M1M2->pulseM1 = pulsepattern_m1m2[i]; break; case 1: // モーター2 pulseportRA_M1M2->pulseM2 = pulsepattern_m1m2[i]; break; case 2: // モーター3 pulseportRC_M3P1->pulseM3P1 = pulsepattern_m3_1[i]; pulseportRC_M3P2->pulseM3P2 = pulsepattern_m3_2[i]; break; case 3: // モーター4 pulseportRC_M4P1->pulseM4P1 = pulsepattern_m4_1[i]; pulseportRE_M4P2->pulseM4P2 = pulsepattern_m4_2[i]; break; } if(LEFTROTATION == direction) //左回り->パルスパターンテーブルを昇順に出力 i = (++i == PATMAX) ? 0 : i; else //右回り->パルスパターンテーブルを降順に出力 i = (--i < 0) ? PATMAX - 1 : i; // パルス送出待ち delay_pulseout(motortype[motornumber]); } // ポートの出力を0にして電流が流れ続けるのを防止 switch(motornumber){ case 0: // モーター1 pulseportRA_M1M2->pulseM1 = 0; break; case 1: // モーター2 pulseportRA_M1M2->pulseM2 = 0; break; case 2: // モーター3 pulseportRC_M3P1->pulseM3P1 = 0; pulseportRC_M3P2->pulseM3P2 = 0; break; case 3: // モーター4 pulseportRC_M4P1->pulseM4P1 = 0; pulseportRE_M4P2->pulseM4P2 = 0; break; } } /* * パルス送出時の待ち * unsigned char motortype 0:PG27-1601 1:SPG20-1362 * * __delay_usのパラメータには変数の使用ができない */ void delay_pulseout(unsigned char motortype){ switch(motortype){ case PG271601: // PG27-1601 __delay_us(7000); break; case SPG201362: // SPG20-1362 __delay_us(3000); break; // 使用するモーターが増えたらここに追加 } return; }
次のフェーズでは位置検出のスイッチを組み込んで、ポインタが切り替わった時点で停止するようにプログラムを改修していく予定。
・・が、レイアウト製作までに月日が流れすぎた
2022年12月
サーボモーターの価格は下がってしまった。
機構が複雑になるが、安価にできると思って作ってきたステッピングモーターを使ったポイントマシンは・・却下。
紆余曲折の経緯は置いておくとすると・・
結論としては・・レイアウトにはサーボモーター版を取り付けることにした。(^^;
↓ これです。