TOPPICC Lite編(PIC16F887)> ステッピングモータの制御(PIC16F887 PICC-Lite)> ソース

ステッピングモータの制御(ソース)
(PIC16F887 PICC-Lite)

更新日2009.5.6

以下のソースを取り込んで、コンパイル→PIC書き込み→実行して下さい。

// ========================== ここから ==============================
// ファイル名	motor_RL.c
// 作成日	2009.3.22
// 作成者	mit.ueno
// 機種		PIC16F887
// CLOCK	8MHz(INTIO)
// 概要
//	ステッピングモータの左右動作
//I/Oポート
//	RA0:LED
//	RB1:右検出スイッチ
//	RB2:左検出スイッチ
// stepping motor
//	RC0:ステッピングモータ(X)
//	RC1:ステッピングモータ(Y)
//	RC2:ステッピングモータ(^X)
//	RC3:ステッピングモータ(^Y)
// LCD
//	RD2:LCD_RS
//	RD3:LCD_E
//	RD4:LCD_DB4
//	RD5:LCD_DB5
//	RD6:LCD_DB6
//	RD7:LCD_DB7
//
//	LCD_R/W  : GND
//	LCD_V0   : 5KΩVRでGND
//	LCD_DB0-3: open
//
//TMR0
//	プリスケーラ	1
//	TMR0	256(フリーラン)
//	割込み周期	(1/8MHz)*4*1*256=128uS
//

#include "pic.h"

#define LCD_E  RD3
#define	LCD_RS RD2


__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & BORDIS & IESODIS & LVPDIS);


struct i_x {
	unsigned char wk[2];
};

static void pic_init();
static void motor_init();
static void RB1_on();
static void RB2_on();
static void motor1_auto();
static void itox_LCD(struct i_x *);
static void LCD_send4(unsigned char);
static void LCD_cmd(unsigned char);
static void LCD_data(unsigned char);
static void LCD_init();
static void wait_50us();
static void wait_1ms();
static void wait_ms(unsigned char);

unsigned char motor1_period;	// パルス周期
unsigned char motor1_period_i;	// パルス周期初期値
unsigned char motor1_pattern;	// XY^X^Y パルス出力パターン
unsigned char motor1_round;		// 回転方向
		// 回転方向 0:stop , 1:right , 2:stop , 3:left
unsigned int  motor1_pos;		// モータ位置
unsigned int  motor1_posmax;	// モータ位置右の最大値
unsigned char motor1_add;		// モータ位置加算値

bit  sw_RB1;
bit  sw_RB2;
bit  RB1_chg;
bit  RB2_chg;

unsigned int  Cnt_T0_500mS;
bit           Flg_T0_500mS;

