goo blog サービス終了のお知らせ 

ゴーイングマイウェイの戯言

パソコンに関することなど、作者の趣味が中心のブログです

Arduino UNOのanalogReadの高速化

2018-02-03 14:56:56 | Arduino&Raspberry Pi
Arduinoであれこれしようと思った時、アナログ電圧をモニターしたくなることがある。

例えば、CdSを使った明るさセンサーなどが該当する。

こんな時は、analogRead関数が便利だ。

しかし、周波数を判別したい場合などは、マイクロ秒[us]オーダーでアナログ電圧をモニターしたくなる。

しかし、analogRead関数は、1回当たりの処理に100[us]~200[us]程度かかってしまうことが判明。

そこで、analogRead関数の高速化の方法を調査した。


参考にしたもの
 ArduinoのADCを高速化してみた | あれたうみと ひるのすなはま
 analogRead()の内部構造 | garretlab
 C言語入門::付録 ビット演算




1.高速化前のスピードの確認
 高速化をする前に、現状でどの程度のスピードか確認してみた。
 確認のため、以下のスケッチを実行してみる。
 (シリアルポートで文字を一文字送信すると実行するスケッチ)

void setup() {
  // シリアルポート初期化
  Serial.begin(9600);
}

void loop() {

  int moji;
  // シリアルポートより、文字を1字読み込む
  moji = Serial.read();

  // 文字入力があった場合のみif関数を実行
  if(moji != -1){
    
    // 開始時間を記録
   unsigned long StartTime = millis();

    // 100,000回 analogReadを実行
    for(long i=0; i<100000; i++){
      int result;
      result = analogRead(0);
    }

    // 終了時間を記録
    unsigned long StopTime = millis();

    // 結果を出力
    Serial.print("analogRead(100,000cyc) = ");
    Serial.print(StopTime - StartTime);
    Serial.println(" [ms]");
  }
}


 analogRead100,000回で11,200[ms]なので、1回当たり112[us]かかっている。



2.analogReadを高速化
 analogReadを高速化させるためには、マイコンの設定レジスタを変更する。
 このため、マイコンの種類ごとに設定方法が異なるということになる。
 今回は、Arduino UNO (マイコン:ATmega328P)の場合で説明する。

 高速化するためには、『ADCSRA』というAD(アナログ-デジタル)変換器の制御を行うレジスタの
 分周比という部分の値を書き換える。

 以下の2行をArduinoのスケッチに追加すると、分周比を標準値の128=>16に書き換えることで高速化できる。

ADCSRA = ADCSRA & 0xf8;   // 分周比を決めるビット(ADPS2:0)を000へ
ADCSRA = ADCSRA | 0x04;   // 分周比を決めるビットに分周比16(100)をセット

 analogRead100,000回で1,506[ms]なので、1回当たり15.06[us]となり、高速化に成功した。



3.なぜ高速化できるか
 なぜ、上記の2行を追加すると高速化できるか勉強してみた。

 Arduino UNOではAD(アナログ-デジタル)変換器を6個持っていて、analogRead関数はこのAD変換器を使って、
 アナログピンから値を読み取っている。
 analogRead関数は、4つのレジスタを使っており、そのうちADCSRAレジスタでAD変換器の制御を行っている。

 ADCSRAレジスタは8bitで構成されていて、下位3bitが分周比を決めている。
 分周比を上げると時間はかかるが、精度が出る。
 今回のように分周比を下げると速度は上がるが、精度は悪くなる。
 使用目的に応じて、分周比を決めるとよい。


 なぜ、上の2行を追加するとレジスタの特定部分を書き換えることができるのか調べてみた。
 やっていることはビット演算で、1行目はAND『&』を使って下位3bitを0にし、
 2行目はOR『|』を使って下位3bitに100とセットした。

 ちなみに、0xとは16進数を意味しており、0xf8を2進数で表すと『11111000』となり、
 0x04を2進数で表すと『00000100』となる。

1 コメント

コメント日が  古い順  |   新しい順
なるほど (中納言)
2021-10-25 13:14:17
おもしろい。
逐次型くらい速いといいのですけどね
返信する

コメントを投稿