マイコン R8c/32cで紙飛行機のカタパルトを制御


 有馬富士公園のキッピーフレンズ結成10周年の記念イベントの紙飛行機を作るコーナーを担当することになりました。
 イベント名は 「定規を使って紙飛行機を作ろう」で、折り紙とクリップと定規で紙飛行機を来館者に作ってもらった後飛ばしてもらいます。
 手で飛ばすだけでは味気ないので、飛ばす道具を作っています。飛ばす道具の名前は、カタパルトが好いでしょうか。
 カタパルトは、ゴム式と、モーター式を考えています。このページでは、モータ式のカタパルトを記録します。
 

●モータ式のカタパルトの概要

 上はモータ式のカタパルトの全景、下は制御部です。
 紙飛行機は、回転する2つの車輪に引っ張られて下から上に放り上げられます。右の車輪は時計回り、左の車輪は反時計回りです。
 2つのモータは同じ電圧をかけると、同じ回転数になるものと信じています。マブチ様宜しくお願いします。
 モータは、マブチモータを使いました。ネットで送料込みで@200円で入手しました。安くなりましたね!

 




 マイコンR8C/32cを使ったモータ式のカタパルトの制御基板です。
 マイコンR8C/32cとモータ駆動用のFETとスイッチだけです。これでマブチモータをPWM駆動します。
 マイコンR8C/32cに発振器、タイマが入っているので極めてシンプルです。






●モータ式のカタパルトの構成

 モータ式のカタパルトの構成です。
 操作用のスイッチとモータ駆動のFETを外付けした以外、制御は、マイコンR8C/32cでほとんど実現出来ました。
 制御マイコンR8C/32cのプログラムで、スイッチのチャタフリー、スイッチ指令に従ってタイマRCにPWM値を設定を行うのですが、そのタイミングはタイマRAが発生する20mSのタイミングです。
 そして、モータを制御する信号は、タイマRCが100uS間隔で2ChのPWM信号を作ります。

 モータを制御を100uS間隔にしたのは、10KHzは人間に聞こえない周波数からです。

 2ChのPWM信号を作るのに、プログラムは設定だけで良いので他の仕事が出来ます。
 




 次の波形は、モータ駆動用FETの入力信号で、上から高速、中速、低速です。
 例えば、高速の波形の上側は57.6uS間モータを駆動しています。下側は、モータ駆動時間は少し長くしています。左右の車輪の回転数を変えて紙飛行機がカーブして飛ばないか試すものです。








●困ったこと

 ルネサス社のアプリケーションノートに載っているプログラムを利用してプログラムを作ってい試したら、何の問題も無くモータは快適に回転しました。高速、中速、低速も問題はありません。
 しかし、高速、中速、低速を何回も繰り返していると、時々異常な高速回転が起こります。 高速、中速、低速の切り替わり時点で発生します。
 シンクロスコープで駆動信号を見ると、駆動パナシです。何だろうか?
 H/Wがノイズで誤動作してるのかと思い、コンデンサを付けたり、電源をロジック用とモータ用に分けたりしましたが治りません。又、プログラムの誤りか見なおしたのですが問題は見当たりません。

 何だろうか?繰り返していると、規則性は無いが起こります。
 ノイズでは無い、プログラムでは無い、と思いつく処を消去していくと。速度切替のタイミングに何か有ると目星をつけて探ります。

 問題点が見つかりました。
 タイマRCにPWM値を再設定する時、タイマRCを停止してPWM値を設定しています。
 タイマRCを停止させたときのPWM駆動信号が駆動になっていると異常な高速回転になります。
 PWM駆動信号が非駆動の時に停止させることで問題は解決しました。


●制御プログラムのリスト

 次は制御プログラムです。



/***********************************************************************/
/* */
/* FILE :PwmMotor.c */
/* DATE :Sun, Jul 01, 2012 */
/* DESCRIPTION :main program file. */
/* CPU GROUP :32C */
/* */
/* This file is generated by Renesas Project Generator (Ver.4.19). */
/* NOTE:THIS IS A TYPICAL EXAMPLE. */
/***********************************************************************/

/* ===== インクルードファイル ===== */
#include "sfr_r832c.h"

/* ===== マクロ定義 ===== */

/* ===== プロトタイプ宣言 ===== */
void main(void);
static void init_clock(void);
static void init_val(void);
static void init_port(void);
static void init_ra(void);
static void init_rc(void);
void ProcessPb(void);