const  char hex_tbl[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

// =================== 割り込み処理 ====================
static void interrupt intr(void) {
	if (T0IF) {	// TMR0割込み
		T0IF = 0;	// TMR0割り込みクリア
		Cnt_T0_500mS--;
		if (Cnt_T0_500mS == 0) {
			Cnt_T0_500mS = 3906;
			Flg_T0_500mS = 1;
		}

		// ステッピングモータの制御
		motor1_period--;
		if (motor1_period == 0) {
			motor1_period = motor1_period_i;
			switch (motor1_round) {
				case 0:	{	// 停止
					motor1_pattern = 0;
					break;
				}
				case 1:	{	// 右回転
					motor1_pattern <<= 1;
					if (motor1_pattern == 0x18) {	// 2相制御
						motor1_pattern = 0x09;
					} else if (motor1_pattern == 0x12) {
						motor1_pattern = 0x03;
					}
					motor1_pos += motor1_add;
					break;
				}
				case 2:	{	// 停止
					motor1_pattern = 0;
					break;
				}
				case 3:	{	// 左回転
					motor1_pattern >>= 1;
					if (motor1_pattern == 0x01) {	// 2相制御
						motor1_pattern = 0x09;
					} else if (motor1_pattern == 0x04) {
						motor1_pattern = 0x0C;
					}
					motor1_pos -= motor1_add;
					break;
				}
			}
			PORTC = (PORTC & 0xF0) | motor1_pattern;
		}
	} else
	if (RBIF) {	// ピン変化割込み
		if (!RB1) {		// RB1 on
			RB1_chg = 1;
		} else
		if (!RB2) {		// RB2 on
			RB2_chg = 1;
		}
		RBIF = 0;	// PORTBピン変化割り込みクリア
	}
}


// ================ メイン処理 =======================
main()	{
	pic_init();			// PICの初期化
	LCD_init();			// LCDの初期化

	LCD_cmd(0x80);		// 1行1桁
	wait_ms(2);
	LCD_data('0');		// DEBUG

	motor_init();		// モータ制御情報などの初期化

	while(1) {
		// スイッチON?
		if (RB1_chg) {	// RB1
			wait_ms(10);	// チャタリングキャンセル待ち
			RB1_chg = 0;
			RB1_on();
		}
		if (RB2_chg) {	// RB2
			wait_ms(10);	// チャタリングキャンセル待ち
			RB2_chg = 0;
			RB2_on();
		}

		LCD_cmd(0xC3);			// 2行4桁
		itox_LCD(&motor1_pos);	// motor1_posを16進でLCDに表示

		// motor1自動モード
		if (motor1_posmax) {
			motor1_auto();
		}

		// スイッチ状態リセット
		if (RB1) {
			sw_RB1 = 0;
		}
		if (RB2) {
			sw_RB2 = 0;
		}

		// LED点滅
		if (Flg_T0_500mS) {
			Flg_T0_500mS = 0;
			PORTA ^= 0x01;
		}
	}
}

// ===== int型を4桁の16進数でLCDに表示 =========
static void itox_LCD(struct i_x *ix_wk) {
	unsigned char c1;
	unsigned char wk1,wk2,wk3;

	wk2 = ix_wk->wk[1];
	wk3 = ix_wk->wk[0];

	wk1 = wk2 & 0xF0;
	wk1 >>=4;
	c1 = hex_tbl[wk1];
	LCD_data(c1);
	wk1 = wk2 & 0x0F;
	c1 = hex_tbl[wk1];
	LCD_data(c1);
	wk1 = wk3 & 0xF0;
	wk1 >>=4;
	c1 = hex_tbl[wk1];
	LCD_data(c1);
	wk1 = wk3 & 0x0F;
	c1 = hex_tbl[wk1];
	LCD_data(c1);
}

// =============== RB1スイッチON ===================
static void RB1_on() {
	if (!RB1) {
		if (!sw_RB1) {	// swは今までoff?
			sw_RB1 = 1;

			// 右回転
			motor1_round = 1;
			motor1_pattern = 3;
			motor1_pos = 0;
			motor1_period_i = 188;
			motor1_period   = 188;

			LCD_cmd(0x80);		// 1行1桁
			LCD_data('1');
		}
	}
}

// =============== RB2スイッチON ===================
static void RB2_on() {
	if (!RB2) {
		if (!sw_RB2) {	// swは今までoff?
			sw_RB2 = 1;

			// 左回転
			motor1_round = 3;
			motor1_pattern = 3;
			motor1_period_i = 47;
			motor1_period   = 47;

			motor1_posmax = motor1_pos;

			LCD_cmd(0x80);			// 1行1桁
			LCD_data('2');
			LCD_cmd(0x83);			// 1行4桁
			itox_LCD(&motor1_pos);	// motor1_posを16進でLCDに表示
		}
	}
}

// =============== motor1自動運転 ====================
static void motor1_auto() {
	if (motor1_pos == 0) {
		// 右回転
		motor1_round = 1;
	} else
	if (motor1_pos == motor1_posmax) {
		// 左回転
		motor1_round = 3;
	}
}

// ========== モータ制御などの初期化 =================
static void motor_init() {
	Cnt_T0_500mS = 3906;
	Flg_T0_500mS = 0;
	motor1_pattern = 0x03;	// 2相
	motor1_round = 0;		// 停止
	motor1_pattern = 0;
	motor1_posmax = 0;
	motor1_add = 1;
	sw_RB1 = 0;
	sw_RB2 = 0;
}

// =============== PICの初期化 =======================
static void pic_init() {
	OSCCON = 0x71;		// INTOSC 8MHz
	ANSEL  = 0x00;		// AN未使用
	ANSELH = 0x00;		// AN未使用
	TRISA = 0xFE;		// RA0:out
	TRISC = 0xF0;		// RC0-3:out
	TRISD = 0x03;		// RD2-7:out
	PORTA = 0x00;
	PORTC = 0x00;
	OPTION = 0x88;		// TMR0プリスケーラ:なし
	INTCON = 0xA8;		// GIE:1 ,T0IE:1 ,RBIE:1
	IOCB = 0x06;		// RB1,2 ピン変化割込み
}


// ====================== LCD 送信(4bit) ======================
static void LCD_send4(unsigned char c) {
	PORTD = (PORTD & 0x0F) | c;
	LCD_E = 1;
	NOP();
	LCD_E = 0;

	return;
}

// ==================== LCDコマンドWRITE =================
static void LCD_cmd(unsigned char cmd) {
	LCD_RS = 0;
	PORTD = (PORTD & 0x0F) | (cmd & 0xF0);
	LCD_E = 1;			// 上位4ビット書き込み
	NOP();
	LCD_E = 0;

	PORTD = (PORTD & 0x0F) | ((cmd <<4) & 0xF0);
	LCD_E = 1;			// 下位4ビット書き込み
	NOP();
	LCD_E = 0;

	wait_50us();

	return;
}

// ==================== LCDデータWRITE =================
static void LCD_data(unsigned char cmd) {
	LCD_RS = 1;
	PORTD = (PORTD & 0x0F) | (cmd & 0xF0);
	LCD_E = 1;			// 上位4ビット書き込み
	NOP();
	LCD_E = 0;

	PORTD = (PORTD & 0x0F) | ((cmd <<4) & 0xF0);
	LCD_E = 1;			// 下位4ビット書き込み
	NOP();
	LCD_E = 0;

	wait_50us();

	return;
}

// ==================== LCDの初期化 ===========================
static void LCD_init() {
	wait_ms(15);
	LCD_E = 0;
	LCD_RS = 0;

	LCD_send4(0x30);	// DB4-7に'3'を出力(8bitモードに)@
	wait_ms(5);
	LCD_send4(0x30);	// DB4-7に'3'を出力(8bitモードに)A
	wait_ms(1);
	LCD_send4(0x30);	// DB4-7に'3'を出力(8bitモードに)B
	wait_ms(1);
	LCD_send4(0x20);	// DB4-7に'2'を出力(4bitモードに)
	wait_ms(1);

	// ここからは4bitモードで、Busyフラグが使える
	LCD_cmd(0x28);	// DL=0:4bit ,N=1:2lines ,F=0:5*7dot
	LCD_cmd(0x08);	// Display off
	LCD_cmd(0x0C);	// Display on ,cursor on ,no blink
	LCD_cmd(0x06);	// Entry mode (Inc ,No Shift)
	LCD_cmd(0x01);	// Clear Display
	wait_ms(2);

	return;
}


// ==================== 50μSウェイトルーチン ================
static void wait_50us() {
	unsigned char i;

	for	(i=32 ; i>0 ; i--) {}
	return;
}

// ==================== 1mSウェイトルーチン ================
static void wait_1ms() {
	unsigned char i;

	for	(i=250 ; i>0 ; i--) {
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
	}
	return;
}

// ==================== 1mS×ms ウェイトルーチン ===========
static void wait_ms(unsigned char ms) {
	unsigned char c;
	for (c=ms ; c>0 ; c--) {
		wait_1ms();
	}
	return;
}
// ========================== ここまで ==============================