アナログ/デジタル変換機能
考え方など基本は同じですので、まず Tekurobo工作室
A/D変換機能を使う を見てください
このA/D変換については 3048Fと3664Fはほとんど同じようです、レジスタの名前が違う程度でそのまま上記HPを読んであてはめれば出来るでしょう。
●簡単にA/D変換とは?
マイコンでいうA/D変換とはアナログ電圧をデジタルの数字に変換することです。 例えば 5Vを5段階にA/D変換すると
電圧(V) | 0-1(V) | 1-2(V) | 2-3(V) | 3-4(V) | 4-5(V) |
A/D変換値 | 0 | 1 | 2 | 3 | 4 |
これで一応 A/D変換です。
これでは荒いので、これを今度は10段階に分けると もっと細かくなります。さらに20、30段階と細かくしていくことが出来ます。
1023段階まで細かくできることになります。5Vなら0.005V程度まで細かく割れることになります。この3664Fでは分解能は10Bitとなっていますから、自動的に1023段階まで小分けされた値になります。
主な特長
- 分解能10Bit -- 1023段階
- 入力チャンネルがこのH8---TINY3664DIP版では4チャンネルです。
- 割り込み発生が可能 --GDL関数ではint_ad (void) になっています。
- 外部信号でA/D変換させられる
- 単一モード、スキャンモード→1-4CHまで連続変換の2種類
A/D変換
A/D変換の方法は明解です。
- 入力端子に電圧を入力する ( AN0~ )
- A/D変換しろの命令をする ( ADCSR.ADST→1 )
↓変換が終わると - A/D変換終了フラグが1になり 終わったことがわかる
(ADCSR.ADF→1 と同時に レジスタにA/D変換結果が入る
( 結果→ADDRA~D )
↓ - レジスタのA/D変換結果を読めばA/D変換結果がわかる (ADDRA~D)
設定
レジスタ設定
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
名称 | ADF | ADIE | ADST | SCAN | CKS | CH2 | CH1 | CH0 |
1:変換終了 の合図 |
1 : 割り込みする 0 : 割り込みなし |
A/D変換しろの命令 | 0 : 単一モード 1 : スキャンモード |
1 :高速変換 0 :低速変換 |
チャンネル選択 下記 |
ADCSR.SCAN
=1 : 単一モード 1ピンだけを変換
0 : スキャンモード 選んだピン全部を変換し、各結果レジスタへいれる
A/D変換しろの命令 をする ( ADCSR.ADST→1 )
* スキャンモードではA/D変換しろの命令はいったんスタートさせるとクリアさせない限りずっと A/D変換をし続けます。
*単一モードではA/D変換終了すると自動的にクリアされる
入力端子は電圧を入力し、A/D変換する入力端子(ピン)を選択
チャンネル選択
SCAN=0 のとき | |||
2 | 1 | 0 | |
CH2 | CH1 | CH0 | 入力端子 |
0 | 0 | 0 | AN0 |
0 | 0 | 1 | AN1 |
0 | 1 | 0 | AN2 |
0 | 1 | 1 | AN3 |
SCAN=1 のとき | |||
2 | 1 | 0 | |
CH2 | CH1 | CH0 | 入力端子 |
0 | 0 | 0 | AN0 |
0 | 0 | 1 | AN0-AN1 |
0 | 1 | 0 | AN0-AN2 |
0 | 1 | 1 | AN0-AN3 |
ADCSR.ADIE → 1 割り込みするにしたときは
GDL関数ではvoid int_ad (void) 関数が呼び出されます。
A/D変換結果が入るレジスタ 10Bit
各入力端子は 次のレジスタに結果が入る
- 入力端子AN0 → ADDRA
- 入力端子AN2 → ADDRB
- 入力端子AN3 → ADDRC
- 入力端子AN4 → ADDRD
結果は6-15Bitに入ります。それ以外は関係ない部分です。
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - - - - - - A/D変換結果が入る 無効な部分
ADCR
通常、A/D変換開始は ADCSR.ADST→1 でしますが、
ADCRは外部信号からA/D変換開始をさせたいときに使用します。
(その信号入力端子はADTRG。)
実際の設定
ここでは1入力端子だけに入力することでやってみます。入力は AN0に入力します。
AN0に可変抵抗(ボリューム)をつなぎ、ボリュームを回転させるとAN0に入力させる電圧がかわるのでそれをA/D変換します。
ADCSR
Bit 7 6 5 4 3 2 1 0 名称 ADF ADIE ADST SCAN CKS CH2 CH1 CH0 0 0 1 1 1 0 0 0
AD.ADCSR.BYTE= 0x38 (0011 1000)
回路図
AN0に可変抵抗(ボリューム)をつなぎ、ボリュームを回転させるとAN0に入力する電圧がかわるのでそれをA/D変換します。
ポート8を使用し、LEDが点灯する回路です。
入力電圧の変更には可変抵抗を用いました。その5V電源には精度は必要ないので、ボードの5V電圧を使い、そのまま分圧を入力しています。
可変抵抗について
可変抵抗は両端をそれぞれ電源(5V)とGNDにつなぎ、真ん中の端子をAN0に接続します。
両端はどちらをGNDにつないでもかまいません(抵抗を増減させるのに回転させる方向が逆になるだけです。)
これで回路図のように、たとえば、ボリュームを20%回すと、8割、2割と仕切られた抵抗値になり、AN0にその電圧が入ります。
ボリュームを回しながら
①真ん中端子-右端子
②真ん中端子-左端子 間の電圧をテスターで測ってみると可変抵抗の働きがよくわかるでしょう。
(回して①の抵抗が増えれば、もう一方の②の抵抗が減ります、両方を足すとVR値-ここでは10KΩになります)
プログラム
ADscan
#include<3664.h>
void main()
{
IO.PCR8=0x00F; /* 出力に設定 0000 1111 */
AD.ADCSR.BYTE = 0x38; /* 0011 1000*/
/* A/D変換開始 */
/* スキャンモード */
/* 高速変換 */
/* AN0 */
while(1){
while(AD.ADCSR.BIT.ADF==0); /* 変換結果がでるまで待つ */
IO.PDR8.BYTE=(AD.ADDRA>>13); /*ビットシフト(13ずらす) 上位3桁 #15-#13 をPDR8に入れる
下位ビットの精度は必要ないので
AD.ADDRB -- #15 #14 #13 → #2 #1 #0 → PDR8 -- #2 #1 #0
*/
AD.ADCSR.BIT.ADF=0; /* 終了フラグを0に戻す */
}
}
あらかじめ A/D変換開始設定にしてあるので、プログラム実行すると開始されます。
A/D変換が終わると、AD.ADCSR.BIT.ADF が 1 になることから、 while(AD.ADCSR.BIT.ADF==0); で変換結果がでるのを待ちます。
A/D変換が終わると、AD.ADDRA に結果が収納されます。
細かい値は必要ないので、ビットシフト(AD.ADDRA>>13)で13ビットずらし、上の桁3ビットだけを使用し3つのLEDに出力しています。(ここではLED3つだけ使用)
A/D変換はものすごく細かい変化でもマジメに数値に変換します。
ビットシフトで下の桁を捨てるのは、つまみを回した細かい変化
100→128 のような小さな変化を切り捨てるため下位のビットは切り捨て
100→ 200 のような 上の桁の大きな変化値だけを得るためです。
それをそのまま LEDをつないだポートのレジスタに入れています。
つまみを回していくと点灯するLEDの数も変化していきます。
A/D変換値は2進数なので、それをそのままLEDのレジスタにほり込むと、
001→010→011
と2進数の増え方どおりにLEDも点灯します。
実行結果
つまみを回していくと点灯するLEDの数も増えていきます。
プログラム1では ボリュームをゆっくり回していくと、A/D変換値がそのまま入力されているので、LEDの変化は 000→001→010→011→100
と2進数の増え方を見ているように点灯します。(2進数の学習にいいかも。。)
これではあまりきれいでないので、プログラム2で
ボリュームをゆっくり回していくと、点灯するLEDの数が増えていくようにしてみました。
今回は2進数でA/D変換で5Vを2進数3桁(0-8)に分割したことになります。
LEDが点灯する電圧の区切りを測ると約0.6Vごとに変化していました。約5V/8ですね。
続いて、少し変えてボリュームを回すにしたがって点灯LED数も増えるように、001→011→111 となるよう、こではわかりやすくCASEで分岐させて、それをしました。今度はLED4本使用し、出力します。
A/D変換 プログラム2
スキャンモード LED順点灯
ADscanCASE
#include<3664.h>
void main()
{
int ledp=0 ;
IO.PCR8=0x00F; /* 出力に設定 0000 1111 */
AD.ADCSR.BYTE = 0x38; /* 0011 1000*/
/* A/D変換開始 */
/* スキャンモード */
/* 高速変換 */
/* AN0 */
while(1){
while(AD.ADCSR.BIT.ADF==0); /* 変換結果がでるまで待つ */
ledp=(int)(AD.ADDRA>>13); /*ビットシフト(13ずらす) 上位3桁 #15-#13 をPDR8に入れる
下位ビットの精度は必要ないので
AD.ADDRB -- #15 #14 #13 → #2 #1 #0 → PDR8 -- #2 #1 #0
*/
switch(ledp){
case 0 : IO.PDR8.BYTE=0x00; break; /* 0000 0000 */
case 1 : IO.PDR8.BYTE=0x01; break; /* 0000 0001 */
case 3 : IO.PDR8.BYTE=0x03; break; /* 0000 0011 */
case 5 : IO.PDR8.BYTE=0x07; break; /* 0000 0111 */
case 7 : IO.PDR8.BYTE=0x0F; break; /* 0000 1111 */
}
AD.ADCSR.BIT.ADF=0; /* 終了フラグを0に戻す */
}
}
A/D変換結果のAD.ADDRA もわかりやすく変数にいれてその値によりCASE文で分岐し、LEDを点灯させます。
A/D変換結果のAD.ADDRA はプログラム1では2進数として扱いましたが、ここでは明示的にintに変換してledp変数に入れました。(通常、あえてする必要はない処理です)
10進数と思って扱っています。
実行結果2
ボリュームを回すと、点灯LEDが増えていきます。
アナログ的で、操作がLEDに反映されて楽しいですね。流れるように増えていくLEDはちょっとした光モノ工作になりました。
明るさがアナログ変化する??
プログラム1、2を比較してみると、プログラム1では、アナログのように明るさが変化する
ボリュームを回して、LEDが点灯するかどうかの境い目のあたりにすると、LEDの明るさが変わりました。境い目のあたりでボリュームを微妙に回すと、LEDの明るさがアナログのように多少変化します。
デジタル値なのでいきなり、点灯、消灯 のどちらかのハズなのですが、徐々に明るくなるのは不思議です。
これは、アナログ入力回路に精度がないので電圧が変動しているからでしょうね。、A/D変換値が境い目では1,0と時々揺れて、1になったりならなかったりとPWM制御風になって、結果、電圧変化しているようになっているからでしょう。
プログラム2では境い目でいくら微妙に回していっても、 0、1どちらかなので、境い目で明るさが変化することのないデジタルになっています。
- twtter
- google+
- hatena