Arduinoで遊ぶページ

Arduinoで遊んだ結果を残すページです。
garretlab
analogRead()

analogRead()

概要

analogRead()は、アナログ‐デジタル(AD)変換器を使って、アナログピンから値を読み取ります。

Arduino Unoは、10ビットのAD変換機を6個持っています。analogRead()では、ADMUXとADCSRA、ADCL、ADCHという4つのレジスタを利用します。

ADMUX

ADMUX(ADC Multiplexer Selection Register)は、参照電圧の設定と出力値の形式(ビットを左詰めにするか右詰めにするか)、チャネル(アナログピン)の選択を制御するレジスタです。

ADMUX
ビット 7 6 5 4 3 2 1 0
名称 REFS1 REFS0 ADLAR - MUX3 MUX2 MUX1 MUX0

REFS0とREFS1は、参照電圧の設定を行います。組み合わせにより意味が異なります。

REFS1 REFS0 意味 analogReference()の引数
0 0 AREFピンに与えた電圧 EXTERNAL(0)
0 1 デフォルトの参照電圧(Arduino Unoの場合は5V) DEFAULT(1)
1 0 予約(未使用) -
1 1 内蔵の参照電圧(Arduino Unoの場合は1.1V) INTERNAL(3)

ADLARは、読み取った値を格納するレジスタ(ADCLとADCH)の値が、左詰め(1)か右詰め(0)かを指定します。Arduinoでは、右詰め(0)固定です。

MUX0からMUX3はアナログピンの選択のためのビットです。4つのレジスタの値の組み合わせによりピンを選択します。Arduino Unoでは、以下の組み合わせが有効です。

MUX3 MUX2 MUX1 MUX0 アナログピン
0 0 0 0 0
0 0 0 1 1
0 0 1 0 2
0 0 1 1 3
0 1 0 0 4
0 1 0 1 5
0 1 1 0 6

MUX3...MUX0=1000を選択すれば、内蔵温度センサから値を読むことができますが、この機能はanalogRead()では利用できません。詳細は、内蔵温度センサの実験のページをご覧ください。

ADCSRA

ADCSRA(ADC Control and Status Register A)は、AD変換器の制御を行うためのレジスタです。

ADCSRA
ビット 7 6 5 4 3 2 1 0
名称 ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0

ADEN(ADC Enable)を1に設定すると、AD変換を有効にします。AD変換を有効にする処理は、main()関数から呼ばれるinit()という関数の中で行なわれています。

ADSC(ADC Start Conversion)を1にするとAD変換を開始します。AD変換が行われているときはこのビットは1で、AD変換が終了すると0になります。

ADATE(ADC Auto Trigger Enable)は、AD変換の自動起動を制御します。Arduinoでは使われていないようです。

ADIF(ADC Interrupt Flag)とADIE(ADC Interrupt Enable)は、割り込みに関する制御を行います。Arduinoでは使われていないようです。

ADPS(ADC Prescaler Select Bits)2とADPS1、ADPS0は、クロックの分周比を設定するためのビットで、AD変換の際のクロック数を決めます。組み合わせの意味は以下の通りです。

ADPS2 ADPS1 ADPS0 分周比
0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128

AD変換で10ビットの精度を得るためには、50kHz~200kHzのクロックを供給する必要があります。精度を落としていいのであれば、200kHZよりも高い周波数でもいいようです。Arduino Unoでは、init()の中で、ADPSを0b111、すなわち、分周比を128に設定しています。Arduinoで使っているクロックの周波数は16MHzなので、結果として、16MHz/128 = 125kHzとなります。また、AD変換には13クロックを要するため、AD変換を行うのに必要な時間は、1/125kHz*13 = 0.000104秒 = 104マイクロ秒となります。

ADCH、ADCL

ADCHとADCLは、AD変換の結果を格納するレジスタです。ADMUXレジスタのADLARビットの値により、結果の格納方法が異なります。Arduinoでは、ADLARビットは0と設定するため、10ビットの変換結果の上位2ビットがADCHに、下位8ビットがADCLに格納されます。

analogRead()のリファレンスはこちらをご覧ください。

ソースコード

analogRead()は、hardware/arduino/avr/cores/arduino/wiring_analog.c に定義されています。以下に全ソースコードを示します。Arduino Unoの場合に適用される部分だけを抜粋しています。実際には#if によりさまざまなチップに対応しています。

int analogRead(uint8_t pin)
{
	uint8_t low, high;

	if (pin >= 14) pin -= 14; // allow for channel or pin numbers

	// set the analog reference (high two bits of ADMUX) and select the
	// channel (low 4 bits).  this also sets ADLAR (left-adjust result)
	// to 0 (the default).
	ADMUX = (analog_reference << 6) | (pin & 0x07);

	// without a delay, we seem to read from the wrong channel
	//delay(1);

	// start the conversion
	sbi(ADCSRA, ADSC);

	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));

	// we have to read ADCL first; doing so locks both ADCL
	// and ADCH until ADCH is read.  reading ADCL second would
	// cause the results of each conversion to be discarded,
	// as ADCL and ADCH would be locked when it completed.
	low  = ADCL;
	high = ADCH;

	// combine the two bytes
	return (high << 8) | low;
}
            

入力はpinで、uint8_t型の変数です。出力はintで、AD変換の結果の10ビットを返します。

まず、pinの番号の変換を行います。

	if (pin >= 14) pin -= 14; // allow for channel or pin numbers

例えば、アナログピンの0番は、0という数値かA0という変数で表します。Arduino Unoでは、A0は14、A1は15というように定義されています(hardware/arduino/avr/variants/standard/pins_arduino.h)。このため、最初にpinが14以上の場合はA0などの表記が使われたとみなし、14を引く処理をしていると思われます。A0が14と定義されているのは、アナログピンをデジタルピンとして使うこともでき、アナログピンの0番がデジタルピンの14番として利用できるためです。

次に、ADMUXレジスタを設定します。

	ADMUX = (analog_reference << 6) | (pin & 0x07);

analog_referenceはADMUXのREFS1(ビット7)とREFS0(ビット6)に設定されます。pinは、0x07(二進数では0b00000111)と論理積をとり、これらを論理和で連結します。ADLARは明示して設定はしていませんが、0が設定されます。

AD変換を開始します。

	// start the conversion
	sbi(ADCSRA, ADSC);

sbi()は、第1引数で指定したアドレスの内容の第2引数ビットを1に設定するマクロです。ADCSRAのADSCビットをセットすることでAD変換が開始されます。

AD変換が終了するのを待ちます。

	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));

bit_is_set()は、第1引数の第2引数ビット目が1かどうかを調べるマクロです。ADCSRAのADSCが1の間はループで待ちます。0になればAD変換完了です。

AD変換結果が格納されているADCLとADCHを読み取り、16ビット(上位6ビットは0)の数値に変換して、リターンします。

	// we have to read ADCL first; doing so locks both ADCL
	// and ADCH until ADCH is read.  reading ADCL second would
	// cause the results of each conversion to be discarded,
	// as ADCL and ADCH would be locked when it completed.
	low  = ADCL;
	high = ADCH;

	// combine the two bytes
	return (high << 8) | low;

ADCLを読みだすと、その後ADCHを読みだすまではADCHは更新されません。このため、先にADCLを読む必要があります。

バージョン

Arduino 1.8.3



メニューを表示するためにJavaScriptを有効にしてください。

Arduinoで遊ぶページ
Copyright © 2016 garretlab all rights reserved.
inserted by FC2 system