Arduino レジスタを読み取る

Arduino nanoに実装されているATmega328/Pのデータシートを見ていてふと思ったのが内部レジスタを直接見れるんじゃないかと。で、試しにレジスタ名を入れるだけで簡単に読み取れました。

参考:https://playground.arduino.cc/Learning/PortManipulation

前回の更なる改善


前回の記事

″基準電圧を決めるanalogReference();がsetup内で正常に動作せずINTERNALへ変わらなかった。

INTERNAL(内部電圧基準)を設定後、1秒ディレイを入れてから電圧値を取得した後にDEFAULT(電源電圧基準)に戻すことで解決。″

ディレイ使うのにちょっと抵抗感を感じていたのでADC関係のレジスタが設定通りになっていることを確認してから次のステップへ進むよう変更しようと思います。

実験回路は前回のラストと同じです。

情報収集


まず、レジスタ名を知るためにデータシートをダウンロード。

ATmega328/P – Complete Datasheet 11/2016

手始めにLEDをレジスタを操作して動かそうと考え、D13に該当するPB5を探す。
116ページの項目18.4.2. Port B Data RegisterのレジスタPORTBのbit5がD13あたり、それに”1″を書き込むことでON、”0″でOFFになる。

  if(LEDstat == 4){
//ON
//    PORTB |= B00100000;
      PORTB |= _BV(5);
    delayMicroseconds(value1);
//OFF
//    PORTB &= ~B00100000;
      PORTB &= ~_BV(5);
    delayMicroseconds(value1);
  }

コメントアウトしていますが、どちらでも出来るようです。
参考:https://garretlab.web.fc2.com/arduino/inside/avr/sfr_defs.h/_BV.html

Serial.print(PORTB, BIN);で状態を読み取ることが出来ます。

レジスタ読み取り実践


次は本命のディレイ取り除き作戦

まず初めにanalogReference(INTERNAL)でちゃんとレジスタが思うように変わっているか確認。

多分、データシート317ページの28.9.1. ADC Multiplexer Selection Register

レジスタADMUXのBit7:6が基準電圧の選択で”01″がAVcc(+5V)、”11″が内部1.1Vとなるはず。

実際にINTERNALを実行後にレジスタを読み取り表示させてみた。
Serial.println(ADMUX, BIN);

結果、Bit7:6は変わってなかった。けれど、analogRead()実行後はADMUXが設定されていた。つまり、これが実行されて初めて書き換えられるのか?!

分からないので次。


今度はADMUXを直接変更してどうなるか試してみた。

確かにADMUXの値は変わるが結果が変わらなかった・・・。
仕方なくIDE内を見て各関数が何をしてるか調査。

先ほどのanalogRead()でADMUXが設定されるのは正しかったようだ。

analogReference()は基準電圧の設定値を格納するだけにすぎない。

スケッチ上でADMUXを書き換えてもanalogRead()内でADMUXを書き換えられてしまう。

Arduino IDEソース:wiring_analog.c

30行目がanalogReference()について。
39行目から98行目がanalogRead()について。
70行目でanalogReference()で設定した値をADMUXに書き込んでいる。

残念。

方針を変えてプログラムと実験


最終案は、ディレイを入れるか。又は、REFピンにプルダウン抵抗を入れるか。
今のスケッチのセットアップはこんな感じ。

void setup() {
  Serial.begin(9600);
  while (!Serial)

  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  Serial.println("/-----START Arduino-----/");

  PORTB = PORTB ^ _BV(5);

  analogReference(INTERNAL);
  
//  delay(10);

  PORTB = PORTB ^ _BV(4);
  
  for(int i=0; i<=0 ; i++){REF_VAL = analogRead(7);}

  PORTB = PORTB ^ _BV(5);
  
  REF_DEF = (float)REF_VAL * 11 / 1024;

  PORTB = PORTB ^ _BV(4);

  analogReference(DEFAULT);

  PORTB = PORTB ^ _BV(5);

}

なぜ、ディレイを入れるか。

そもそも電気的、タイミング的によくなかったようで、AREFが1.1Vへ上がる途中で値を取得していたようだ。波形を見てみた。

CH1:AREF(黄)、CH2:D13(青)、CH3:D12(紫)
※安価オシロの為正確ではないかも。

動きとしては
(1)初回シリアル送信:D13 ON
(2)基準電圧値を設定後:D12 ON
(3)アナログ読み取り:D13 OFF
(4)電源電圧を求めた:D12 OFF
(5)セットアップ完了:D13 ON

(3)アナログ読み取りから(4)電源電圧を求めるまでの間のAREFは、まだ1.1Vに達していないのが分かります。ですので1.1Vに到達する時間を稼ぐのにディレイを入れます。

または、下記のように10kΩの抵抗を入れることで一応は解決した。

こちらも同様に波形を取り見てみました。

測定個所と動作は先ほどと同じです。

1.1Vに到達後、アナログ取得しているのが分かります。
若干乱れた波形になっているので抵抗値は変える必要がありそうですね。

抵抗追加後の測定値

結局、目標だったレジスタの値見て動作させるのは今回達成できず・・・。

でも、なかなか勉強になったかなと。

今回のプログラムはPORTBいじる位で他は前回と同じなので省略。

Arduino nano モーター制御

スポンサーリンク