« ナットがぁ!? 9年前の残党を発見 | トップページ | Gigazineの記事「DDR Type 2の内部構造がすごい」 »

2023年1月 9日 (月)

Arduino UNO, Tips and Tricks:analogRead()を捨てちゃうぞ

Arduino UNOでのアナログ入力(A/D値の読み出し)、
通常はこんな感じかと。

・setup()内で
  analogReference(DEFAULT);  // 使う基準電圧を設定
                 // DEFAULTはAVCCの+5V電源
・loop()で
  d = analogRead(A0);  // A0ピンからアナログ入力
              // UNOだとA0~A5の6つから選択

読み出したd値をシリアル出力したり、加工して何かの操作に
使うという具合です。

しかし、analogRead()は結果が出てくるまで時間がかかり、
約100μs待たされます。
時間にきびしい処理の中では使うのはちょっと・・・
となってしまいます。

もし、使うアナログ入力が単一チャンネルで固定して良いのなら、
時間のかかるanalogRead()は捨てちゃいましょう

Arduino UNOのマイコン、ATmega328Pのレジスタを直接操作
して、固定チャンネルの連続変換動作で初期化します
すると、待ち時間無しで(A/D変換完了を待たずに)いつでも最新の
A/D値を読み出せます。

スケッチ例を示します。

//  A/D値読み出し実験  A0ピンが入力
// 読み出し中、PB5をonしてタイミングをチェック
#define PB5_H (PORTB |= (1 << PB5)) // LED on ※1
#define PB5_L (PORTB &= ~(1 << PB5)) // LED off

/***** SETUP *****/
void setup() {
pinMode(13, OUTPUT); // PB5 基板上LED ※1
Serial.begin(9600); // シリアル出力

// A/D入力
// ↓通常の記述
// analogReference(DEFAULT); // ArefはAVCCアナログ+5V電源 ※2
// ↓直接レジスタを操作 ※3
ADMUX = 0b01000000; // VREF設定
// ||| ++++--- MUX3~0 ch0 PC0を入力に ★
// ||+-------- ADLAR 右詰め (LSBがD0)
// ++--------- REFS AVCCから(+5V)
ADCSRB = 0b00000000;
// ||| +++--- ADTS 連続変換モード ★
// ||+-------- IPR
// |+--------- ACME
// +---------- BIN
ADCSRA = 0b11100111;
// |||||+++--- CLK 1/128 125kHz
// ||||+------ ADIE 割り込みしない
// |||+------- ADIF
// ||+-------- ADATE 自動トリガする ★
// |+-------- ADSC 変換開始 ★
// +---------- ADEN A/Dイネーブル ★
}

/***** LOOP *****/
void loop() {
word ad_10; // 10bit A/Dデータ
PB5_H; // LED on ※1
// ↓通常の記述
// ad_10 = analogRead(A0); // A0からアナログ入力 ※2
// ↓直接レジスタを操作
ad_10 = ADC; // 10bit直接 ※3
PB5_L; // LED off
Serial.println(ad_10); // 読んだA/D値をシリアル出力
delay(1000); // 1秒待ち
}

※1:タイミングチェック用パルス オシロで確認
※2:通常の記述
※3:レジスタを直接操作

通常の記述だと読み出しに時間がかかります。
約0.1ms。
C01_20230109143101

それが、直接記述だとこんな命令に変換されます。
  sbi 0x05, 5    ;PB5_H
  lds r18, 0x0078  ;ad_10 = ADC
  lds r19, 0x0079  ;ADCL、ADCHの順で
  cbi 0x05, 5    ;PB5_L

勝手に変換が行われるので、待ち時間なく、ADCレジスタを読むだけ。
実行時間はこれだけ。
C02_20230109143101
   ※シリアル出力データが出てくるのはず~っと後。

単一チャンネルだからできる技。
多チャンネルだと入力マルチプレクサを切り替えてから
変換を始め、そして変換完了を待つという動作になりますので
どうしても時間がかかります。

忙しい処理の中でアナログ値を読みたい(ボリュームの角度で
何かをしたいなど)時に使ってみてください。

|

« ナットがぁ!? 9年前の残党を発見 | トップページ | Gigazineの記事「DDR Type 2の内部構造がすごい」 »

Arduino」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« ナットがぁ!? 9年前の残党を発見 | トップページ | Gigazineの記事「DDR Type 2の内部構造がすごい」 »