はじめに
ここではセンサー入力とADコンバータについて説明します。
※このページで紹介する内容はあくまでも一例です。個別の作成のご相談ご質問はお答えできませんのでご了承下さい。このページと同じ内容についてのご質問についてはロボット掲示板にてお願いいたします。
※以下の情報は2007年12月現在のものです。ご注意ください。
※このページではC言語の基本的な部分を理解している方向けに書いてあります。また、何回かMPLABの操作を行った方を対象にしています。それ以外の方はまず基本編を読んで下さい。
センサーの出力方式
ロボットを作る上で欠かせないのがセンサーです。センサーにはいろいろな種類がありますが、マイコンでセンサー入力を行う場合にはまずその出力方式が気になるところです。
<センサー素子>
センサーを探して、目的のものを見つけた場合、そのセンサーが素子の状態だったとします。この時はマイコンと直接接続できるものなのかを確認する必要があります。ほとんどの場合は出力が微弱なためにマイコンとは直接接続することはできず、オペアンプなどで増幅回路を構成して信号を増幅する必要があります。
<シリアル出力の素子>
センサーがモジュール(基板上に回路が形成されている状態)の場合、シリアル出力されているというセンサーがあります。この場合、動作電圧が同じであれば直接UARTに接続することができます。A33Fの場合はUART1はUSBシリアルでPC接続用となっておりますが、UART2が自由に使えます。但し、一般的に入手できるセンサーモジュールは5V電源が多いので気をつけてください。A33Fは3.3V動作です。この場合、3.3Vと5Vを変換するICがありますので、それを使って電圧変換回路を作る必要があります。
尚、浅草ギ研のロボット神経システムシリーズと、赤外線距離センサーIR600はシリアル出力のセンサーですが、これらも動作電圧は5VなのでA33Fには直結できません。
<パルス出力型のセンサー>
センサーによっては出力がパルス状になっており、そのパルス幅の長さがセンサー値というものもあります。浅草ギ研では2軸加速度センサーや超音波距離センサーがそれにあたります。しかし、これらも動作電圧は5Vなので直接接続することはできません。
パルス出力型のセンサーの値を読む場合は、接続した端子の電圧のHIGH/LOWを調べて、状態をTIMERで計測して値を求めます。
<電圧出力型のセンサー>
センサーによっては出力が電圧値になっているものもあります。浅草ギ研では3軸加速度センサー、感圧センサー、近接センサーがそれにあたります。これらは3.3Vでも動作するのでA33Fに直結可能です。また、市販のその他のセンサーでも動作電圧が5Vであってもセンサー出力が3V以下しか出ないものなどもあり、そのようなものも接続できます。
裏ワザですが、距離計測にシャープのGP2D12がよく使われています。これは安価だし、ロボットパーツを売っているところなら大抵のショップで入手できます。これは本当は5V動作なのですが3.3Vでも動きます。
電圧を測定する場合にはマイコンのADC(アナログデジタルコンバータ)機能を使います。
AD(アナログ/デジタル)変換
マイコンなどで、電圧変化のアナログ量をデジタル数値に変えることをAD変換と言います。AD変換を行う装置をADC(ADコンバータ)と言います。性能の目安としては
1)サンプリングレート : どれだけの速度(間隔)で電圧を数値に変えられるか。一瞬では測定できない。
2)分解能 : どれだけ小さい単位の電圧変化を測定できるか。
があります。
上限値と加減値の電圧は設定できますが、通常は動作電圧の範囲内になります。
電圧を数値に変換する方法にはいろいろあります。下に代表的な方式と性能を示します。dsPIC33FのADCは逐次(ちくじ)比較型です。
方式 |
サンプリングレート(Hz) |
分解能(bit) |
並列比較型 |
10G - 10M |
12 - 6 |
パイプライン型 |
150M - 10M |
14 - 8 |
逐次比較型 |
1M - 10k |
16 - 8 |
デルタシグマ型 |
100k - 100 |
24 - 18 |
二重積分型 |
1k - 10 |
22 - 12 |
サンプリングレートは、例えば1MHzという仕様だったら、1秒間に100万回の測定ができるということになります。上のグラフで、測定間隔が狭いということは元の波形をより忠実に再現できる、つまりアナログ量をより忠実に取得(サンプリング)できるということになります。
1MHzということは1uSに相当するので、1個のデータを取る場合は1uSしかかからないということになります。例えば二重積分型で1kHzのサンプリングレートのADCだと、1個のデータを取るのに最低1mSはかかることになります。
dsPIC33FのADコンバータ
<A33FのADCポート>
センサーを接続する場合、センサーモジュールにも電源を供給する必要がありますが、A33Fでは700mAまでの電流を外部に供給できる3.3V電源が付いており、各センサー端子の周りに電源端子も配置していますので、センサー側が3.3V動作するものであればA33Fから電源を供給することができます。
端子は2mmピッチですので2mmピッチのピンヘッダを取り付けられます(浅草ギ研で販売)。また、浅草ギ研の電圧出力型センサーモジュールのいくつかは同じく2mmピッチなので、専用のセンサーケーブル(浅草ギ研で販売)を使って接続することができます。また、京商のロボット「マノイ」のオプションのセンサー類も同じ端子配列、同じピン間隔になっていますので直接接続することができます。
<dsPIC33FのADCの仕様>
dsPIC33FシリーズのADCは、「10bit、1MHz」か「12bit、500kHz」のどちらかを設定で選択できます。その中でもA33Fで使用しているdsPIC33FJ256GP710はADCの入力端子が32個付いています。
dsPIC33Fの使い方は、基本的にはdsPIC30Fリファレンスマニュアルの17章と18章に書いてあります。これは30Fシリーズ用なので、33F固有の情報はdsPIC33Fデータシートの22章を参照します。
構造は次のようになっています。他のマイコンも大体同じですが、端子は沢山ありますがAD変換を実際に行う回路は1つか2つ(dsPIC33Fは2つ)しかなく、測定する度に端子を切り替えてから測定します。つまり、測定の時は端子を指定する作業が必要になります。
VREF+とVREF-端子は測定電圧の上限と下限を設定します。ここにつないだ電圧の間を12bitもしくは10bitに分解します。この端子は使わなくてもOKで、設定により3.3V電源電圧を上限に、0Vを下限に、又は各VREF+やVREF-と組み合わせて設定することができます。
ADCはADC1とADC2の2つがあり、それぞれ32個の端子につながっています。AD変換は時間がかかるのと、設定を変えて測定した場合もあるので、2つあった方が便利です。2つは同じように使えます。
<ADC用のSFR(特殊レジスタ)>
ADC1とADC2がありますが、どちらも使い方は同じです。以下、ADC1の場合を説明しますが、ADC2も使う場合は番号だけ変えると同じ動きになります。
ADCを使うのに次のSFRがあります。
ADPCFGHとADPCFGL : 32個ある端子のどれをADCとして使うかを設定。
AD1CON1 : ADCの基本的な設定
AS1CON2 : 電圧の上限下限設定とDMA関連設定
AD1CON3 : サンプルビット設定
AD1CON4 : DMAのバッファ設定
ADC1BUF0〜F : 測定した結果が入るレジスタです。バッファ(一時記憶装置)として16個あります。
AD1CHS0 : 測定する端子を選択します。
AD1CSSHとAD1CSSL : 一度に複数の端子を読む(スキャン)場合、どの端子をスキャンするかを選択。
DMAは、ダイレクトメモリーアクセスという機能で、CPUの動作とは別に特殊機能で得た値をメモリに書き込むもので、ADCとDMAを組み合わせればCPUを止めることなく、取得した値がメモリに蓄積されていきます。これは例えば音声データやセンサーデータのログを高速に取るときに有効です。(ここでは詳しく説明しませんのでデータシートを参照して下さい。)
流れとしては、
1) あらかじめADPCFGとAD1CONで設定をしておき、
2) 読むときにAD1CHS0で端子を指定し、
3) 開始(AD1CONのSAMPビットを1にするとスタート)させ、
4) 終了を待つ(AD1CONのDONEビットが0になると終了)
という手順になります。
以下、各レジスタの説明をしますが、ADCはSFRが沢山あってややこしいので、次の節のサンプルプログラムを見た方が必要な情報だけあってわかりやすいかもしれません。
こまかい話は飛ばして、サンプルプログラムを見る方はこちらへ
<ADPCFGHとADPCFGL>
これは各端子をADCの入力端子として使う場合は1にします。例えばAN0端子をADC入力とする場合はAD1PCFGLのPCFG0ビットを0にします。初期設定は全部0になっていますので、逆にADCとして使いたくない場合は1に設定する必要があります。
<AD1CON1>
ADCの設定をします。
以下、重要な部分を説明します。
ADON : dsPIC33Fの1でADC機能を有効にします。ADPCFGで設定しただけでは有効になりません。
FORM : 結果の数値の形式を設定します。詳しくはdsPIC30Fリファレンスの17.17に書いてあります。
SSRC : ADCのサンプリングはある条件により開始されますが、その条件を設定します。特になにも無い場合は111の自動変換開始がよいと思います。
SAMP : ここを1にすると測定開始を指示した状態になります。実際の測定開始はSSRCで設定した条件に合ったときに開始されます。
DONE : サンプリングが終了するとここが1になります。ということで、SAMPを1にした後、DONEが1になるまで待つ必要があります。サンプリングが終了したらバッファアに値が書き込まれます。DONEは自動で0にならないので、終了後にここをに0を書き込む必要があります。
<AS1CON2>
VCFG : 表のような設定になります。A33Fの場合、AVDDは3.3V、AVSSは0Vです。ADREF+が上限の電圧値、ADREF−が下限の電圧値となります。
CHPS : 10bitモードの場合には、3つあるサンプルホールドを使えます。サンプルホールドは測定した瞬間のアナログ電圧をその電圧値のまま保持するものです。12bit動作ではこれは使えません。詳しくはdsPIC30Fリファレンスの17.4に記述がありますのでそちらを参照してください。
その他はDMAに関する設定などです。詳しくはdsPIC30Fリファレンスを参照してください。
<AD1CON3>
ADCは動作した瞬間に電圧が数値に変換されるのではなく、ある手順をふんで変換され、それには数クロック必要となります。変換には大きく「サンプル期間」と「変換期間」に別れ、動作スピードなどによって何クロック使うかや変換のタイミングを決める必要があります。これについてはdsPIC30Fリファレンスの17.4、17.7、17.12、17.15、17.16に記述があります。かなり長いので、読むのが面倒な場合は次の節のサンプルプログラムが標準的な設定ですのでそちらを参照してください。なお、リファレンスで動作クロックを表すFcyというのが出てきますが、A33Fで今までのページで説明した設定の場合(内蔵クロックで最速)はFcy=36.85になります。次の節のプログラム例の設定も同じです。
<AD1CON4>
DMAを使う場合のバッファの大きさを設定します。詳しくはdsPIC30Fリファレンスを参照願います。
<ADC1BUF0〜F>
変換結果が格納されるレジスタで、ここから結果を読むことができます。これらのレジスタは読み取り専用となっています。
通常、結果はADCBUF0に格納されますが、複数同時サンプリングや、逐次サンプリング(一回の命令で数個をいっぺんに読む)の場合はその他のADBUF1〜Fに値が一時格納されます。詳しくはdsPIC30Fリファレンスの17章(17.5を中心にかいてある)を参照してください。
<AD1CHS0>
ADC1は32個の端子に対して1個しかありませんので、CH0SAで読み取る端子を設定します。その他ですが、端子を切り替える装置をマルチプレクサと言い、MUXで表しますが、どうやらMUXがAとBと2つあるようです。しかし、そのあたりの詳しい記述が見当たらないのでよくわかりませんでした。とりあえず初期設定でOKです。(おそらく、dsPIC33FとdsPIC30Fではそのあたりの名称などが違うが、細かい動作については30Fの方にかいてあるので検索できなかったのだと思います。両方をすみずみまで読めばわかるかも)
<AD1CSSHとAD1CSSL>
一回の指令で複数の端子を読み取るときに、どの端子を読み取るかを設定するものです。
センサーからの電圧入力を読み取ってみる
実際に指定した端子の電圧を読んでみるプログラムを作ってみました。(右クリックで対象を保存)
ADC.c
テストとして、浅草ギ研で販売している感圧センサーAS−FORCEを接続しました。3.3V動作で、コネクタもA33Fと同じなので、センサーケーブルで直結できます。
今回は、ADCで読み込んだ値をUSBシリアルを経由してPCのハイパーターミナルに表示させてみました。PCへの表示についてはこちらのページにやり方が書いてあります。printf関数を使っていますので、プロジェクトを作った後、「Project」->「Build
Optins」->「Project」->「MPLAB LINK30」 の Heap size を設定するのを忘れないで下さい(適当に128とか)。
ではプログラムの説明をします。
今回は設定が複雑なので、設定部を関数にしました。まず、行37,38で全端子をADCにしています。ここは初期設定が全部0なので不要ですが一応参考のために入れておきました。あとはコメントの通りです。設定としてはスキャンなしで一回に一つの端子から読み取るもので、12bitモードになっています。よって結果の数値はADCBUF0に12bit値で入ります(0〜4095の範囲)。
行43、44はサンプルタイムの設定ですが、とくになにもなければこの設定でOKです。気になる方はdsPIC30Fリファレンスの17章を読んでください。
ADC読み込みも関数化しました。引数に端子番号(AN0なら0)を入れると読み取った値を返します。まず、行53のようにAD1CHS0レジスタで読み取る端子を指定します。その後、AD1CON1のSAMPを1にすると自動的に読み取りが開始されます。読み取りには数クロックかかります。読み取りが終了するとAD1CON1レジスタのDONEが1になりますのでそれを行55のように監視しています。この部分は本当はDONEが1にならなかったら暴走となるので本当はタイムアウトを設けた方がよいのですが、実験中は一度もコケたことはありませんでした。DONEは終了しても自動的にクリア(0)にならないので、行56のように0を書き込んでクリアする必要があります。結果はADC1BUF0に書き込まれます。
メインはこのようになっています。上の関数を呼び出しているだけなのであまりむずかしくないかと。
実行結果はこのように値が1秒おきに表示されました。感圧センサーAS−FORCEは、通常時に電源の半分の値の電圧を出力させ、センサー部を押すと電圧が下がっていきます。2030の値は、12bitの最大値4095の約半分です。(ゴム部があるので多少圧力が加わっている)
圧力を加えるとこのように値が下がっていきます。
という感じでセンサーの電圧出力を数値に変えることができます。
おわりに
次はシリアル通信について説明します。
2007年12月5日
|