ヴイストン「Beauto Chaser」で学ぶプログラミング入門講座

【第8回】BeautoChaserをC言語でプログラミング!-C言語でプログラムを書いてみよう(前編)

Reported by imokenpi

 どうも皆様こんにちは! 大阪工業大学電子工学研究部のimokenpiです。この連載も第8回を迎えました。今回と次回では前後編としてC言語を用いたプログラミングをどんどん書いていきます。前回は開発環境のセットアップ編ということでLEDを光らせるだけで終わってしまいましたが、今回はセンサーやブザーも活用してプログラミングをしていきたいと思います。

 それでは早速ですが前回サンプルプログラムを読み込み、ビルドを成功したところから続けていきたいと思います。まだビルドが成功していない場合、前回第7回の記事を読んでそこまで進めておいてください。

・【第7回】Beauto ChaserをC言語でプログラミング!-開発環境セットアップ編
http://robot.watch.impress.co.jp/docs/column/vstone/20090529_170134.html

 またこの連載ではC言語自体を詳しく解説することはないので、お手数ですが実際に作業を行なわれる方はC言語を解説した本やサイトを見ながら読み進んでいただければと思います。

関数とは?

 いきなりですが、C言語の文法のお話です。前回LED(1);と書けばLEDが光るという説明をしました。これは関数というものを呼び出しています。関数の中では実際によく使うプログラムがまとめられていて、これを定義したり呼び出すことでC言語では複雑なプログラムを見通しよく作成することができます。

 マイコンプログラミングではマイコンごとにいろいろなルールがあり、これらをよく理解しないとプログラミングをすることは難しいのです。しかし前回準備したサンプルプログラムではBeauto Chaser(正確には搭載されているマイコンボードVS-WRC003)の主な機能に対応する関数が定義されていて、ここから自分の使いたい関数を選んでいくことでマイコンプログラミングに慣れていなくともBeauto Chaserのプログラミングができるようになっています。というわけで、これからこの関数を呼び出しながらプログラミングをしていきましょう。

ボタンを使ってみよう

 それではまずボードについているスイッチ(ボタン)が押されているかC言語を用いて取得してみましょう。前回のLEDがマイコンから私たちの世界への出力だとすれば、こちらは外界からマイコンへの入力ということになりますね。ブザーに関する関数はvs-wrc003.hに宣言と共に解説が書かれています。皆さんも実際にHEWで調べてみてください。vs-wrc003.hの該当箇所の引用を以下に示します。

(vs-wrc003.hの引用)
/*ボタン状態取得
CPUボード上の押しボタンの状態を取得する
引数: 無し
戻り値: 0:off 1:on
*/
BYTE getSW();
(引用ここまで)

 と書かれています。まとめてみると以下の通りです。

・getSW()関数
役割:CPUボード上の押しボタンの状態を取得する
戻り値:0:off 1:on

 getSW関数を呼べば、戻り値としてボタンが押されていれば1が、押されていなければ0が返されることがわかります。なるほどなるほ……ど? わかったようなわからないような……。大丈夫、C言語の学習を続けていけばきっとわかります! それでは何事も実践というわけで、せっかくボタンが押されているかどうかを読み取る方法がわかりましたので、ボタンを押している間LEDが光るプログラムを書いてみましょう。HEWでled.cを開き、下の書き換え箇所(太字になっています)を見ながらmain関数内を書き換えてください。

