TOP>MPLAB XC8編(PIC16F887)> ステッピングモータの制御(PIC16F887 XC8)> ソース
ステッピングモータの制御(ソース)
(PIC16F887 XC8)
| 更新日2012.5.20 |
| 作成日2009.5.6 |
以下のソースを取り込んで、コンパイル→PIC書き込み→実行して下さい。
// ========================== ここから ==============================
// ファイル名 motor_RL.c
// 作成日 2009.3.22
// 更新日 2012.5.12
// 作成者 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
//XC8 __CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & BORDIS & IESODIS & LVPDIS);
__CONFIG(FOSC_INTRC_NOCLKOUT & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & IESO_OFF & LVP_OFF);
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;
//XC8 OPTION = 0x88; // TMR0プリスケーラ:なし
OPTION_REG = 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;
}
// ========================== ここまで ==============================