ATtiny26Lを使って、A⁄D変換(アナログ⁄デジタル変換)の実験をしました。入力端子に加えられたアナログ電圧をデジタル値に変換するプログラムです。
下にテスト用のマイコン回路を示します。このページのプログラムはすべてこの回路で実験できます。ATtiny26LにはA⁄D変換用の入力端子が11本ありますが、今回はそのうちADC9という端子(PB6, 9番ピン)に10kΩのボリュームをつないで0〜5VのDC電圧が加えられるようにしました。また、A⁄D変換値の表示用にLCD・液晶ディスプレイを接続します。この部分は「LCD表示のテスト用回路」と同じです。
まずはいちばん基本的なプログラム、入力電圧をデジタル値に変換してそれをそのままLCD画面に表示するというのをやってみます。ATtiny26LのA⁄D変換は10ビットです。これは2の10乗、すなわち1024段階のデジタル値を出力できるという意味です。今回のように電圧を測定する場合は、フルスケールが1024のデジタル電圧計と考えればわかりやすいかと思います。表示は0から1023までになります。
入力電圧はボリュームによって0Vから+5Vまで変化します。下のプログラムを実行して、入力電圧が0Vのとき「ADC=0」、5Vのとき「ADC=1023」と表示されれば成功です。ボリュームのスライダーが中点付近にあるときは、A⁄D変換値(ADC値)は500前後になるはずです。
BASCOM-AVRがインストールされたパソコンで下記リンク「adc1a.bas」をクリックしてファイルをダウンロードすると、BASCOM-AVR IDEが自動的に立ち上がって画面内にプログラムが表示されます。
プログラムファイル adc1a.bas
1 | $regfile = "at26def.dat" | ATtiny26Lを使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | |||
4 | Config Lcdpin=Pin, Db4=Porta.4, Db5=Porta.5 | LCDのピン接続の設定。DB4=PA4, DB5=PA5。 | |
5 | Config Lcdpin=Pin, Db6=Porta.6, Db7=Porta.7 | LCDのピン接続の設定。DB6=PA6, DB7=PA7。 | |
6 | Config Lcdpin=Pin, E=Porta.3, Rs=Porta.2 | LCDのピン接続の設定。E=PA3, RST=PA2。 | |
7 | Config Lcd = 16 * 2 | 16文字×2行表示のLCDを使用する。 | |
8 | Config Adc = Single , Prescaler = Auto | A⁄D変換の設定。 | |
変換方法は「単独変換」、分周値は「自動」。 | |||
9 | |||
10 | Dim A As Word | ワード型変数「A」を使用する。 | |
11 | Cursor Off | カーソルを表示しない。 | |
12 | |||
13 | Do | Doループの範囲ここから。 | |
14 | Start Adc | A⁄D変換を開始する。 | |
15 | A = Getadc(9) | 「ADC9」の入力をA⁄D変換して「A」に代入。 | |
16 | Cls | LCDの表示を消去する。 | |
17 | Lcd "ADC=" ; A | LCDに「ADC=」と変数「A」の値を表示する。 | |
18 | Wait 1 | 1秒間そのまま。 | |
19 | Loop | Doループの範囲ここまで。13行目へ戻る。 | |
20 | |||
21 | End | 終わり。 |
8行目「Config Adc = Single , Prescaler = Auto」はA⁄D変換の基本設定に関するプログラムです。「Config Adc = Single」はA⁄D変換の方法を「単独変換」にするという意味です。もうひとつ、「連続変換」というやり方もあり、その場合は「Config Adc = Free」と書きます。実は両者の違いはまだよくわからないのですが、私が参考にしたプログラム例はみんな「Single」になっていたので、私もそれをまねしました。
「Prescaler = Auto」はA⁄D変換用のクロックに関する設定です。A⁄D変換をする際は50〜200kHzのクロックが必要です。このクロックはマイコンICの基本クロックを適当に分周して使用しますが、そのときの分周比を設定するプログラムです。本来は数字を入力するのですが、「Auto」と書いておけばマイコンが自動的に最適な分周比に調節してくれます。
A⁄D変換の結果を表示するための変数「A」は、最大値が1023なので「Word」型にしました。「Integer」でもいいと思います。「Byte」では範囲が不足します。14行目「Start Adc」でA⁄D変換を開始し、15行目「A = Getadc(9)」でADC9端子のアナログ電圧をデジタル値に変換して変数「A」に代入します。今回はADC9端子をアナログ入力にしたので「Getadc(9)」と書きましたが、もしADC0端子(PA0, 20番ピン)にボリュームがつないであれば、ここは「Getadc(0)」になります。
17行目「Lcd "ADC=" ; A」で、LCD画面に「ADC=」という文字列に続いて変数「A」の値、すなわちデジタル値に変換したADC9の入力電圧(0〜1023の数値)を表示します。18行目に「Wait 1」があるので、ボリュームをぐるぐる回しても表示は1秒毎にしか切り替わりません。ここを「Waitms 100」とかにすればボリュームを早く回しても表示が追随しますが、LCDの表示がチラチラして見づらくなります。
上記のプログラムでは入力電圧が5VのときADC値が「1024」(表示は「1023」ですが)になります。1024÷5=204.8ですから、ADC値を204.8で割ってやれば入力電圧そのものを表示することができます。A⁄D変換の精度(最小単位)は約5mVなので、小数点以下2位(10mVの位)まで表示することにしました。
プログラムファイル adc1b.bas
1 | $regfile = "at26def.dat" | ATtiny26Lを使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | |||
4 | Config Lcdpin=Pin, Db4=Porta.4, Db5=Porta.5 | LCDのピン接続の設定。DB4=PA4, DB5=PA5。 | |
5 | Config Lcdpin=Pin, Db6=Porta.6, Db7=Porta.7 | LCDのピン接続の設定。DB6=PA6, DB7=PA7。 | |
6 | Config Lcdpin=Pin, E=Porta.3, Rs=Porta.2 | LCDのピン接続の設定。E=PA3, RST=PA2。 | |
7 | Config Lcd = 16 * 2 | 16文字×2行表示のLCDを使用する。 | |
8 | Config Adc = Single , Prescaler = Auto | A⁄D変換の設定。 | |
変換方法は「単独変換」、分周値は「自動」。 | |||
9 | |||
10 | Dim A As Word | ワード型変数「A」を使用する。 | |
11 | Dim V1 As Single | シングル型変数「V1」を使用する。 | |
12 | Dim V2 As String * 4 | 4文字の変数「V2」を使用する。 | |
13 | Cursor Off | カーソルを表示しない。 | |
14 | |||
15 | Do | Doループの範囲ここから。 | |
16 | Start Adc | A⁄D変換を開始する。 | |
17 | A = Getadc(9) | 「ADC9」の入力をA⁄D変換して「A」に代入。 | |
18 | V1 = A / 204.8 | 「A÷204.8」の答えを変数「V1」に代入。 | |
19 | V2 = Fusing(v1 , "#.##") | 「V1」の値を「#.##」の形にして変数「V2」に代入。 | |
20 | Cls | LCDの表示を消去する。 | |
21 | Lcd "Vin=" ; V2 ; "V" | LCDに「Vin=」, 変数「V2」の値, 「V」を表示する。 | |
22 | Wait 1 | 1秒間そのまま。 | |
23 | Loop | Doループの範囲ここまで。15行目へ戻る。 | |
24 | |||
25 | End | 終わり。 |
19行目「V2 = Fusing(v1 , "#.##")」は変数「V1」の値の小数点以下第3位を四捨五入して小数点以下第2位までに丸めるプログラムです。変数「V2」は4桁の文字変数です。
このプログラムは、A⁄D変換の基準電圧(=マイコン回路の電源電圧)が5Vぴったりと仮定して書いています。基準電圧が5Vちょうどでない場合は正しい電圧が表示されませんので、18行目「V1 = A / 204.8」を書き換える必要があります。最初に示した回路図の通り、この回路の電源はパソコンのUSBポートから取っています。私のパソコンのUSBポートの電圧を実測したところ、5.01V±0.1%くらいでした。そこで「V1 = A / 204.4」(1024÷5.01=204.4)にしました。これで、テスタで測った電圧とほぼ同じ値を表示するようになりました。
LCDの上の行で電圧値を表示、下の行で電圧値に応じた長さのバーを表示します。バーグラフの表示はサブルーチン「Bargraph」の中でやっています。これは「LCDの表示(その6)」の「lcd6a.bas」と同じです。ADC値が64(電圧で約0.31V)増えるたびにバーが1桁分ずつ右へ伸びていきます。ADC値を16分割で表示するために64で割りますが、ADC値が「1023」のときにバーグラフが16桁目(右端)まで行くように、あらかじめ「1」を加えました。
プログラムファイル adc1c.bas
1 | $regfile = "at26def.dat" | ATtiny26Lを使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | |||
4 | Config Lcdpin=Pin, Db4=Porta.4, Db5=Porta.5 | LCDのピン接続の設定。DB4=PA4, DB5=PA5。 | |
5 | Config Lcdpin=Pin, Db6=Porta.6, Db7=Porta.7 | LCDのピン接続の設定。DB6=PA6, DB7=PA7。 | |
6 | Config Lcdpin=Pin, E=Porta.3, Rs=Porta.2 | LCDのピン接続の設定。E=PA3, RST=PA2。 | |
7 | Config Lcd = 16 * 2 | 16文字×2行表示のLCDを使用する。 | |
8 | Config Adc = Single , Prescaler = Auto | A⁄D変換の設定。 | |
変換方法は「単独変換」、分周値は「自動」。 | |||
9 | |||
10 | Declare Sub Bargraph | サブルーチン「Bargraph」を使用する。 | |
11 | Dim A As Word | ワード型変数「A」を使用する。 | |
12 | Dim V1 As Single | シングル型変数「V1」を使用する。 | |
13 | Dim V2 As String * 4 | 4文字の変数「V2」を使用する。 | |
14 | Deflcdchar 0, 32, 32, 31, 31, 31, 31, 32, 32 | Chr0(表示用バー)の文字データ。 | |
15 | Cursor Off | カーソルを表示しない。 | |
16 | |||
17 | Do | Doループの範囲ここから。 | |
18 | Start Adc | A⁄D変換を開始する。 | |
19 | A = Getadc(9) | 「ADC9」の入力をA⁄D変換して「A」に代入。 | |
20 | V1 = A / 204.8 | 「A÷204.8」の答えを変数「V1」に代入。 | |
21 | V2 = Fusing(v1 , "#.##") | 「V1」の値を「#.##」の形にして変数「V2」に代入。 | |
22 | Cls | LCDの表示を消去する。 | |
23 | Lcd "Vin=" ; V2 ; "V" | LCDに「Vin=」, 変数「V2」の値, 「V」を表示する。 | |
24 | Call Bargraph | サブルーチン「Bargraph」を実行。 | |
25 | Wait 1 | 1秒間そのまま。 | |
26 | Loop | Doループの範囲ここまで。17行目へ戻る。 | |
27 | |||
28 | End | メインプログラム終わり。 | |
29 | |||
30 | Sub Bargraph | サブルーチン「Bargraph」ここから。 | |
31 | Local Bar As Byte | サブルーチン内で変数「Bar」を使用する。 | |
32 | A = A + 1 | 変数「A」に1を加える。 | |
33 | A = A / 64 | 「A」を64で割った値を新たな「A」とする。 | |
34 | Lowerline | LCDの下の行に表示する。 | |
35 | For Bar = 1 To A | Forループここから。 | |
36 | Lcd Chr(0) | LCDにChr(0)を表示。(A個並べる) | |
37 | Next Bar | Forループここまで。 | |
38 | End Sub | サブルーチン「Bargraph」ここまで。 |