■PIC16F877AとL6470によるスッテッピングモータ制御のサンプルコード
com_def.h :共通定義文
uart.h :シリアル通信(RS-232C)定義文
uart.c :シリアル通信(RS-232C)関数
877A_serv.c :メインタスク処理
■com_def.h ************************************************************
// 定義文
#define ON 1 // ON 定義
#define OFF 0 // OFF定義
#define I_8 signed char // 8bit -128~127
#define U_8 unsigned char // 8bit 0~255
#define I16 signed int // 16bit -32,768 ~ +32,767
#define U16 unsigned int // 16bit 0 ~ 65,535
#define I32 signed long // 32bit -2,147,483,648 ~+2,147,483,647
#define U32 unsigned long // 32bit 0 ~ 4,294,967,295
#define F32 double // 32bit メモリを消費量が激しいので通常は使用しない
#define CR 0x0D // ASCII 制御コード
#define LF 0x0A // ASCII 制御コード
■uart.h ************************************************************
#ifndef __UART_H__
#define __UART_H__
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 // 4MHz ★ 4000000:正常動作確認(システムクロックを記述:今回は外部4MHz発振子使用)
#endif
#define BAUDRATE 14400 // 14400 bps ★ 14400bps:正常動作確認
#define TX9_RX9_BIT 0 // 0: 8bit, 1: 9bit ★ 0:正常動作確認
#define BRGH_BIT 1 // 0/1:(低速/高速)サンプル指定 ★ 1:正常動作確認
// 9-bit Transmit Enable bit -> 0:8-bit Transmission 1:9-bit Transmission
#if TX9_RX9_BIT == 1
#define TX9_RX9_DATA 0x40
#else
#define TX9_RX9_DATA 0x00
#endif
// High Baud Rate Select bit -> 0:Low speed 1:High speed
// PIC16F877A.pdfの115page TABLE 10-1の式により、ボーレートからSPBRG値を逆算
#if BRGH_BIT == 1
#define BRGH_DATA 0x04
#define SPBRG_DATA *1 // BRGH=1(High Speed)時のSPBRG値
#else
#define BRGH_DATA 0x00
#define SPBRG_DATA *2 // BRGH=0(Low Speed)時のSPBRG値
#endif
// プロトタイプ宣言
void initUART();
void putch(unsigned char byte);
unsigned char getch();
unsigned char getche();
#endif // __UART_H__
■uart.c ************************************************************
#include <pic.h>
#include <stdio.h>
#include "uart.h"
void initUART( void )
{
PIE1bits.RCIE = 1 ; // USART割込み受信を有効
PIR1bits.RCIF = 0 ; // USART割込み受信フラグの初期化
TXSTA = (TX9_RX9_DATA | BRGH_DATA | 0x20); // TX9_RX9_DATA,BRGH_DATAはuart.hで定義、0x020:Transmit enabled
RCSTA = (TX9_RX9_DATA | 0x90); // TX9_RX9_DATAはuart.hで定義、0x90(SPEN->Serial port enabled, CREN->Enables continuous receive
SPBRG = SPBRG_DATA; // PIC16F88ではTXSTA,RCSTAの前で処理すると正常動作しない(PIC16F877Aでは現在評価中)
}
void putch(unsigned char byte)
{
while(!PIR1bits.TXIF){}
TXREG = byte;
}
unsigned char getch( void )
{
while(!PIR1bits.RCIF){}
return RCREG;
}
unsigned char getche( void )
{
unsigned char c;
c = getch();
putch(c);
return c;
}
■877A_serv.c ************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include "com_def.h"
#include "uart.h"
// タスク制御用パラメータ
// ■割り込み処理用のカウンタ初期値設定
// 割り込み周期 = (0xffff - TMR1)*1 [μsec]
// |64536->65536
// TMR1入力クロック | 4MHz
// 割り込み | 1msec
// 初期値(カウンタ値)|64536(1000)
// 16進表示 | 0xfc18
#define P_TIMER_H 0xfc // | 0xfc
#define P_TIMER_L 0x2a // | 0x18
// カウンタ初期値補正値
// ・default:4MHz:0xfc18 10MHz:0xf63c
// ・4MHz水晶発振子での計測による補正値:0xfc2a
// ・内部クロック での計測による補正値:0xfc23
#define D_TIMER 0xfc2a // PIC16F877Aでは2byte処理が可能なので2bytにまとめる。
#define D_INT_TSK 10 // タスク周期 = 割り込み周期*D_INT_TSK (0~255)
// 受信処理関連定義文
#define D_REC_RBUFSIZE 10 // 受信リングバッファサイズ
#define D_REC_CMDSIZE 9 // 受信命令判定サイズ
#define D_PRT_SIZE 16 //
#define P_CHECK 10 // 10msec×P_CHECK毎にLEDが点滅(max 65536まで:U16変数のため)
// ビットフィールド変数宣言
struct {
U16 task_exec_flg : 1; // 00:タスク演算終了確認フラグ(ON/OFF→未/済)
U16 rec_flg : 1; // 01:シリアル受信フラグ
U16 LED : 1; // 02:LED点灯指令
U16 flick_flg : 1; // 04:
} bit1;
// 変数宣言
I_8 recRing[D_REC_RBUFSIZE]; // 受信リングバッファ
I_8 recRingCtr; // 受信リングバッファカウンタ
I_8 rec_cmd[D_REC_CMDSIZE]; // 受信セット
U16 alt500m_ctr; // 500msec周期処理用カウンタ
I16 Count ; // タイマーの割込み発生回数をカウントする変数
// 関数のプロトタイプ宣言
void recv_fun( void );
void interrupt InterTimer( void );
void init_fun( void );
void input__fun( void );
void output_fun( void );
void task___fun( void );
U_8 SPIMsCom( U_8 );
void SPIwrite_3byteCmd(U_8, U32);
void SPIwrite_2byteCmd(U_8, U16);
void SPIwrite_1byteCmd(U_8, U_8);
U32 SPIread_3byteCmd(U_8, U32);
U16 SPIread_2byteCmd(U_8, U16);
U_8 SPIread_1byteCmd(U_8, U_8);
// CONFIGURATION WORD definitions (PIC16F887A)
#pragma config CP = 0x1 // Code protection off
#pragma config DEBUG = 0x1 // In-Circuit Debugger disabled, RB6 and RB7 are general purpose I/O pins
#pragma config WRT = 0x2 // 0000h to 00FFh write-protected
#pragma config CPD = 0x1 // Data EEPROM code protection off
#pragma config LVP = 0x0 // RB3 is digital I/O
#pragma config BOREN = 0x1 // Brown-out Reset enabled (1:enabled / 0:disabled )
#pragma config PWRTE = 0x0 // Power-up Timer enabled (0:enabled / 1:disabled )
#pragma config WDTE = 0x0 // Watchdog Timer disabled (1:enabled / 0:disabled )
#pragma config FOSC = HS // oscillator ( 4MHz~ 20MHz)
// InterTimer() 割込みの処理
void interrupt InterTimer( void )
{
I_8 i,s;
// タイマー割り込み発生時の処理
if(PIR1bits.TMR1IF == 1) // タイマー1の割込み発生か?
{
PIR1bits.TMR1IF = 0; // タイマー1割込フラグをリセット
TMR1 = D_TIMER; // タイマ1初期化(本値~65536までカウントアップ
Count++ ; // 割込み発生回数をカウント
if( Count >= D_INT_TSK ) // 割込みをD_INT_TSK回毎にタスク実行フラグをON
{
bit1.task_exec_flg = ON; // タスク演算終了確認フラグをON(未実行状態へ)
Count = 0 ;
}
}
// 受信割り込み発生時の処理
if (PIR1bits.RCIF == 1) // 割込みはUSART通信の受信か?
{
if( RCREG == CR ) // コマンド指令の末尾にCR受信時のみ受信処理を実施
{
// 受信リングバッファを受信セットに代入
for(i=0;i<D_REC_CMDSIZE;i++)
{
// recRingCtr = 0の場合
s = ( recRingCtr - 1) - i;
if( s < 0 ){ s += D_REC_RBUFSIZE; }
rec_cmd[i] = recRing[s];
}
bit1.rec_flg = ON; // 受信フラグをセット(受信処理を実行)
}
else
{
// 受信データをリングバッファに格納
recRing[recRingCtr] = RCREG;
recRingCtr ++;
if( recRingCtr >= D_REC_RBUFSIZE ){ recRingCtr = 0; }
}
PIR1bits.RCIF = 0 ; // 割込み受信フラグをリセット
}
}
// 初期化処理
void init_fun( void )
{
int i;
U16 tempU16;
U_8 tempU_8;
PORTA = 0x00; PORTB = 0x00; PORTC = 0x00; PORTD = 0x00;
CMCON = 0x07 ; // コンパレータは使用しない(内容確認)
TRISA = 0b00111000; // RA5~RA0の入出力設定 0:出力 1:入力 (RA0とRA1は出力のため0)
TRISB = 0b11111111; // RB7~RB0の入出力設定 0:出力 1:入力
TRISD = 0b11111000; // RD7~RD0の入出力設定 0:出力 1:入力 (RD0とRD1はSPIのCSとしてDOとして使用)
ADCON1 = 0b00000110; // AN0~AN7をデジタル入力に設定(PCFG1と2を1)
T1CON = 0b00000001; // 内部クロックでTIMER1をカウントする、プリスケーラー 1:1
TMR1 = D_TIMER; // タイマ1初期化(本値~65536までカウントアップ
PIR1 = 0b00000000; // PSPIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF
PIE1 = 0b00000001; // PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE
INTCON = 0b11000000; // GIE PEIE TMR0IE INTE RBIE TMR0IF INTF RBIF
SSPCON = 0b00110010; // 【SPI設定】WCOL SSPOV SSPEN CKP SSPM3 SSPM2 SSPM1 SSPM0
initUART(); // 調歩同期式シリアル通信設定
__delay_ms(200);
printf("\r\n");
printf(" Init L6470 Parameter\r\n");
SPIwrite_2byteCmd(0x05, 20); // ACC [0- 4096]:加速度係数
SPIwrite_2byteCmd(0x06, 20); // DEC [0- 4096]:減速度係数
SPIwrite_2byteCmd(0x07, 165); // MAX_SPEED [0- 1024]:
SPIwrite_2byteCmd(0x08, 0); // MIN_SPEED [0- 8196]:
SPIwrite_2byteCmd(0x0D, 10000); // INT_SPEED [0-16384]:
SPIwrite_2byteCmd(0x18,0x2E80); // CONFIG [ 0x0000]:
SPIwrite_1byteCmd(0x09, 60); // KVAL_HOLD [0- 256]:モータ停止時の電圧設定
SPIwrite_1byteCmd(0x0A, 160); // KVAL_RUN [0- 256]:モータ定速時の電圧設定
SPIwrite_1byteCmd(0x0B, 160); // KVAL_ACC [0- 256]:モータ加速時の電圧設定
SPIwrite_1byteCmd(0x0C, 160); // KVAL_DEC [0- 256]:モータ減速時の電圧設定
SPIwrite_1byteCmd(0x0E, 250); // ST_SLP [0- 256]:
SPIwrite_1byteCmd(0x0F, 250); // FN_SLP_ACC [0- 256]:
SPIwrite_1byteCmd(0x10, 40); // FN_SLP_DEC [0- 256]:
SPIwrite_1byteCmd(0x11, 0); // K_THERM [0- 16]:
SPIwrite_1byteCmd(0x13, 15); // OCD_TH [0- 16]:過電流の電流スレショルド
SPIwrite_1byteCmd(0x14, 110); // STALL_TH [0- 128]:ストールの電流スレショルド
SPIwrite_1byteCmd(0x16, 0x77); // STEP_MODE [ 0x00 ]:励磁モードの設定( 00:Full-step 0x77:1/128microstep
SPIwrite_1byteCmd(0x17, 0x00); // ALARM_EN [ 0x00 ]:
}
// シリアル受信処理
void recv_fun( void )
{
U_8 dummy;
if( rec_cmd[2] == 'r' && rec_cmd[1] == 'u' && rec_cmd[0] == 'n' )
{
SPIwrite_3byteCmd(0x51, 1000); // run命令受信時の処理
}
if( rec_cmd[3] == 's' && rec_cmd[2] == 't' && rec_cmd[1] == 'o' && rec_cmd[0] == 'p' )
{
dummy = SPIMsCom(0xB0); // stop命令受信時の処理
}
}
// 【SPI通信】 1バイト書込み&読込み
U_8 SPIMsCom(U_8 txdat)
{
U_8 rxdat;
PORTD = 0x00 ; // CS Low
__delay_us(10) ; // 時間待ち
SSPBUF = txdat; // マスタ送信データ設定, 送受信開始
while(!SSPSTATbits.BF){}; // SSPIFセット(通信完了)待ち
rxdat = SSPBUF; // マスタ受信データ取り出し
PORTD = 0x03; // CS High
return( rxdat );
}
// 【SPI通信】 3~1バイトデータの書込み
void SPIwrite_3byteCmd(U_8 cmd, U32 data)
{
U_8 dummy;
dummy = SPIMsCom(cmd); // コマンド送信
dummy = SPIMsCom((data>>16)&0xFF); // データ送信(17-24bit)
dummy = SPIMsCom((data>> 8)&0xFF); // データ送信( 8-16bit)
dummy = SPIMsCom((data )&0xFF); // データ送信( 0- 7bit)
}
void SPIwrite_2byteCmd(U_8 cmd, U16 data)
{
U_8 dummy;
dummy = SPIMsCom(cmd); // コマンド送信
dummy = SPIMsCom((data>> 8)&0xFF); // データ送信( 8-16bit)
dummy = SPIMsCom((data )&0xFF); // データ送信( 0- 7bit)
}
void SPIwrite_1byteCmd(U_8 cmd, U_8 data)
{
U_8 dummy;
dummy = SPIMsCom(cmd); // コマンド送信
dummy = SPIMsCom(data); // データ送信( 0- 7bit)
}
// 【SPI通信】 3~1バイトデータの読込み
U32 SPIread_3byteCmd(U_8 adr, U32 mskbit)
{
U_8 dummy,data[3];
U32 ret_data;
data[2] = SPIMsCom(0); // データ受信(17-24bit) (ダミーデータ送信)
data[1] = SPIMsCom(0); // データ受信( 8-16bit) (ダミーデータ送信)
data[0] = SPIMsCom(0); // データ受信( 0- 7bit) (ダミーデータ送信)
ret_data = (((U32)data[2] << 16)&0x00FF0000) | (((U32)data[1] << 8)&0x0000FF00) | (((U32)data[0])&0x000000FF);
return(ret_data&mskbit);
}
U16 SPIread_2byteCmd(U_8 adr, U16 mskbit)
{
U_8 dummy,data[2];
U16 ret_data;
data[1] = SPIMsCom(0); // データ受信( 8-16bit) (ダミーデータ送信)
data[0] = SPIMsCom(0); // データ受信( 0- 7bit) (ダミーデータ送信)
ret_data = (((U16)data[1] << 8)&0xFF00) | (((U16)data[0])&0x00FF);
return(ret_data&mskbit);
}
U_8 SPIread_1byteCmd(U_8 adr, U_8 mskbit)
{
U_8 dummy;
U_8 ret_data;
ret_data= SPIMsCom(0); // データ受信( 0- 7bit) (ダミーデータ送信)
return(ret_data&mskbit);
}
// 入力処理
void input__fun( void )
{
}
// タスク処理
void task___fun( void )
{
I16 i,d;
U32 tempU32;
// 500msec周期処理(LED点滅や動作確認用)
if(alt500m_ctr >= P_CHECK ) // 10msecタスクをP_CHECKで500msec周期
{
if( bit1.flick_flg == OFF ){ bit1.LED = ON ; bit1.flick_flg = ON ; }
else { bit1.LED = OFF; bit1.flick_flg = OFF; }
alt500m_ctr = 0;
// L6470の状態出力
tempU32 = SPIread_3byteCmd(0x24, 0x000FFFFF);
printf("SPEED:%lu , ",tempU32);
tempU32 = SPIread_3byteCmd(0x21, 0x000FFFFF);
printf("ABS_POS:%lu\r\n",tempU32);
}
alt500m_ctr ++;
// 受信処理(送信命令の場合は送信を実行)
if( bit1.rec_flg == ON )
{
recv_fun(); // 受信処理
bit1.rec_flg = OFF; // 受信フラグをセット
}
}
// 出力処理
void output_fun( void )
{
RA0 = bit1.LED;
}
// メインの処理
void main()
{
init_fun(); // 初期化処理
while(1)
{
if( bit1.task_exec_flg == ON )
{
input__fun(); // 入力処理
task___fun(); // 演算処理
output_fun(); // 出力処理
bit1.task_exec_flg = OFF; // タスク演算終了確認フラグをOFF(実行済状態へ)
}
}
}