PAGE TOP

ポイントマシン用ステッピングモーターの動作確認

ポイントマシン制御用パーツ取り付け基板

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マイコンを作り込む予定。

LANケーブルとステッピングモーター用ケーブルの比較基板とステッピングモーターの間は0.5/4PのLANケーブルを使って接続する。

細いかな?という感じがしないわけでもないが、元々ステッピングモーターについていた配線もかなり細い物。


写真の上側が0.5のLANケーブルの心線、下側がステッピングモーターについていたケーブル。
どっこいどっこいかと思っていたが、実は0.5のLANケーブルの方が太そう。

ポイント転換に要する時間も2秒程度ではなかろうかと思われるし、ポイントなんかそんなにしょっちゅう転換することはない。
0.5のLANケーブルで大丈夫だと思う。
・・最近はやりの細いケーブルは無理・・かな。

 

動作確認用プログラム

基本的にはI2Cのマスターからのどのポイントを定位にするか反位にするかのコマンドを受信して動作させることになるが、I2Cのマスターが接続されていないときには押し釦スイッチでも転換できる仕様とする予定。

手元に用意してあるステッピングモーターはPG27-1601、SPG20-1362の2種類。

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;
}



 

次のフェーズでは位置検出のスイッチを組み込んで、ポインタが切り替わった時点で停止するようにプログラムを改修していく予定。



趣味の部屋 スマホ/タブレットサイト 趣味の部屋 PCサイト