ArduinoのanalogRead()処理の高速化を行ってみました。ついでに簡単に精度確認と速度効果も見てみました。(UNOが前提です)
データシート確認するとデフォルトでAD変換に掛かる時間はどうも
0.0625μs × 分周値 × 13クロック
このような感じ??。分周値はデフォルトで「128」なので、1回に掛かるAD変換時間は、104μsです。
一応、こんなスケッチで処理時間実測してみました。
▼ソース抜粋▼
void loop() { PORTB |= B00100000; battery = analogRead(0); PORTB &= B11011111; delay(10); Serial.println(battery*1024/5.0); }
AN0ピンには3.3Vを印可。13pinのHIGH時間をロジアナ使って計測してます。(PICKit3をロジアナとして使う方法)
▼結果▼
AD変換時間はおよそ「117μs」、で測定電圧は「3.308V」。それなりの処理速度≒理論値で、それなりの測定精度です。
変換時間の誤差はArduino関数のanalogRead()が処理時間使ってるかも、と思って、なるべくレジスタ操作での計測も行ってみました。
レジスタ操作でのソース抜粋
void loop() { PORTB |= B00100000; ADMUX = 0b01000000; ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)); uint8_t dL, dH; dL = ADCL; dH = ADCH; battery = (dH << 8 | dL); PORTB &= B11011111; delay(10); Serial.println(battery * 1024 / 5.0); }
同様にAN0ピンには3.3Vを印可してます。結果は「114μs」と若干早くなりましたがほとんど測定誤差??あまり変わりませんでした・・。
分周値デフォルト(128)ではこれくらいの処理速度のようです。で、分周値を変えて見ることに。
データシートによると、分周値はADCSRAレジスタの下位3bitで変更できるようです。
▼分周値は▼
ADCSRA |= 0b00000111; // |||<--分周値bit // 0bxxxxx000:2分周 // 0bxxxxx001:2 // 0bxxxxx010:4 // 0bxxxxx011:8 // 0bxxxxx100:16 // 0bxxxxx101:32 // 0bxxxxx110:64 // 0bxxxxx111:128 <--デフォルト
2~128で設定。
分周値を変えて電圧値、処理時間を測定してみました。
▼結果▼
AN0ピンに3.3Vを印可して測定してます。
分周値「2」のときはうまく測定できなかったです(何故か不明)。測定精度は悪くなる??ような気もしますが・・。測定のやり方がかなりアバウトなのでよくわかりません・・。
デフォルト設定に比べれば、10倍以上も高速化できます。
Arduino関数使った場合とレジスタ操作した場合で速度差はあまりなかったのですが、レジスタ操作ではArduino関数では設定できない『読取りピン』の設定があります。
analogRead()関数では『読取りピン(入力)』を「AN0」~「AN5」のピン設定しかできませんが、ADMUX レジスタを直接操作すればAN0~AN5ピンに加えて「温度感知器」と「内部1.1V基準電圧」を『読取りピン』に設定できるようです。
前者はそのままCPU?の温度測定。ただデータシートには精度±10℃と記載があったので微妙です・・。
「内部1.1V基準電圧」を『読取りピン』に設定できるのはちょっと便利です。
内部1.1Vを読み取ってどうするの?という感じですが、基準電圧を「AVcc」にして、『読取りピン』を「内部1.1V電圧」に設定しておけば、読取り値は必ず1.1Vとなります。基準電圧を逆算すれば、Arduinoへの電源電圧を測定することができます。これは何気に便利かも。
ArduinoというよりAVRよりの内容となってしまいましたが・・・。分周値いじるだけでanalogRead()は高速化できるのでお手軽です。
コメント
内部1.1V基準電圧は、analogReference(INTERNAL)でできますよ。
記事本文がわかり難かったですね。
確かにanalogReference(INTERNAL)で『基準電圧』を内部1.1Vに設定できますが、ADMUXレジスタを操作すれば『読取りピン』(入力)に内部1.1Vを設定できるということです。
記事本文にもう少し説明加えておきます。