/* ===== グローバル変数宣言 ===== */
unsigned char gInSwitchData;

// **********************************************************************
// ******************** 高速オンチップオシレータ切替 関数。 clk= 20MHz
static void init_clock(void)
{
unsigned int i = 0;

prc0 = 1; /* Protect off */
cm14 = 0; /* Low-speed on-chip oscillator on */

fra2 = 0x00; /* Selects Divide-by-2 mode */
fra00 = 1; /* High-speed on-chip oscillator on */
while(i <= 255) i++; /* This setting is an example of waiting time for the */
/* oscillation stabilization. Please evaluate the time */
/* for oscillation stabilization by a user. */
fra01 = 1; /* Selects High-speed on-chip oscillator */
cm16 = 0; /* No division mode in system clock division */
cm17 = 0;
cm06 = 0; /* CM16 and CM17 enable */
prc0 = 0; /* Protect on */

}

// ******************** 初期化すべき変数があれば、ここに記述。
static void init_val(void)
{
}

// ******************** ポート初期化。
static void init_port(void)
{
p1 = 0x00; //ポートデータを設定
p3 = 0x00; //ポートデータを設定
p4 = 0x00; //ポートデータを設定

pd1 = 0x00; //入力ポートに設定

pd3 = 0x00; //入力ポートに設定
pd3_3 = 1; //出力ポートに設定 LED用

pd4 = 0x00; //入力ポートに設定

pu02 = 1; //p1_0〜3はプルアップ
pu03 = 1; //p1_4〜7はプルアップ

//ポートの初期化を行います。効率は悪いけど一ビットづつ設定するのがわかりやすい。
//サンプルのように記述すればよいです。
/*
pd1_1 = 0; //入力
pu1_4 = 1; //p1_4はプルアップ

pd1_5 = 1; //出力
drr3_7 = 1; //p3_7は駆動能力High (でバック環境ではLEDを駆動していました)

//未使用ポートは出力で0固定
pd1_7 = 1;
*/
}

// ******************** raの設定 20mS 周期のタイミングを作る
static void init_ra(void)
{
tstop_tracr = 1;//強制停止
tstop_tracr = 0;
tstart_tracr = 0;

tramr = 0x10; //タイマRA;動作モード選択:タイマモード, カウントソース選択:f8
traioc = 0x00; //タイマモードなので 0 を設定
// ********** 20MHz / 8 / (250 + 200 ) =50Hz を作成
trapre = 250; /* タイマRAプリスケーラレジスタ */
tra = 200; /* タイマRAレジスタ */

tstart_tracr = 1; /* タイマRAカウント開始ビット(0:停止/1:開始) */
}

// ******************** rcの設定 TRCIOC,TRCIODから10KHzのPWM信号を出力
static void init_rc(void){

trcpsr1 = 0x22; // TRCIOC Pin:P3_4 , TRCIOD Pin:P3_5

tstart_trcmr = 0; // Stop TRC Count
trcic = 0x00; // Interrupt disabled

pwmb_trcmr = 1; // TRCIOB PWM mode selection bit:PWM mode
pwmc_trcmr = 1; // TRCIOC PWM mode selection bit:PWM mode
pwmd_trcmr = 1; // TRCIOD PWM mode selection bit:PWM mode
pwm2_trcmr = 1; // PWM2 mode selection bit:PWM mode
bfc_trcmr = 0; // TRCGRC:General register
bfd_trcmr = 0; // TRCGRD:General register

tob_trccr1 = 0; // TRDIOB output level:"H" active
toc_trccr1 = 0; // TRDIOC output level:"H" active
tod_trccr1 = 0; // TRDIOD output level:"H" active

eb_trcoer = 0; // TRCIOB Pin Output enable
ec_trcoer = 0; // TRCIOC Pin Output enable
ed_trcoer = 0; // TRCIOD Pin Output enable
pto_trcoer = 0; // INT0 of Pulse output forced cutoff input disabled

tck0_trccr1 = 0; // Count Source Selection Bit:fOCO40M("110")
tck1_trccr1 = 1;
tck2_trccr1 = 1;
cclr_trccr1 = 1; // The TRC register clear at the compare match with TRCGRA

trc = 0; // The Count value of TRC is initialized to "0"
trcgra = 4000 - 1; // 25ns * 4000 = 100us
trcgrb = 1000 - 1; // 25ns * 1000 = 25us
trcgrc = 2000 - 1; // 25ns * 2000 = 50us
trcgrd = 2000 - 1; // 25ns * 2000 = 50us

trcier = 0x00; // Disable interrupts ,ovie/imied/imiec/imieb/imiea
tstart_trcmr = 1; // Start TRC Count
}

