はじめに
近藤科学からマイコンボードKCB1が発売されてからだいぶ経過しました。KCB1は基本的には近藤科学製シリアルサーボを駆動するもののようで、マイコンのシリアル通信機能は自由に使うことはできません。ということで、ここではKCB1の汎用IOポートを使ってソフトUARTを構成し、浅草ギ研のADCボードAGB65-ADCと接続してセンサーを増設できるようにしてみます。
※このページで紹介する内容はあくまでも一例です。個別の作成のご相談ご質問はお答えできませんのでご了承下さい。このページと同じ内容についてのご質問についてはロボット掲示板にてお願いいたします。
※以下の情報は2008年3月現在のものです。ご注意ください。
AGB65-ADCについてはこちらを参照願います。
KCB1については近藤科学のホームページを参照願います。
KCB1のマイコンと開発について
通常、マイコンボードといえばそのマイコンチップについて熟知した上でプログラムを組まなければなりません。ビギナーでよくあるのが、「マイコンボードを買った。サンプルプログラムを動かした。その後どうやってよいかわからない。」という声をよく聞きます。マイコンボードを買って独自のプログラムを組もうとした場合は、基本的には「メーカーから出ているマイコンチップのドキュメントを熟読して使い方を体得する」ことになり、これができれば自由にシステムを構築することができます。
このページで作成しているソフトUART(シリアル通信機能)もKCB1のドキュメントではなく、チップのドキュメントを読んで作っています。
KCB1を購入するとSDKとしてマイコンの各機能を使うための関数ライブラリ(近藤科学製)が付いてきますので有る程度のことはできますが、それ以上をしようとするとやはりドキュメントを読むしかありません。KCB1添付のCD-ROMにはマイコンチップ自体のドキュメントは付いていませんのでメーカーのホームページからダウンロードすることになります。尚、CD-ROM内のマニュアルには記述はありませんが、KCB1のマイコンチップはルネサステクノロジー社製の「M30262F8」というものです。
ドキュメントは大きく2つあり、「M16CTinyソフトウェアマニュアル」と「M16C26シリーズハードウェアマニュアル」があります。どちらもルネサス社のホームページからダウンロードできますのでそちらで入手してください。尚、M30262F8は最新チップではない(というか現時点では収束方向)のでドキュメントを探すのに少々苦労するかもしれません(筆者が確認したところでも、2008年3月時点と、現在2008年8月時点でホームページの構成が変わってます。ということでリンクは貼っていません。)
M16CTinyの開発はC言語かアセンブラで行えます。もしアセンブラで開発したい場合はオーム社より「はじめてのM16C/Tinyマイコン:寺下晴一著:ISBN4-274-07974-0」という書籍も出ています。筆者の感想ですが、この書籍は内容的にはおもしろいのですが、ビギナーはチップに依存するアセンブラ言語を使うよりも、他の開発でも比較的同じように使えるC言語を勉強した方がよいかと思います。
KCB1のUARTについて
KCB1のIO構成は次のようになっています。
マイコンによくある機能でUART(非同期シリアル通信機能)というものがあり、マイコンのハードで構成されています。マイコンのシリアル通信については、弊社の他のサンプルプログラムのページなどに多数書かれていますが、トランジスタ技術2006年6月号に特集記事が載っており、かなり詳しく書かれていますので一度参照されることをお勧めします。
マイコンのUARTは通常はTX(送信)、RX(受信)と2つの信号線+GNDを使って通信されますが、KCB1のSIO1とSIO2は特殊なハード構成になっており、ここに普通のマイコンのUARTを直結することはできません。
M16CTiny26はUARTをハード的に3つ持っていますが、UART0とUART2は近藤シリアルサーボを駆動するために下図のようにTXとRXが基板上でつながっています(実際にはさらに保護抵抗などがあります)。COMは近藤科学社製のUSBアダプタに接続するために電圧変換回路(HighとLowが逆になる)を経由していますので普通のマイコンのUARTとはそのままでは接続できません。
浅草ギ研製品とソフトUARTの必要性
浅草ギ研ではマイコンのUART(もしくはPC)と接続していろいろな機能を追加させる「ロボット神経システム」を作っています。これは一般的なUARTとの接続を想定していますのでKCB1の3つのシリアルポートとは接続できません。といいますか、KCB1にあるシリアルポートもそれぞれ別な目的で使いますのでここをつぶすことは本末転倒となります。
UARTの通信方法ですが、これはシリアル通信としては比較的簡単な部類に入り、電気的には単に端子をHIGH/LOWするだけで通信することができます。つまり、UARTの仕様に合ったタイミングで汎用のIOで端子を操作すれば他のマイコン(ここでは浅草ギ研製品)と接続することができます。
マイコンのシリアル通信の仕様
非同期シリアル通信なのですが、スタートのタイミングは送信側のTXがHIGH->LOWになった瞬間から行われます。つまり待機時はTXがHIGHになっています。よく、浅草ギ研製品を購入された方から「TXがHIGHになっているので不良ではないか?」という問い合わせを受けますが、これはマイコンのシリアル通信の仕様です。
送信側と受信側はそれぞれタイマでタイミングを計測し、このスタートの瞬間から各ビットまでの時間を計測して各ビットがHIGH(論理1)なのかLOW(論理0)なのかを判定します。
下は通信の様子です。他の資料のものなので、上部のPCのところは無視してください。
非同期なので送信側と受信側であらかじめ通信速度、つまり各ビットを読むタイミングを決めておかなくてはなりません。一般的には、通信速度の16倍のタイミングを生成し、各ビットの中心、つまり8カウント目を読んで値を判定します。
上の図(下のマイコンの方)を例にとりますと、通信待機時はTXからHIGHが出され続けます。通信開始になるとTXがLOWになり、受信側もこのタイミングから通信開始します。開始後はLOWなので、1ビット分の時間、つまり16カウント待ちます。
その後、8カウント目で初めのビットを読みます。2番目のビットはその16カウント後に読めばよいことになり、このようにして16カウントごとにビット7まで読みます。次の通信を始めるために通信後はHIGHにしなければなりませんので最期のデータ終了後に送信側は1ビット分のHIGHを出します。
注意)KCB1のCOMはシリアル通信とはいえども、このような一般的な通信方法ではないため、待機時にTXがLOWになっています。これは近藤製USBアダプタと接続するための特殊なシリアル通信の規格になっているようですので注意してください。
というように、マイコンのタイマを使って汎用IOの端子をHIGH/LOWすれば通信は可能という
接続
ロボット神経システムはいろいろな種類がありますが、KCB1に役立ちそうなものにADCボードがあります。これにより、浅草ギ研製センサーや、マノイ用センサーなどを増設することができるでしょう。
AGB65-ADCとの接続は次のようにしました。
KCB1のP106:TX −> AGB65-ADCのRXへ
KCB1のP107:RX −> AGB65-ADCのTXへ
プログラム−プロジェクトの説明
今回のプログラムをHEWのプロジェクトファイルごと圧縮しました。
KCB1_AGB65.lzh (100KB、右クリックで対象を保存)
プログラムは大きく分けて2つ
nuart.h : 今回の心臓部。ソフトUART
KCB1_AGB65.c :テスト用のプログラムで、センサーの値を定期的にCOMから出力してPCに表示する。
です。各プログラムにコメントを詳細に入れていますのでファイルの中を読んだだけでもある程度は使い方が理解できるかと思います。ソフトUARTの名称をnuart(ヌーアート)と名づけました。
プロジェクトを解答して展開すると、HEWの構成は次のようになるかと思います。
今回はプロジェクトごと圧縮したので、解答すると上の構成になっているかと思いますが、独自のプログラムを作る際にnuartを組み込む場合は次の手順にします。もしくはnuart.hの関数部分を自分のCソースファイルにコピーしても使えると思います。
・ビルド前に「ビルド」->「Renesass M16C Standard Tolochain...」の「コンパイラ」タブ の「オプション項目」で「インクルードファイル検索ディレクトリ」を選択し、
「追加」ボタンを押して、nuart.hがあるディレクトリを追加指定してください。
プログラム−nuartの説明
nuart.hを開くとプログラム部分が見れます。プログラムは初期化、送信、受信の3つに分かれます。
<初期化関数>
初期化は次のようになります。KCB1では汎用IOの表記がなぜかP100〜になっていますが、M16CTinyではその部分はP70番台とP80番台になります。まぎらわしいので、M16Cの表記で進めます。
ここではKCB1のP106つまりM16のP80をTX、KCB1のP107つまりM16のP81をRXにしましたのでそれぞれ入出力設定します。その後、TXは待機状態つまりHIGHに固定します。行37でTXをhighにしていますが、nTXというのはその上の行(行26,27)で定義したものでP80の端子を示します。
又、タイマを設定して通信のためのタイミング作成の準備をします。
<タイマの設定>
今回は9600bpsと比較的遅い速度で固定する設定としました。KCB1のクロックは20MHzなので、計算すると9600bpsの1ビットは2083.3333...カウントになります。
UARTでは1ビットのさらに16倍のタイミングを生成して、真ん中の8カウント目で値を読みますので、この2083.333カウントを16分割した値の単位で動作させます。
今回はこのタイミング生成にタイマ4を使いました。よって、他のアプリでタイマ4は使用できませんのでご注意下さい。
<送受信同時処理と割り込みについて>
一般的なUARTは送信も受信も同時にできて、他のプログラムが動いていても通信機能は勝手に動きます。これはハード的にUARTが構成されているので可能なわけで、今回はソフト的にUARTを作るので送受信同時はできません。厳密に言うと割り込みなどを駆使して実現は可能ですが、そこまでするのであれば根本的に違うシステムを作った方がよいことになります。(つまりマイコンボードの選択が間違っている)
今回は簡易的にAGB65シリーズとつなげる目的で作られていますので、送受信同時と割り込み処理はできませんのでご了承下さい。
<送信関数>
送信部分はつぎのようになります。
行45: 計算では1ビットの長さはタイマの2083カウントになりますが、C言語なので1行が1クロックで動くわけではありません。いろいろと試行錯誤した結果、カウントは2050で大体1ビット(9600bps時)になりましたのでその値を定数としました。
行52:バイト長の配列と、その配列で何バイト送るかを指定します。
行57:1バイトはスタートビットとストップビットを足した10ビット単位で行われます。これを指定したバイト数分ループ処理します。
行58:配列の値は8ビット単位、送るのはシリアルなので1ビット単位、ということで8ビットのうち、現在はどのビットを送るかをmaskでマスクします。UARTは下位ビットから送るのでここで最下位ビットだけ1にしてマスクを初期設定します。
行59:現在送るデータ1バイト(8ビット)をセットします。
行62〜65:スタートビットを生成します。TXをLOWにして1バイト分待ちます。行64ですが、カウンタ値を比較している間にカウントが行き過ぎて0を下回るとカウンタがリロードされてしまい1ビットでとまらなくなるので、カウント10前後で寸止めしています。行65ですが、1ビットごとにタイマを止めないと、カウントが進んでしまいこれまたカウントがおかしくなるのでタイマを一時止めています。この辺り、タイマの構造をよく知っていないとハマる要因の部分です。C言語は遅いので一行処理するあいだにカウントが進んでしまうというのを頭においてプログラムします。
行68:1ビットづつ8回処理します。
行69〜73:現在送る1ビットが1なのか0なのかを判定してTXラインをセットします。
行75:1ビット分待ちます。先のカウント10で寸止めではなく、カウント15で寸止めしていますが、これは試行錯誤した結果この値になりました。
行76:マスクを左1ビットシフトして、次のビットを指定するマスクを作ります。
行80〜:データ部分が終わったら、スタートビットと同じようにして1ビット分のHIGHのストップビットを出力します。
<受信関数>
送信はこちら側でコントロールするので問題ありませんが、受信は相手がどのような処理をしているかわからないのでエラー処理を含めました。又、受信をするために待っていてもいつまでたっても相手から送信が開始されない場合はこの関数でずーっととまってしまうということもありえますのでタイムアウトも入れました。
戻り値:0で指定バイト数を正常受信、1が断線又は送信途中で受信開始エラー、2がタイムアウト、3がストップビットエラーとなります。
行114:この関数起動時に相手のTXがHIGHでなかったらエラーとなります。主に断線かどうかの判定ができます。
行115:指定したバイト数を受信しとうと試みます。
行119〜123:通信開始のタイミングを判定しています。今回はAGB65シリーズとの接続用なので、この関数起動時から3秒以内に相手から送信が開始されなかったらエラーとしています。これは、AGB65シリーズの場合、返答するタイプ(今回のAGB65−ADCも同じ)の場合は長くても1〜2秒ぐらいで値を返すのでタイムアウトを3秒としました。他で使う場合はこのタイムアウト値を変えるとよいでしょう。
行124〜行128:スタートを検知、つまり相手のTXがHIGH−>LOWになったら1.5ビット分の時間待ちます。この次の処理で、各1ビット分の時間間隔で値を読めばちょうど各ビットの中心位置で読むことになり、お互いにスピードが少々ズレていても問題なく通信することができます。
行130〜142:後は送信と同じようにマスクを利用して1ビット分ずつ判定した値を格納していきます。行135は意味はありませんが、受信した値が1の場合と0の場合と同じタイミングになるように同じような処理を入れています。
行144:結果を配列に格納します。
行145:最後にデータ受信後にHIGHになっているかを確認します。ここでHIGHになっていない場合は送信側と受信側でタイミングがズレてしまったか途中で断線したかということになります。
全体的な説明ですが、C言語なので各行でどのぐらいの時間が消費されているかわかりませんので、実際のタイミング調整にはオシロなどを使ってタイミングを見ながらタイマ値などを決めていきました。通信速度を速くしようとした場合はタイミング誤差がシビアになるので簡単な方法としてはこのぐらい(9600bps)が限界ではないかと思います。それ以上速くしたい場合はアセンブラで書いたりクロックを変えたりしなくてはならないような気がします。
プログラム−KCB1_AGB65.cの説明
nuartを使ってAGB65−ADCの値を読むサンプルプログラムがKCB1_AGB65.cになります。nuart.hをインクルードすると上の各関数が使えるようになります。こちらは単純にシリアル通信でAGB65-ADCに対してコマンドを送っているだけなので詳しい説明は割愛します。
一部、わかりづらいところだけ説明します。
AGB65-ADCは8ビットもしくは12ビットの解像度でセンサーの値を読めます。12ビットで読んだ場合、シリアル通信では8ビット(1バイト)単位の通信となるので2バイトで値をやり取りすることになります。
下の部分は2バイトで受け取った結果を合成するところです。RXbufは1バイト単位の配列で、result変数は16ビット長になっています。
行96:上位8ビットをとりあえずresult変数に入れます。この時、上位8ビットはresultの下位8ビットの位置に入ることになります。とりあえず。
行97:変数を左に8ビットシフトすることで、結果の上位8ビットがresultの上位8ビットに移動します。このとき、resultの下位8ビットはまだ空白、つまり全て0のままになります。
行98:resultの下位8ビットに結果の下位8ビットを入れるには単純に足せばよいことになります。
その他はAGB65−ADCのページの仕様の通りにデータを送れば結果が返信されます。結果が返信されるタイミングですが、AGB65−ADCは500Kサンプル/秒の速度でセンサー値を読みますので、9600bpsのシリアル通信の場合は送信してすぐに値が返信されるような感じになります。
読み取り結果の様子を写真に取るのを忘れましたのでここまで、ということで。
所感
筆者はMicrochip製品やAVRを好んで使っており、ルネサス製品はあまり好きではなかったのですが、今回、久しぶりにHEWをつかってみて開発ツールは以外に使いやすかったと感じました。
チップの方ですが、xxTinyと付くものは現在のホビーロボットの進化を考えると少々パワー不足のような気がします。HとMが合体してルネサスになったわけですが、H系もM系も同じような機能のxxTinyがあるのでどちらかが収束していくとも考えられます。どうせならもっと高機能なマイコンだったらなあ、と思いつつ今回はここまで。
2008年8月20日
(プログラムは2008年3月に書いたものです)
|