講義日: 2016.11.30
今週は、アナログ入力について勉強します。
目次
- I. Basics of Analog Input
- II. Potentiometer
- III. CdS
- IV. Accelerometer
- V. Practical Work
I. Basics of Analog Input
デジタル入力は、端子にある一定以上の電圧がかかっているか、かかっていないかという2状態を入力として識別することでした。アナログ入力は、端子にかかる電圧の変化を複数の状態として識別します。
ここでは例として、部屋の明るさを光センサーで測定している場面を考えましょう。部屋の明るさは、太陽の位置等によって滑らかに変化していきます。光センサーは、その変化を電圧の変化に変換します。この時、光センサーからの出力も滑らかに変化します。しかし、マイコンの中では、受け取った明るさデータをデジタルデータとして保持することになります。音楽データも、写真データも、動画データも、コンピュータの中では全てデジタルデータですよね。それと同じことです。つまり、アナログからデジタルへの変換が必要になるということです。マイコンの中でそれを行なってくれるのが、Analog to Digital Convertor(ADC)と呼ばれるデバイスです。一般的には、ADコンバータと呼ばれます。
マイコンでアナログ入力といったときには、端子から入力されるアナログデータをADコンバータを使ってデジタルデータへ変換して、それを入力として扱うということを意味します。F303K8は12ビットの解像度を持つADコンバータを備えているので、4096段階で電圧の変化を表現します。0.0から1.0の間の数値で考えると、4096の各段階の幅は1.0 / 4096 = 0.000244くらいになります。
Analog Input on F303K8
それでは、実際にF303K8を使って実験してみましょう。まず、以下のような回路を作ります。3.3Vから抵抗を介して直接A5に接続しています。こうすることで、A5に3.3Vかかった時にアナログ入力で得られる値が実験できるはずです。
以下に示すプログラムを転送しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "mbed.h" AnalogIn myInput(A5); Serial pc(USBTX, USBRX); int main() { while(1) { pc.printf("%f\n", myInput.read()); wait(1); } } |
PCに出力を送っていますから、MacのTerminalを開きcatコマンドでシリアルポートを開いてください。すると、以下のようになっているはずです。
ほぼ、1.0ですね。これがアナログピンで計測できる最大の電圧です。3.3Vよりも大きな電圧をかけてはいけません。
それでは、プログラムの説明をしましょう。AnalogIn
は、端子をアナログ入力として使うためのクラスです。アナログピンA5を指定しています。pc.printf()
の中で、myInput.read()
というAnalogIn
のread()
メソッドが呼び出されていますね。このread()
メソッドを呼び出すと、端子の状態を読み取ってくれます。返値は実数で、0.0から1.0の範囲です。F303K8の場合、アナログ入力で読み取れる最大の電圧は3.3Vまでなので、もし、A5に3.3Vがかかっていれば1.0になります。回路を良く見て、実際に3.3VがA5にかかっていることを確認しましょう。
AnalogIn
には、端子の状態を読み取るためのメソッドがread()
の他にもう1つ用意されています。read_u16()
を使うと、端子の状態を16ビット符号なし整数として読み取ります。こちらも試しておきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "mbed.h" AnalogIn myInput(A5); Serial pc(USBTX, USBRX); int main() { while(1) { pc.printf("%d\n", myInput.read_u16()); wait(1); } } |
結果は、以下のとおりです。
16ビット符号なし整数の最大値は65535ですから、おおよそ最大の値が読み取れていることがわかります。
II. Potentiometer
可変抵抗(potentiometer) とは、抵抗値を変えることができる抵抗器です。典型的なものとしては、以下の写真に示すようなボリュームつまみのようなものが挙げられます。
このつまみを、回すことによって、抵抗値を小さくしたり大きくしたりすることができます。通常、可変抵抗には3つの端子があります。両端がVccとGNDで、真ん中の端子をその先の電子部品に繋ぎます。
可変抵抗の原理は、抵抗の分圧則によって説明されます。以下の回路図を見てください。
2つの抵抗はそれぞれxΩ、yΩです。このとき、アナログピン(A5)にかかる電圧はyΩの抵抗にかかる電圧と等しくなります。yΩにかかる電圧は以下のように計算されます。
Vout = (y / x + y) × 3.3v
つまり、xとyの比によってA5の電圧は計算されるわけです。
可変抵抗は、このxとyの比をつまみによって変化させることのできる抵抗です。回路図としては以下のようになります。
mbedをはじめようキットに入っている可変抵抗の抵抗値は10KΩです。この意味は、先ほどの図にあったxとyのうち、yが0Ωになるようにつまみを回転させた時のxの抵抗値が10KΩになりますということです。
それでは、上記の可変抵抗の回路図を参考にして回路を作ってみましょう。つまみを、真ん中辺にすると、31000から33000くらいの値になるはずです。どちから片方に回すと0に近づき、逆に回すと65535に近づいていきます。
III. CdS
光を感知するセンサは、光センサ、あるいはフォトレジスタ(Photoresistor) と呼ばれます。光センサには色々なタイプがありますが、ここではCdS(Cadmium sulfide) を使った光センサを扱います。CdSとは、硫化カドミウムと呼ばれる物質を応用したセンサで、光の強弱によって抵抗値が変わります。CdSは、mbedをはじめようキットには入っていないので、木曜日の演習の時に配ります。
それでは、回路を作りましょう。
CdSは、光に応じて抵抗値が変わる可変抵抗なので、そのままで光センサと呼ぶのは言い過ぎかもしれません。しかし、抵抗の分圧則を応用すれば立派にセンサとして機能します。Cdsの抵抗値は受ける光の強さによって変化しますから、もう1つ抵抗を使って可変抵抗の時と同じ状況を作ります。CdSは、強い光を受けるほどに抵抗値が小さくなっていきます。つまり、この回路ではCdSが受ける光が強くなると、アナログピンにかかる電圧が高くなります。CdSと抵抗の位置を逆にすると、光が強くなるほどアナログピンにかかる電圧は低くなります。
実際に回路を作成して、cdsの上に指を乗せた状態と話した状態でどのように数値が変わるかを確認しましょう。
IV. Accelerometer
加速度センサを使って見ましょう。加速度センサ(Accelerometer)とは、加速度を数値化して教えてくれるセンサです。加速度とは、速度の変化率のことで、大雑把に言えば、どのくらいの勢いでどちらの方向に動いたかということです。単位はm/s2、あるいはGが使われます。X m/s2は、1秒間にX m/sの速度の変化があることを意味します。Gは、重力加速度に基づく単位です。地表にある物体は、重力によって地球の中心へと引っ張られています。その力が1Gです。地表にある物体は加速していないので少し奇妙に感じますが、加速度センサはそれにかかっている力を検出するものなので、この1Gを常に感知します。
mbedをはじめようキットの中には、ADXL337という加速度センサが入っています。
これは、3軸加速度センサというもので、x軸、y軸、z軸の3軸方向に+-3Gまでの加速度が測れます。加速度センサの脇にあるものは、ピンヘッダというもので、加速度センサをブレッドボードに差し込めるようにするものです。以下のように組み付けて、上から半田付けします。
それでは、以下のような回路を組んで見ましょう。
ADXL337からのデータは、X、Y、Zと印字されたピンから出力されます。まずは、それらをそのまま見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include "mbed.h" AnalogIn xaxis(A0); AnalogIn yaxis(A1); AnalogIn zaxis(A2); Serial pc(USBTX, USBRX); int main() { wait(1); while(1) { pc.printf("X=%d\n", xaxis.read_u16()); pc.printf("Y=%d\n", yaxis.read_u16()); pc.printf("Z=%d\n", zaxis.read_u16()); wait(0.5); } } |
出力は、以下のようになりました。
x軸とy軸の値は、それぞれ31500くらい。z軸だけ39700くらいです。この値が何を表しているのかを考えてみましょう。この加速度センサは+-3Gまで計れます。ということは、理論的には0から65535を6等分した値、すなわち10922.5が1G分ということになります。ということは以下のようになっているはずですね。
z軸の値には1Gがかかっていて、x軸とy軸は0Gがかかっているはずです。だいぶ値がずれていますね。これには色々な理由が考えられます。データシートを見ると、もともと個体によってだいぶズレがあることが書いてあります。また、温度によっても値はだいぶ変わってきます。この手の加速度センサで正確なGを測ることは難しいです。しかし、ある程度の傾きを検出することなどには使えます。
それでは、この加速度センサを傾けて見ます。基板上に印字されているx軸の矢印が上を向くように傾けました。今度はy軸とz軸が、それぞれ31000から32000くらいで、x軸だけ38000くらいになりました。
この実験から想像されることは、1Gがかかっている時には38000から40000くらい、0Gの時には31000から32000くらいの値が帰ってくるということです。
ADXLから出力される値が少し使いにくいので、ちょっと加工しましょう。0Gの時に0,
1Gの時に100くらいの値が得られるように調整してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include "mbed.h" AnalogIn xaxis(A0); AnalogIn yaxis(A1); AnalogIn zaxis(A2); Serial pc(USBTX, USBRX); int adjustInput(int, char); int main() { wait(1); int x, y , z; while(1) { x = adjustInput(xaxis.read_u16(), 'x'); pc.printf("X=%d\n", x); y = adjustInput(yaxis.read_u16(), 'y'); pc.printf("Y=%d\n", y); z = adjustInput(zaxis.read_u16(), 'z'); pc.printf("Z=%d\n", z); wait(0.5); } } int adjustInput(int n, char c) { int xymin = 31500; int xymax = 38000; int zmin = 32500; int zmax = 39700; if(c == 'x' || c == 'y') { n = (n - xymin) / ((xymax - xymin) / 100); } else if(c == 'z') { n = (n - zmin) / ((zmax - zmin) / 100); } return n; } |
出力は以下のようになりました。
このくらいだと使いやすそうですね。加速度センサを振ってみると、だいたい-200から+200くらいの範囲で値が変わります。
adjustInput()関数のxymin、xymax、zmin、zmaxは、加速度センサの個体によって変わります。実験して値を決める必要があります。
V. Practical Work
今日は、全て個人で実験を行います。実験に入る前に、ADXL337にピンヘッダを半田付けしてください。
実験1. 可変抵抗でLEDの明るさコントロールする
可変抵抗のつまみを回すと、LEDの光が明るくなったり暗くなったりするようにして見ましょう。LEDは、PWMで明るさ調整を行います。
実験2. CdSを使ってLEDをコントロールする
CdSを使って、手をかざすとLEDが点灯し、手を退けるとLEDが消灯するようにして見ましょう。LEDの明るさを調整する必要はありません。
実験3. 加速度センサを使ってみる
傾きに応じてLEDの光り方が変わるようにしてみましょう。以下の動画と同じような動きをするものを作ってください。