// **********************************************************************
// ******************** メイン関数
void main(void)
{
int n;
unsigned int i = 0;
unsigned char InSwitchData, InSwitch0, InSwitch1, InSwitch2, InSwitch3;

// ********** 初期化処理
init_clock();
init_val();
init_port();
init_ra();
init_rc();

// ********** スイッチ入力変数初期化
InSwitchData = 0x00; // スイッチ入力変数初期化
InSwitch2 = 0x00; // スイッチ入力変数初期化
InSwitch1 = 0x00; // スイッチ入力変数初期化
InSwitch0 = 0x00; // スイッチ入力変数初期化

// ********** ループ処理
n = 0;
while(1){

// ++++++++++ raの 20mS 周期のタイミングで動作
if(ir_traic) {
ir_traic = 0;
n++;
if(n >= 20) { // 400mSか?
n = 0;
p3_3 = ~p3_3;
} //End Of if(n >= 20) { // 400mSか?


// ********** 20mS毎の処理
// ***** スイッチ入力してチャタフリー
InSwitch2 = InSwitch1;
InSwitch1 = InSwitch0;
InSwitch0 = ~p1; //スイッチを入力して極性逆転

InSwitch3 = InSwitch0;
InSwitchData = ~InSwitch2 & InSwitch1 & InSwitch0 & 0x3F;

// ***** PB押下有りか?
if(InSwitchData & 0x07){ //PB押下有りか?

gInSwitchData = InSwitch0;
ProcessPb();

} //End Of if(InSwitchData & 0x20){ //PB0押下有りか?
} //End Of if(n >= 20) { // 20mSか?

}
}

// ******************** PB押下での処理
void ProcessPb(void)
{
unsigned int iMotorSpeed, iRMotorSpeed, iLMotorSpeed;
int n;

switch(gInSwitchData & 0x07) {
case 0x01 : iMotorSpeed = 1500 - 1; break; //低速に設定
case 0x04 : iMotorSpeed = 2300 - 1; break; //高速に設定
default: iMotorSpeed = 2000 - 1; //中速に設定
}
iRMotorSpeed = iMotorSpeed;
iLMotorSpeed = iMotorSpeed;

if(gInSwitchData & 0x20) { // 右は高速指定か?
iRMotorSpeed = iMotorSpeed + 200;
} //End Of if(gInSwitchData & 0x50) { // 右は高速指定か?

if(gInSwitchData & 0x40) { // 左は高速指定か?
iLMotorSpeed = iMotorSpeed + 200;
} //End Of f(gInSwitchData & 0x50) { // 左は高速指定か?


// ++++++++++ rcの設定
while(imfc_trcsr == 0){ }
imfc_trcsr = 0; /* IMFA flag clear */

while(imfd_trcsr == 0){ }
imfd_trcsr = 0; /* IMFA flag clear */

// while(imfc_trcsr == 1){ }
// while(imfd_trcsr == 1){ }

while(imfc_trcsr == 0){ }
imfc_trcsr = 0; /* IMFA flag clear */

while(imfd_trcsr == 0){ }
imfd_trcsr = 0; /* IMFA flag clear */

tstart_trcmr = 0; // Stop TRC Count
trcic = 0x00; // Interrupt disabled

// ++++++++++ raの 20mS 周期のタイミングで時間待ち
n = 0;
while(n <= 50) {
if(ir_traic) {
ir_traic = 0;
n++;
} //End Of f(ir_traic) {
} //End Of while(n <= 1000) {


cclr_trccr1 = 1; // The TRC register clear at the compare match with TRCGRA

trc = 0; // The Count value of TRC is initialized to "0"
// trcgra = 4000 - 1; // 25ns * 4000 = 100us
trcgrb = iMotorSpeed; // 25ns * 1000 = 25us
trcgrc = iRMotorSpeed; // 25ns * 2000 = 50us
trcgrd = iLMotorSpeed; // 25ns * 2000 = 50us

trcier = 0x00; // Disable interrupts ,ovie/imied/imiec/imieb/imiea
tstart_trcmr = 1; // Start TRC Count

}



ホームへ戻る