(led.cの書き換え箇所)  /*メイン関数***********************************************************/  void main(void)  {  	//制御周期の設定[単位:Hz 範囲:30.0~]  	const BYTE MainCycle = 60;    	Init((BYTE)MainCycle);		//CPUの初期設定    	//ループ  	while(1){if(getSW() == 1) {LED(1);	//緑のLED点灯  		Wait(1000);	//1000msec待つ} else {LED(2);	//オレンジのLED点灯  		Wait(1000);	//1000msec待つ}}  }  (書き換え箇所終わり)

 この後説明するif文によって、スイッチを押している間は緑のLED、離しているときはオレンジのLEDが光るプログラムです。ここまで書けましたら一度ビルドし、VS-WRC003に転送してください。ビルド方法とVS-WRC003への転送方法は連載第7回を参照してください。エラーが表示されてうまくビルドできない場合は書いた部分に間違いがないか確認し、修正しましょう。うまく転送できたら電源を入れてボタンを押してみましょう。するとうまくLEDが切り替わ……、あれ、切り替わるのが遅いですね。どうやらWait関数で1000msec(=1秒)も待機すると人間の目にも遅く感じてしまうようです。Wait関数を取り除くとスイッチに瞬時に反応してくれるようになります。一度修正し、もう一度ビルド、VS-WRC003に転送してください。今度はうまく切り替わりましたね。

スイッチを押さない時は緑色のLEDが光りますスイッチを押した時はオレンジ色のLEDが光ります【動画】実際に動かしてみた動画です

if文

 さて、ここでif文の紹介をしたいと思います。if文とは連載第7回で使いましたwhile文と同じように、条件に応じて分岐を行なうためのものです。書き方は下記のとおりです。

if(条件式){  	//条件式が満たされた時実行される処理を書く  }  else{  	//条件式が満たされない時実行される処理を書く  }

 先ほどのプログラムでは条件式がgetSW() == 1となっており、getSW() の戻り値が1である時(ボタンを押された時)に緑のLED点灯の処理が、押されていないときにはオレンジのLED点灯の処理が行なわれることになります。if文はプログラミングで大変よく使うのでぜひ覚えておきましょう。

ブザーを使ってみよう

 さて、ボタンを押してLEDが光るだけでは寂しいですね。ブザーを使って音を鳴らしてみましょう。先ほどと同じようにvs-wrc003.hを参照し、ブザー関連の宣言箇所を探しましょう。皆さんもご一緒にお願いします。まとめてみると、以下の3つの関数を使うことがわかります。

・BuzzerSet関数
役割:ブザーを鳴らす際の音程とボリュームを設定
第1引数:音程の設定(0~255、値が大きいほど低い音)
第2引数:ボリュームの設定(0~128)

・BuzzerStart関数
役割:ブザーを鳴らし始める。BuzzerStop()関数を呼ぶまでなり続ける。

・BuzzerStop関数
役割:ブザーを止める。

 上記の3つの関数を使えばブザーを使ったプログラミングができてしまいます。早速先ほどのプログラムを改造して、ボタンを押している間、LEDの代わりにブザーが鳴るプログラムに改造してみます。HEWのサンプルプログラムのled.c内のwhile文を以下の内容に書き換えてください。

(led.cの書き換え箇所)  /*メイン関数***********************************************************/  void main(void)  {  	//制御周期の設定[単位:Hz 範囲:30.0~]  	const BYTE MainCycle = 60;    	Init((BYTE)MainCycle);		//CPUの初期設定BuzzerSet(175 , 100);//ループ  	while(1){  		if(getSW() == 1) {BuzzerStart();} else {BuzzerStop();}  	}  }  (書き換え箇所終わり)
【動画】実際に動かしてみた動画です

 ここまで書けましたらビルド、そしてボードに転送です! うまくできていればスイッチを押すとブザーが鳴ります。

 このブザーはBuzzerSet関数の第一引数を書き換えることで音階を変えることもできます。おおよその音階と数値の対応表は次のとおりです。

音階	数値  シ	233  ド	220  ド♯	208  レ	196  レ♯	185  ミ	175  ファ	165  ファ♯	156  ソ	147  ソ♯	139  ラ	131  ラ♯	124  シ	117  ド	110

 上記のプログラム内では175を第一引数に指定しているのでミの音が鳴ることがわかります。ためしに147にしてみると、ソの音が鳴りますね。

センサーの値の習得方法

 それでは次にセンサの値を読み込む方法を見ていきましょう。vs-wrc003.hからAdRead関数を見つけることができます。まとめてみると以下の通りです。

・AdRead関数
役割:A/D変換の入力値を取得。
引数:チャンネル(0~7=1~8)
戻り値:A/D変換の値(0~1023)

 AdRead関数で注意しなければならないのは、引数でどのセンサーを使って読み取るのかを指定しないといけないところです。画像を参考にしていただきたいのですが、センサーが刺さっているところ(シルク印刷でAN1と印刷されている箇所)を使用するにはC言語で引数に0を指定する必要があります。C言語では数字は0から順に数えることが多く、基板のシルク印刷の数字とC言語で指定する数字が食い違っていますので注意してください。詳しいピンの対応についてはヴイストン社のWebサイトからテクニカルマニュアルがダウンロードできますので、そちらを参照してください。

・VS-WRC003テクニカルマニュアルのダウンロードサイト
http://www.vstone.co.jp/top/products/robot/beauto/cdownload.html#ref

 今回はAN1にBeauto Chaser標準搭載の赤外線センサーを取り付け、センサーの値によってブザーの音が変わるプログラムを書きましょう。

画像でセンサーが刺さっているところ(AN1)はC言語では0を指定すれば値を読み出せます。その隣がAN1(C言語では1を指定)、ピンを増設すればその隣のAN2、AN3も使用できます赤外線センサーを取り付けたところ

 例によってled.cの変更箇所を以下に示します。少しややこしいですが皆さんも自分の手で書きこんでみましょう。

(led.cの書き換え箇所)  /*メイン関数***********************************************************/  void main(void)  {  	//制御周期の設定[単位:Hz 範囲:30.0~]  	const BYTE MainCycle = 60;    	Init((BYTE)MainCycle);		//CPUの初期設定    	//ループ  	while(1){if(AdRead(0)<=100) {  			//AN1のAdRead関数の戻り値が100以下のとき実行される  			BuzzerSet(220,100); //ド  		} else if (AdRead(0)>100 && AdRead(0)<=300) {  			//AN1のAdRead関数の戻り値が100より大きく300以下のとき実行される  			BuzzerSet(196,100); //レ  		} else if (AdRead(0)>300 && AdRead(0)<=500) {  			//AN1のAdRead関数の戻り値が300より大きく500以下のとき実行される  			BuzzerSet(175,100); //ミ  		} else if (AdRead(0)>500 && AdRead(0)<=700) {  			//AN1のAdRead関数の戻り値が500より大きく700以下のとき実行される  			BuzzerSet(165,100); //ファ  		} else if (AdRead(0)>700) {  			//AN1のAdRead関数の戻り値が700より大きいとき実行される  			BuzzerSet(147,100); //ソ  		}  	BuzzerStart();  	Wait(100);}  }  (書き換え箇所終わり)
実際に動かしてみた動画です

 今回if文の条件式に「&&」という演算子を使っています。これは「a && b」と書いたときにa、bがともに成り立つ(真)の時、真になります。C言語では数学のように100<AdRead(0)<=300という書き方ができないので、少し回りくどいのですがこのようになります。今回はaとbの条件が両方成り立つ場合if文の中身が実行されることになります。余談ですが&&演算子に対応する演算子として||演算子がありa || bと書いた場合aまたはbのどちらかが成り立てば真となります。どちらもif文の条件式の中でよく使うので覚えておくと便利でしょう。

 さて、書き換えたらビルド、そしてVS-WRC003に転送しましょう。もう操作の方も慣れてきましたでしょうか。机などに赤外線センサーを手のひらなどに近づけて音が変化すれば成功です!

 さて、今回も紙面が尽きてしまいました。次回はモーターの動かし方、そしてライントレースのプログラムを書いていきましょう。C言語編も次回で最後です。お楽しみに!



2009/6/9 00:00