Pi:Co Classicの状態をユーザーに知らせる方法は、2つ考えられます。1つは、LEDの点灯、もう1つはブザー音です。ここでは、前回覚えたLEDの点灯とスイッチを組み合わせて、ユーザーに選択モードを知らせる方法を採用します。
それでは、スイッチとLEDをどのように組み合わせたら、使い勝手の良いシステムになるでしょうか。以降で検討してみましょう。
Pi:Co Classicには、前方に4個のLEDが搭載されています。この場合、LEDの点灯パターンで2進数を表示するのが“電子工作の王道”です。2進数なら、0〜15までを表示できますね。全LEDが消灯している「0」を除き、1〜15をモード表示としましょう。
では、「スイッチ3」には、どんな役割を持たせましょうか? 「スイッチ2」を実行A、「スイッチ3」を実行Bとすれば、15×2で30個のモードを搭載できます。そんなにたくさんのモードが必要ないのであれば、「スイッチ3」を2進数の減算に使うこともできます。「スイッチ1」の動作を、1→2→……→15→1→2→……とした場合、スイッチをうっかり押し過ぎて目標の数字をオーバーしてしまうと、やり直しが面倒ですね。「スイッチ3」で減算できれば、使いやすくなります。
「いやいや、モードは30個必要! でも、ユーザーインタフェースとして減算もほしい!!」――そんな要求があったら、どうしますか?
その場合、「スイッチ3」を“シフトキー”とするのも1つの案です。
スイッチ1:モード選択(インクリメント)
スイッチ2:実行A
スイッチ3+スイッチ1:モード選択(デクリメント)
スイッチ3+スイッチ2:実行B
こうすれば、要求仕様をかなえることができます。
そして、もう1つ検討すべきなのは「どのスイッチに、どの機能を割り当てるのか?」です。
「実行」スイッチは、“青はススメ”のイメージで青にしましょうか? でも、それだと、モード選択が2つ並んでしまいます。それぞれのスイッチに人差し指、中指を乗せると、押しにくくないでしょうか? 指は1本しか使わないから、スイッチが並んでいても問題はないでしょうか? そもそもスイッチが並んでいると、間違いやすくはないでしょうか?
世の中に出回っている全ての製品は、スイッチの配置だけではなく、色や形状にも意図があります。使いやすい製品もあれば、使用するたびに小さな違和を感じる製品もあります。その違いは何から生じるのでしょうか? 日ごろから、そうした意識を持って身の回りを観察していると、モノづくりをする際に必要なセンスが磨かれると思います。
えみちゃんは、どのスイッチに、何の機能を割り当てたい?
えっと〜。モードは15個もあれば、十分かなと思いますね。
30個作ってもきっと覚えられないでしょうしぃ〜。
ふむふむ。
で、真ん中の黄色のスイッチを「実行」に使いたいですね。
何て言うかぁ〜、中心にあると「GO!」って気がしません?
いいんじゃない。
となると、加算・減算スイッチを両端に分けるんだね。
はい! その方が、スイッチの押し間違いが減るんじゃないかなって思います。
右端の青を加算、左端の赤を減算にしたいですね。
OK! いいと思うよ。
やった! 正解ですか?
いや。こういうのって、正解は1つじゃないんだよ。だから基本的に、えみちゃんのセンスで決めればいいんだよね。
「ただ、何となくぅ〜」じゃなくて、“なぜ、そうしたいのか”、自分なりの理由があることが大切だよ。
えへっ!!
じゃあ、その仕様でプログラムを組んでいこう!!
ハイッ!!
それでは、スイッチを制御するプログラムを作りましょう。えみちゃんが考えたスイッチの動作は、以下のような仕様になります。
プログラミングを始める前に、スイッチを制御するのに必要な情報を、マニュアルの「基板ポート一覧」と「回路図」から取得しておきましょう。タクトスイッチと書かれているPB1〜PB3が該当のスイッチです。
マイコンプログラムで、スイッチの状態を取得するには、該当するポートを入力に設定し、ドライバ関数内でreturnするだけでOKです。
では、前回と同じ要領で、スイッチを制御する関数を書いていきましょう。
まず、I/Oポート初期化関数に、スイッチのポートを追加します(ソースコード1)。
void init_io(void) { //スイッチ PFC.PBIORL.BIT.B1 = 0; //PB1を入力に設定(青) PFC.PBIORL.BIT.B2 = 0; //PB2を入力に設定(黄) PFC.PBIORL.BIT.B3 = 0; //PB3を入力に設定(赤) //LED …… 以下略(前回記述) …… }
ソースコード1 「init.c」内のI/Oポート初期化関数に、スイッチのポートを追加する。ポートの初期値は「0」なので、このソースコードを書かなくても動作に影響はない |
続いて、「common.h」内にスイッチオンの状態を定義します(ソースコード2)。Pi:Co Classicの場合、スイッチが押されていないとき、ポートの電位は“1(High)”、スイッチが押されるとポートはグランドに接続され、電位は“0(Low)”になります。ですから「SW_ON」を“0”で定義します。
//SW ON #define SW_ON 0 //SW ON
ソースコード2 呼び出し側、実行側で同じ定義を使用するものは、「common.h」内に記述する |
そして、「drv.h」内にスイッチの各ポートの名前を定義し(ソースコード3)、「drv.c」内に記述した関数でポート名を取得すれば、スイッチの状態を読み取ることができます(ソースコード4)。
//スイッチポート #define SW_BLUE PB.DR.BIT.B1 //青スイッチ #define SW_YELLOW PB.DR.BIT.B2 //黄スイッチ #define SW_RED PB.DR.BIT.B3 //赤スイッチ
ソースコード3 「drv.h」内にスイッチのポートを定義する |
unsigned char drv_sw_b(void) { //スイッチドライバ(青) //スイッチを読み込む return SW_BLUE; }
ソースコード4 「drv.c」内に、スイッチの状態を読んで返す「drv_sw_b」関数を作成。赤、黄スイッチも同様に記述する |
「ctrl.c」内には、3つのスイッチの状態を一度に取得する関数を記述します。この関数では、最初に押されたスイッチが常に優先されています(ソースコード5)。
void ctrl_sw_all(unsigned char *o_sw_b, unsigned char *o_sw_y, unsigned char *o_sw_r) { //スイッチ処理(一括) *o_sw_b = drv_sw_b(); //青スイッチ *o_sw_y = drv_sw_y(); //黄スイッチ *o_sw_r = drv_sw_r(); //赤スイッチ //どれかのスイッチがONならば、全てのスイッチがOFFになるまで待つ if (*o_sw_b == SW_ON || *o_sw_y == SW_ON || *o_sw_r == SW_ON) { while(drv_sw_b() == SW_ON || drv_sw_y() == SW_ON || drv_sw_r() == SW_ON); } }
ソースコード5 3つのスイッチの状態を読み込む関数。最初に押されたスイッチの値がSW_ONで返る |
よし、これでスイッチの制御ができるよ。
スイッチの制御って、押されているか? いないか? を判断するだけだから、すごーくカンタンですね!
そうだねぇ〜(ニヤリ)。
じゃあ、スイッチを押したらLEDを2進数表示する関数を作ろうか。
はいっ!!
Copyright © ITmedia, Inc. All Rights Reserved.