温度を測る その7 温度センサはいらない
マイコンの中に温度センサは内蔵されていることが多いです。Arduino UNOで使われているマイコンATMega328です。Arduino IDEが1.0になるまでは、A-Dコンバータのチャネル8につながった温度センサを、
analogRead(8); |
という記述で読み込めたようですが、今はできません。今現在、Arduino IDEは1.8.5です。
●スケッチの中でアセンブラが書ける
スケッチは、CもしくはC++言語に準じた言語です。C言語はもともとハードウェアを直接操作するのに向いた言語ですが、処理系によって、アセンブラの併用ができます。gccなどでは、Cのプログラムの途中に、asmや__asm__を使うと、ニモニックでアセンブラのプログラムを記述できます。
Arduino IDEでは、ATMegaのマニュアルにあるレジスタ名をそのまま利用して記述するだけで、特別にここからここまでアセンブラだという宣言などは不要です。
●内蔵温度センサは確度が低い?
ATMega328に内蔵されている温度センサの出力はA-Dコンバータの8番につながります。外部にピンは出ていません。確度がよくないようで、検索すると10℃程度ずれるという記述が見つかります。室温付近で校正すると、分解能は±1℃程度は取れ実用的です。
●設定するのはADMUXレジスタ
A-Dコンバータの入力切り替えに使われるマルチプレクス・レジスタは、次の構成です。
bit7 | 6 | 5 | 4 | 3 | 2 | 1 | bit0 |
---|---|---|---|---|---|---|---|
REFS1 | REFS0 | ADLAR | - | MUX3~0 |
温度センサを利用するときは、内部基準電圧源を指定します。内部レファレンス1.1Vを選ぶためにREFS1と0は'11'、チャネル8を選ぶのでMUXは'1000'を指定します。ADLARはデータを右詰めにするか左詰めにするかを指定します。
●A-Dコンバータの制御はADCSRAレジスタ
A-Dコンバータを起動したりする制御レジスタは、次の構成です。
bit7 | 6 | 5 | 4 | 3 | 2 | 1 | bit0 |
---|---|---|---|---|---|---|---|
ADEN | ADSC | ADATE | ADIF | ADIE | ADPS2~0 |
ADENはA-D変換イネーブル、ADSCはA-D変換スタート、ADATEはオート・トリガ・イネーブル、ADIFはA-D変換割り込みフラグ、ADIEは割り込み許可、ADPS2~0はシステム・クロックから変換用クロックを作る時のプリスケーラ(割り算)です。必要なビットだけを指定します。
●変換結果はADCLとADCHレジスタを読む
8ビット・マイコンなので、A-D変換された12ビットのデータは二つのレジスタに保存されます。下位バイトADCLを読み出すと上位バイトはロックされ、正しく2バイトを読み出せるようにロジックが構成されています。
●スケッチ
Arduino.ccにスケッチがあります。一部コメントを意訳しました。
// Internal Temperature Sensor
// Example sketch for ATmega328 types.
//
// April 2012, Arduino 1.0
void setup(){
Serial.begin(9600);
Serial.println(F("Internal Temperature Sensor"));
}
void loop(){
Serial.println(GetTemp(),1);
delay(1000);
}
double GetTemp(void){
unsigned int wADC;
double t;
// マイコン内部の温度センサを利用。
// 基準電圧は内部の1.1Vを使う。
// チャネル8を選択。analogRead()では選択できない
// 基準電圧源を1.1Vに、チャネル8を選択
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
ADCSRA |= _BV(ADEN); // A-Dコンバータを有効に
delay(20);
ADCSRA |= _BV(ADSC); // 変換開始
// 変換終了を待つ
while (bit_is_set(ADCSRA,ADSC));
// ADCL とADCHレジスタを読む。ADCL | (ADCH << 8)。
// ADCWは#define ADCW _SFR_MEM16(0x78)でワード長で定義されている。
wADC = ADCW;
// 摂氏の単位で温度を計算。オフセット324.31はデバイスによって異なる。校正した値を記述すべき
t = (wADC - 324.31 ) / 1.22;
return (t);
}
実行結果です。内部温度計は、マイコンが異常になっているか、温度が上がり過ぎると処理を抑えるとかの目的で使われます。マイコンの隣に発熱する3端子レギュレータがあったりすると、影響をうけます。USBからの電源を利用すれば、発熱するのはマイコン自身になるので、温度を読み出すだけのように軽い動作であれば温度センサとして利用できます。