常識的に考えて初期設定の前には追加しませんから、追加する位置としてはこの二つが考えられる、ということになるでしょうか。
実際は、左の図の位置ではあまりよろしくありません。 絶対にできないということはなく、要するに 「パラレル式リモコンタイプA処理」 に入ったらそこから抜け出さないような構造にすれば実現できます。 しかし、これにほかの処理を追加したい、となったら大変です。 大掛かりな改造をしなくてはなりませんね。 何しろこの処理は終わらないわけですから、新しい処理をこの中に組み込んでいくはめになってしまいます。
そんなわけで、右の図の位置に追加するのが自然です。 これなら 「パラレル式リモコンタイプA処理」 を実行し続けることになりますし、後からほかの処理を追加するのも簡単です。
それでは、「パラレル式リモコンタイプA処理」 の中身はどのようにすればよいか考えてみましょう。 「タイプAのリモコンでマイコン・カーを動かす」 という要求をもう少し具体的に見てみると、次のように表現することができます。 なお、これまでタイプAのリモコンで 「前進」 「後退」 と書いたところがありますが、「正転」 「逆転」 に読み替えていただくようお願いします。
右正転スイッチ(SW1) がオンの間、モータ右+ をオンにする。
右逆転スイッチ(SW2) がオンの間、モータ右- をオンにする。
左正転スイッチ(SW3) がオンの間、モータ左+ をオンにする。
左逆転スイッチ(SW4) がオンの間、モータ左- をオンにする。
これらは独立しており、同時に動かすことも可能。
右正転と右逆転を両方オンしてもよい。そのとき右モータは停止(*1)する。 左も同様。
(*1) 正転と逆転を両方オンのとき停止と書いたが、正確にはモータ・ドライバ MPC17531A ではフリー(ハイ・インピーダンス)状態となる。 ちなみに正転と逆転を両方オフのときも停止するが、これはブレーキ状態となる。 TA7291 とは反対なのでそちらに慣れた方は注意が必要。
これだけわかれば、あとは簡単そうに思えます。 初期設定は同じなので、その続きの for 文のところだけ書いてみましょう。
for( ; ; ){
if ( PTB_PTB0 == 0 ){ // SW1がオン
PTB_PTB6 = 1; // モータ右+
}
if ( PTB_PTB1 == 0 ){ // SW2がオン
PTB_PTB7 = 1; // モータ右-
}
if ( PTB_PTB2 == 0 ){ // SW3がオン
PTB_PTB4 = 1; // モータ左+
}
if ( PTB_PTB3 == 0 ){ // SW4がオン
PTB_PTB5 = 1; // モータ左-
}
}
この for 文の中はずっと繰り返されるので、要求通りに書けたかのように見えます。 ところが、これではダメなんですね。 どこがまずいのでしょう? 動かしてみればわかるかもしれませんが、意外とわかりにくいかもしれません。 時間の節約で答えを教えてしまいます。 実はこのプログラムでは、モータ出力を“H”にすることはできても、“L”にすることができないのです。 おわかりでしょうか、どこにもポート出力を 0 にしているところがありませんね!
それでは、次のようにしてはどうでしょうか。
for( ; ; ){
PTB = 0x00;
if ( PTB_PTB0 == 0 ){ // SW1がオン
PTB_PTB6 = 1; // モータ右+
}
if ( PTB_PTB1 == 0 ){ // SW2がオン
PTB_PTB7 = 1; // モータ右-
}
if ( PTB_PTB2 == 0 ){ // SW3がオン
PTB_PTB4 = 1; // モータ左+
}
if ( PTB_PTB3 == 0 ){ // SW4がオン
PTB_PTB5 = 1; // モータ左-
}
}
ちょっとした変更で直すことができた・・・? これなら、それぞれのスイッチがオフのときはモータ出力がオフのままで、スイッチがオンのときはモータ出力がオンになりそうです。 これを実際に動かしてみると、「あっ うまくいった!?」 と思うかもしれません。 ところがこれも、良いとはいえないのです。 繰り返し繰り返し、毎回出力をオフしていますから、安定したオン出力ができず、パルス状の信号が出てしまうのです。
思ったより難しいな、と感じた方もいるかもしれません。 でもわかってしまえば簡単なことなのです。 先ほどの要求仕様の確認のところでは、スイッチがオンのときのことしか書かれていませんでした。 実際は、スイッチがオフのときには出力をオフしたいわけですから、次のように解釈するのが正しかったのです。
右正転スイッチ(SW1) がオンの間、モータ右+ をオンにする。
↓ 正しい解釈
右正転スイッチ(SW1) がオンの間はモータ右+ をオンにして、
右正転スイッチ(SW1) がオフの間はモータ右+ をオフにする。
ほかのスイッチとモータも同様です。
意味がわかったところで、さっそく書き直してみます。
for( ; ; ){
if ( PTB_PTB0 == 0 ){ // SW1がオン
PTB_PTB6 = 1; // モータ右+
} else {
PTB_PTB6 = 0;
}
if ( PTB_PTB1 == 0 ){ // SW2がオン
PTB_PTB7 = 1; // モータ右-
} else {
PTB_PTB7 = 0;
}
if ( PTB_PTB2 == 0 ){ // SW3がオン
PTB_PTB4 = 1; // モータ左+
} else {
PTB_PTB4 = 0;
}
if ( PTB_PTB3 == 0 ){ // SW4がオン
PTB_PTB5 = 1; // モータ左-
} else {
PTB_PTB5 = 0;
}
}
やっとできました。 自信を持って、マイコンに書き込んで動かしてみましょう! パラレル式リモコン(タイプA)の四つのボタンを使って、マイコン・カーを操ることができるようになりました。 まずは、一安心です。 ここまでやけに長かったですね。 でも正常に動くところを見ると、単純なことですが嬉しいものです。 おめでとうございます!
念のためにプロジェクトごと圧縮したものを parallel_01.zip に置いておきます。
パラレル式リモコン(タイプA)とマイコン・カーで遊ぶようす
ところで、たったこれだけのことを書くのに、妙に長ったらしいと思いませんか? 次のように書くこともできるんです。
for( ; ; ){
PTB_PTB6 = !PTB_PTB0;
PTB_PTB7 = !PTB_PTB1;
PTB_PTB4 = !PTB_PTB2;
PTB_PTB5 = !PTB_PTB3;
}
えらく短くなっちゃいましたね! でも汎用ポートのところの説明を理解していれば、意味はわかるはずです。 面白いですね。
それはそうと、こんな書き方をしていては実際の動きの意味がわかりにくいじゃないか、という不満があってもおかしくありません。 はい、次のような書き方もできます。 #define のところで文字列の置き換えを指示しているのです。
#include <hidef.h>
#include "derivative.h"#define PORT_SW1 ( PTB_PTB0 )
#define PORT_SW2 ( PTB_PTB1 )
#define PORT_SW3 ( PTB_PTB2 )
#define PORT_SW4 ( PTB_PTB3 )
#define PORT_MT_RP ( PTB_PTB6 )
#define PORT_MT_RM ( PTB_PTB7 )
#define PORT_MT_LP ( PTB_PTB4 )
#define PORT_MT_LM ( PTB_PTB5 )
void main( void ){
CONFIG1 = 0x11; // LVI無効、COP無効
PTAPUE = 0x24;
PTA = 0x08;
DDRA = 0x0A;
PTBPUE = 0x0F;
PTB = 0x00;
DDRB = 0xF0;
for( ; ; ){
PORT_MT_RP = !PORT_SW1;
PORT_MT_RM = !PORT_SW2;
PORT_MT_LP = !PORT_SW3;
PORT_MT_LM = !PORT_SW4;
}
}
これは for 文だけでなく、全体を示しました。 プロジェクトごと圧縮したものを parallel_02.zip に置いておきます。
余談ですが、スイッチ入力ポートとモータ出力ポートの並びがいまいち対応していないように見えたかもしれません。 そのとおりです・・・。 なんせ最初のマイコン・カーを設計したのは 2003年頃ですから今とは感覚が違っていたようなのです。 そのためリモコンは右・左の順で考えていますが、新しいマイコン・カーのほうは現在の設計で左・右の順で考えてしまいました。 まあ、とくにこれで問題があるわけではないので、このままにしておきます。 弊害といえば、次の書き方ができなかったことくらいです。
for( ; ; ){
PTB = ~( PTB << 4 );
}
これは非常に短くて面白いのですが、実際問題こんなことができる場面なんて限られていますし、設計変更に対応しにくいので 「良い方法」 とは言い切れないのですけど。
気になる方向けの解説
前回の初期設定だけのプログラムのときもそうだったのですが、LVI無効というのが不思議に感じた方がおられるかもしれません。 LVI の説明はもっと後のほうで行いますが、要するに電源電圧が下がってきたら暴走する前にリセットさせる、という機能です。 ちなみに PIC マイコンでは BOR(ブラウン・アウト・リセット)と呼ばれているようです。
この機能を無効にしておくと、電源電圧が下がってきて本当に暴走または停止してしまうポイントまでマイコンを動かし続けることができます。 その反面、電源を入れ直さないと復帰しないような状態に陥る可能性がある、ということを忘れてはなりません。
今回のクルマのおもちゃの場合はモータを 2個同時にオンしたとき 3V の電池電圧が瞬間的に下がってしまうので、やむなく LVI無効の設定にしています。
次回は、パラレル式リモコン(タイプB)を使ってマイコン・カーを動かします。
『参考文献』
「試しながら学ぶHC08マイコン入門」 (CQ出版)
第9章 USB-HC08デバッグ・ツールを自作する
Appendix F KMC908QY4Aユーザ・モード・モニタ入りマイコンの知識
筆者のホームページ 『マイコン工作の実験室』
組み込みエンジニア KAWANO
