ステッピングモータ・ドライバを介してステッピングモータを回します.
マイコンとドライバ間の信号は次の通り.
- 回転を示すパルス
- CW/CCW
- ドライバ・レディ
パルスはPWMを使って出力し,パルス数をカウントすることで指定した数のパルスを出力するようにします.
開発環境
e2studioを使いました.コンパイラはGCC for Renesas RXです.
●
プログラム
自動生成されたプロジェクトのうち,主に3つのソースコードファイルを編集します.
メインプログラム
UART0で受信したテキストコマンドをパースし,R
コマンドを受信するとRに続く数字を読み取り,その数のパルスをPWMで生成する(デューティ比は50%固定).
ステッピングモータの回転速度はパルスの周波数で決まる.これはS
コマンドで設定できる.
パルスのカウントはPWMの立下りエッジで割り込みをかけ,割り込みハンドラでカウンタをインクリメントする.
PWMはTGRBとコンペアマッチで信号H
となる.
TGRAとコンペアマッチで信号L
及びカウンタリセットとなる.このタイミングでTGRA割り込みをかける.
main.c
#include <iodefine.h>
#include "timer.h"
#include <stdio.h>
#include <stdlib.h>
省略
//UART0 リングバッファ
unsigned char rx_buff[32]; //受信用
unsigned char tx_buff[32]; //送信用
//UART0 データポインタ
volatile int ptr_rx_top,ptr_rx_bottom;
volatile int ptr_tx_top,ptr_tx_bottom;
volatile int tx_flag = 0; //送信フラグ データ送信中かどうか(0=TX_INACTIVE)
//状態インジケータ用7セグLED
//0:待機状態 1:回転指示受信 2:モータ回転中 3:モータ回転終了 4:モータ回転数指令受信 E:キットカットがありません(エンプティ) U:重大なエラー
int8_t statusLED[10] = {63, 48, 91, 79, 102, 109, 125, 7, 127, 111};
int motorStep; // current number of pulse
int motorStepTarget; // target number of pulse for motor rotation
char pulseDone; //flag of motor rotation was done
unsigned int pwmCyclePercentage; //percentage of motor rotation speed(default 50%, 1 is minimum)
unsigned char message[64];
unsigned char uartRecieve[32];
void initSCI(int bps)
{
MSTP(SCI0) = 0; //Enable SCI0
PORT2.DDR.BIT.B1 = 0; //RxD0 is input
PORT2.ICR.BIT.B1 = 1; //Enable Input Buffer on RxD0
PORT2.DDR.BIT.B0 = 1; //TxD0 is output
SCI0.SCR.BYTE = 0; //Disable Tx/Rx
SCI0.SMR.BYTE = 0x00;
//SCI0.SEMR.BIT.ABCS = 1;
/* 送受信で割込み発生 */
SCI0.SCR.BIT.RIE = 1;
SCI0.SCR.BIT.TIE = 1;
/* 割込み優先度 */
IPR(SCI0,RXI0) = 0x0F;
IPR(SCI0,TXI0) = 0x0F;
/* Clear IR bits for TIE and RIE */
IR(SCI0, RXI0) = 0;
IR(SCI0, TXI0) = 0;
/* 受信・送信割込み許可 */
IEN(SCI0, RXI0) = 1;
IEN(SCI0, TXI0) = 1;
IEN(SCI0, ERI0) = 1;
SCI0.BRR = PCLK *1000000 / 32 / bps - 1; //SCI0.BRR = 38;
SCI0.SCR.BYTE |= 0x30; //Enable TxRx
ptr_rx_top = ptr_rx_bottom = 0; //リングバッファ初期化
ptr_tx_top = ptr_tx_bottom = 0;
}
/* データの送信 */
void charput(unsigned char output_char)
{
int tmp;
tmp = ptr_tx_top + 1;
tmp = tmp % 32;
while(tmp == ptr_tx_bottom) ; //バッファに空きができるまで待つ
tx_buff[ptr_tx_top] = output_char;
ptr_tx_top++;
ptr_tx_top = ptr_tx_top % 32;
if(tx_flag == 0) {
tx_flag = 1;
IEN(SCI0, TXI0) = 1;
SCI0.SCR.BYTE |= 0xA0; //送信割込み発生
}
}
/* データの受信 */
unsigned char charget(void)
{
unsigned char c;
if(ptr_rx_bottom == ptr_rx_top)return 255;
c = rx_buff[ptr_rx_bottom];
ptr_rx_bottom++;
ptr_rx_bottom = ptr_rx_bottom % 32;
return c;
}
/* 文字列の出力 */
void printString(char *s)
{
while( *s != 0 ) {
if(( *s == '\r' ) && ( *(s+1) != '\n')) {
charput('\r');charput('\n');
} else if( (*s == '\n') && ( *(s-1) != '\r') ) {
charput('\r');charput('\n');
} else {
charput(*s);
}
s++;
}
}
void initPWM(){
MTUA.TRWER.BIT.RWE = 1;
MSTP(MTU4) = 0;
MTUA.TSTR.BIT.CST4 = 0;
MTUA.TOER.BIT.OE4A = 1;
IOPORT.PFCMTU.BIT.MTUS4 = 0;
MTU4.TCR.BIT.TPSC = 0x02;
MTU4.TCR.BIT.CKEG = 0x00; //立ち上がりエッジでカウント
MTU4.TCR.BIT.CCLR = 0x01; //TGRBのコンペアマッチでクリア
MTU4.TCNT = 0x0000; //カウンタクリア
MTU4.TIER.BIT.TGIEA = 1; //TGRA割り込み有効
MTU4.TIER.BIT.TGIEB = 1;
MTU4.TIER.BIT.TGIEC = 1;
IEN(MTU4, TGIA4) = 1;
IPR(MTU4, TGIA4) = 6; //割り込みプライオリティの設定必須
MTU4.TMDR.BYTE = 0x02; //0x02;//PWMモード1
MTU4.TIORH.BIT.IOA = 0x01; //BIT.IOA = 0x02;
MTU4.TIORH.BIT.IOB = 0x02;
MTU4.TIORL.BIT.IOC = 0x00;
unsigned int tmpCycle = 0x180 * pwmCyclePercentage;
MTU4.TGRA = tmpCycle;
MTU4.TGRB = tmpCycle >> 1; //duty is 50%
}
void startPWM(int target){
if(PORT5.DR.BIT.B1){ //when emergency button have been pushed
motorStepTarget = 0;
return;
}
PORTC.DR.BYTE = statusLED[2]; //showing motor is rotating
PORT0.DR.BIT.B5 = 0; //Motor Enable
motorStepTarget = target-1;
MTUA.TSTR.BIT.CST4 =1; //PWM pulse is stopped
}
int scanCommand(){
int i = 0;
int tmpPulseCount = 0;
do{
uartRecieve[i++] = charget();
}while(uartRecieve[i-1] != 255);
uartRecieve[--i] = '\0';
printString("\n");
printString(uartRecieve);
printString("\n");
switch(uartRecieve[0]){
case 'R':
PORTC.DR.BYTE = statusLED[1]; // showing recieve command of rotation
tmpPulseCount = atoi(&uartRecieve[1]);
if(tmpPulseCount < 0) {
PORT5.DR.BIT.B0 = 1; //ccw
startPWM(-tmpPulseCount);
}else if(tmpPulseCount > 0){
PORT5.DR.BIT.B0 = 0; //cw
startPWM(tmpPulseCount);
}else{
tmpPulseCount = 0;
return 0;
}
break;
case 'S':
pwmCyclePercentage = atoi(&uartRecieve[1]);
if(pulseDone) return 0; //while motor is ratating
if(pwmCyclePercentage > 0 && pwmCyclePercentage < 101){
PORTC.DR.BYTE = statusLED[4];
pwmCyclePercentage = 100 - pwmCyclePercentage;
unsigned int tmpCycle = 0x180 * pwmCyclePercentage;
MTU4.TGRA = tmpCycle;
MTU4.TGRB = tmpCycle >> 1;
}
break;
default:
return 0;
}
return 0;
}
void initIO(){
PORT5.DDR.BIT.B0 = 1; //CW/CCW select
PORT1.DDR.BIT.B5 = 1; //On Board LED
PORT5.DDR.BIT.B1 = 0; //Emergency SW
PORT0.DDR.BIT.B5 = 1; //Motor Enable/Disable
PORT0.DR.BIT.B5 = 1; //Set Motor Disable
PORTC.DDR.BYTE = 0xFF; //7Segment LED for indicater
PORTC.DR.BYTE = 0;
}
void stopMotor(){
PORTC.DR.BYTE = statusLED[3]; //
MTUA.TSTR.BIT.CST4 = 0;
PORT0.DR.BIT.B5 = 1; //Motor Disable
motorStep = 0;
motorStepTarget = 0;
pulseDone = 0;
delay_ms(200);
PORTC.DR.BYTE = statusLED[0]; //showing mode wait
}
int main(void) {
pwmCyclePercentage = 50;
initIO();
initPWM();
initTimer();
initSCI(9600);
stopMotor();
while(1) {
if(pulseDone){
PORT0.DR.BIT.B5 = 1; //Motor Disable
motorStepTarget = 0;
pulseDone = 0;
printString("ACK\n"); //return ACK Signal to HOST
}
//when emergency button have been pushed
if(PORT5.DR.BIT.B1) stopMotor();
if(ptr_rx_bottom != ptr_rx_top){ //when RX buffer was changed, recognizing text command
delay_ms(2500);
scanCommand();
}
}
return 0;
}
割り込みハンドラ
generate/inthandler.c
#include "interrupt_handlers.h"
#include <iodefine.h>
extern unsigned int utimer;
extern unsigned char rx_buff[32]; //受信用
extern unsigned char tx_buff[32]; //送信用
extern volatile int ptr_rx_top,ptr_rx_bottom; //データポインタ
extern volatile int ptr_tx_top,ptr_tx_bottom;
extern volatile int tx_flag; //送信フラグ データ送信中かどうか(0=TX_INACTIVE)
extern int motorStep;
extern int motorStepTarget;
extern char pulseDone;
extern void printString(char*);
省略
// Timer
//;0x0074 CMTU0_CMT1
void INT_Excep_CMT1_CMI1(void){
utimer++;
}
省略
// PWM Count
//;0x0218 MTU4_TGIA4
void INT_Excep_MTU4_TGIA4(void){
motorStep++;
if(motorStep > motorStepTarget){
MTUA.TSTR.BIT.CST4 =0;
motorStep = 0;
pulseDone = 1;
}
}
省略
//(UART0)
//;0x0358 SCI0_ERI0
void INT_Excep_SCI0_ERI0(void){
SCI0.SSR.BYTE &= ~0x38; //エラーフラグクリア
}
//;0x035C SCI0_RXI0
void INT_Excep_SCI0_RXI0(void){
/* Read data */
PORT1.DR.BIT.B5 ^= 1;
rx_buff[ptr_rx_top] = SCI0.RDR;
ptr_rx_top++;
ptr_rx_top = ptr_rx_top % 32;
}
//;0x0360 SCI0_TXI0
void INT_Excep_SCI0_TXI0(void){
/* Write the character out */
SCI0.TDR = tx_buff[ptr_tx_bottom];
ptr_tx_bottom++;
ptr_tx_bottom = ptr_tx_bottom % 32;
//すべてのデータを送信したら割込み禁止
if( ptr_tx_bottom == ptr_tx_top ) {
IEN(SCI0, TXI0) = 0;
tx_flag = 0;
}
}
省略
// (UART2)
//;0x0378 SCI2_ERI2
void INT_Excep_SCI2_ERI2(void){
SCI2.SSR.BYTE &= ~0x38; //エラーフラグクリア
}
//;0x037C SCI2_RXI2
void INT_Excep_SCI2_RXI2(void){
/* Read data */
PORT1.DR.BIT.B5 ^= 1;
rx_buff[ptr_rx_top] = SCI2.RDR;
ptr_rx_top++;
ptr_rx_top = ptr_rx_top % 32;
}
//;0x0380 SCI2_TXI2
void INT_Excep_SCI2_TXI2(void){
/* Write the character out */
SCI2.TDR = tx_buff[ptr_tx_bottom];
ptr_tx_bottom++;
ptr_tx_bottom = ptr_tx_bottom % 32;
//すべてのデータを送信したら割込み禁止
if( ptr_tx_bottom == ptr_tx_top ) {
IEN(SCI2, TXI2) = 0;
tx_flag = 0;
}
}
generate/hwinit.c
省略
### ハードウェアの設定
システムクロックの設定をします.
UARTの設定に影響するので注意が必要です.
void HardwareSetup(void)
{
SYSTEM.SCKCR.LONG = 0x00C10100; //システムクロックなどの設定
省略