部品 · 読了まで19分

NTCサーミスタとArduinoのガイド:配線、B定数の式、Steinhart-Hartの式

ArduinoでNTCサーミスタを使う方法:分圧回路の配線、B定数(B3950)の式とSteinhart-Hartの式、キャリブレーション、LCD温度計、ESP32とPicoのコードを紹介します。

NTCサーミスタは、温度が上がると抵抗値が下がる、2本足の安価な温度センサーです。ArduinoでNTCサーミスタを使うには、10 kΩの固定抵抗と組み合わせて分圧回路を作り、中点の電圧をアナログピン(A0)で読み取ります。その値からサーミスタの抵抗値を求め、B定数の式で摂氏温度に変換します。ライブラリは不要で、アナログピンは1本で足ります。正しく組めば、室温で0.1 °Cの分解能が得られます。3Dプリンターのベッドとホットエンド、スマホやノートパソコンのバッテリー、エアコン、冷蔵庫、デジタル体温計も、ほとんどがNTCサーミスタで温度を測っています。

この記事では、10 kΩのNTCサーミスタの抵抗値が温度でどう変わるか、分圧回路の配線と固定抵抗の選び方、B = 3950を使ったB定数の式、より正確なSteinhart-Hartの式、3点キャリブレーションをステップごとに学びます。続いてI2C LCDを使った温度計を作り、同じ測定をESP32とRaspberry Pi PicoのADCでも行います。さらに、NTCとPTCの違い、3Dプリンターやバッテリーでの応用、よくある間違いも見ていきます。

ディスク型のNTCサーミスタ
ディスク型のNTCサーミスタ:極性がないので、2本の足はどちら向きに挿してもかまいません。このような大きな本体のモデルは、主に電源の突入電流を制限するために使われます。温度の測定には、小さなエポキシビーズ型や防水プローブ型の10 kΩのNTCが向いています。

NTCサーミスタとは?その仕組みは?

サーミスタ(thermistor)という名前は、英語の「thermal」(熱の)と「resistor」(抵抗)を組み合わせたもので、温度によって値が大きく変わる抵抗です。NTCはNegative Temperature Coefficient(負の温度係数)の略です。マンガン、ニッケル、コバルトなどの金属酸化物を高温で焼き固めて(焼結)作る半導体セラミックでできています。温まると導電に加わる電荷キャリアが増えるため、抵抗値が下がります。変化は大きく、B = 3950のNTCでは25 °C付近で1度あたり約4.4%抵抗値が下がります。比べると、一般的な金属皮膜抵抗の変化は1度あたりわずか50〜100 ppm、つまり0.005〜0.01%です。この高い感度のおかげで、NTCは安価でも非常に反応のよいセンサーになります。その代わり、温度との関係は直線的ではありません。

特性一般的な10 kΩのNTC(B3950)
公称抵抗値(R25)25 °Cで10 kΩ。誤差は通常±1%、±3%、±5%
B定数B25/50 = 3950 K(±1%)。3435 Kや3380 Kのモデルもよく使われる
感度25 °Cで約−4.4%/°C、100 °Cで約−2.8%/°C
動作温度範囲エポキシビーズ型で約−40〜+125 °C。ガラス封止型は250〜300 °Cまで
自己発熱(熱放散定数)静止空気中で通常1.5〜2 mW/°C
熱時定数静止空気中のエポキシビーズ型で約10〜20秒
極性なし。足を入れ替えてもかまわない
パッケージの種類エポキシビーズ、ガラス(DO-35)、ステンレス製の防水プローブ、SMD(0402、0603)、ディスク

抵抗値と温度の関係:なぜ直線にならない?

NTCの抵抗値は温度に対して指数関数的に変化します。低温では非常に速く、高温ではよりゆっくり下がります。下の表は、10 kΩ、B = 3950のNTCについてB定数の式で計算した抵抗値と、このNTCを5 Vで動作する10 kΩの分圧回路の上側に入れたとき(次のセクションの配線)にArduino UnoのA0ピンで見られる電圧とanalogReadの値を示しています。最後の列は、ADCの1ステップが何度に相当するか、つまり測定の分解能です。実際のメーカーの表は、特に範囲の両端でこれらの値と数パーセント異なることがあります。

温度NTCの抵抗値A0の電圧(5 V)analogRead(読み取り値)1ステップ ≈
−20 °C105.4 kΩ0.433 V890.20 °C
0 °C33.6 kΩ1.146 V2350.10 °C
10 °C20.2 kΩ1.657 V3390.09 °C
20 °C12.5 kΩ2.219 V4540.09 °C
25 °C10.0 kΩ2.500 V5120.09 °C
30 °C8.04 kΩ2.772 V5670.09 °C
40 °C5.30 kΩ3.268 V6690.11 °C
50 °C3.59 kΩ3.680 V7530.13 °C
60 °C2.49 kΩ4.004 V8190.17 °C
80 °C1.27 kΩ4.436 V9080.31 °C
100 °C698 Ω4.674 V9560.57 °C
125 °C359 Ω4.827 V9881.17 °C

この表から2つの重要なことがわかります。1つ目は、分圧回路の感度がいちばん高くなるのはNTCの抵抗値が固定抵抗と等しいときで、この例では25 °C付近だということです。そこでは1度あたりA0の電圧が約55 mV変化し、10ビットのUnoでも0.09 °C刻みで測れます。これは、5 Vの基準電圧で0.49 °Cの分解能しか得られないLM35の5倍の細かさです。2つ目は、その点から離れるほど分解能が悪くなることです。100 °Cでは1ステップが0.57 °C、125 °Cでは1.2 °Cになります。そのため、固定抵抗は、いちばんよく測る温度でのNTCの抵抗値に近いものを選びましょう。ある範囲でA0の電圧の振れ幅を最大にするには、固定抵抗を範囲の両端でのNTCの抵抗値の幾何平均にします。0〜100 °Cなら√(33.6 kΩ × 0.70 kΩ) ≈ 4.8 kΩなので標準値の4.7 kΩ、60〜100 °Cなら約1.3 kΩなので1.2 kΩか1.5 kΩです。

NTCサーミスタの配線:分圧回路(Uno、ESP32、Pico)

Arduinoのアナログ入力が測るのは、抵抗ではなく電圧です。そのため、NTCを固定抵抗と直列につないで分圧回路を作ります。2つの抵抗の接続点の電圧は、NTCの抵抗値、つまり温度によって変わります。LDRで使う回路とまったく同じで、違いは抵抗が光ではなく温度に反応することだけです。この記事のコードでは、NTCを上側(電源側)、10 kΩの抵抗を下側(GND側)に置いています。こうすると温まるほど読み取り値が上がるので、直感的にわかりやすくなります。抵抗値を変えたときの出力電圧は「分圧回路」ツールで計算でき、固定抵抗のカラーコードは「抵抗のカラーコード」ツールで確認できます。

接続Arduino UnoESP32Raspberry Pi Pico
NTCの足15V3V33V3(OUT)、ピン36
NTCの足2+10 kΩの抵抗の片側A0GPIO 34(ADC1)GP26 / ADC0、ピン31
10 kΩの抵抗のもう片側GNDGNDAGND、ピン33
100 nFのコンデンサ(任意)A0とGNDの間GPIO 34とGNDの間GP26とAGNDの間
配線A0の電圧NTCの抵抗値(10ビット)温まったときのanalogRead
NTCが上側:5V – NTC – A0 – 10 kΩ – GNDVcc × Rs / (Rs + Rntc)(Rs=固定抵抗)Rntc = Rs × (1023 − adc) / adc(adc=読み取り値)上がる
NTCが下側:5V – 10 kΩ – A0 – NTC – GNDVcc × Rntc / (Rs + Rntc)(Rs=固定抵抗)Rntc = Rs × adc / (1023 − adc)(adc=読み取り値)下がる
よくある間違いは2つあります。1つ目は、固定抵抗を使わずにNTCを5VとA0の間に直接つなぐことです。この場合、温度に関係なくA0は1023を示します。2つ目は、回路を一方の配線で組み、もう一方の配線の式を使うことです。すると温まるほど温度が下がるように見えたり、おかしな値が出たりします。ESP32とPicoでは、分圧回路を絶対に5Vから給電しないでください。NTCが上側にあると約41 °Cでピンの電圧が3.3 Vを超え、NTCがショートすると5 Vがそのままピンにかかります。どちらも3.3 VのADC入力を壊すおそれがあります。

この回路には便利な性質があります。レシオメトリック測定になることです。UnoのADCは標準で5 Vの電源を基準電圧に使い、分圧回路も同じ5 Vで動作します。USBから来る電圧が5.0 Vではなく4.8 Vでも、分圧回路の出力とADCの基準電圧が同じ割合で下がるので、analogReadの値は変わりません。そのため、NTCの測定では電源電圧を知る必要がなく、LM35のように基準電圧に悩まされることもありません。同じ理由で、NTCの回路ではanalogReference(INTERNAL)を使わないでください。基準電圧が1.1 Vになると比率が崩れ、計算が狂います。精度を本当に左右するのは固定抵抗の値で、誤差5%の抵抗だけで約1 °Cの誤差が出ることがあります。誤差1%の金属皮膜抵抗を使うか、抵抗の実際の値をテスターで測ってコードに入力しましょう。

B定数の式(B = 3950)で温度を計算する

メーカーはNTCを2つの数値で表します。25 °Cでの抵抗値(R0 = 10 kΩ)とB定数(Beta)です。この2つの数値があれば、B定数の式でどんな抵抗値からも温度が求められます:1/T = 1/T0 + (1/B) × ln(R/R0)。ここでTとT0はケルビン(T0 = 25 + 273.15 = 298.15 K)、lnは自然対数です。結果から273.15を引くと摂氏になります。例:NTCの抵抗値が5300 Ωなら、ln(5300/10000) = −0.635、1/T = 0.003354 − 0.000161 = 0.003193で、T = 313.2 K、つまり約40 °Cです。B定数の横にある小さな数字は、どの2つの温度の間で測ったかを表します。B25/50 = 3950は、25 °Cと50 °Cの抵抗値からBを計算したという意味です。データシートがない場合は、自分でBを求めることもできます。2つの温度で抵抗値を測り、B = ln(R1/R2) / (1/T1 − 1/T2)を使います。たとえば25 °Cで10,000 Ω、50 °Cで3588 Ωと測れたなら、B ≈ 3950になります。

Arduinoで最初の測定をする手順

  1. NTCと10 kΩの抵抗をブレッドボードに挿します。NTCの片方の足を5Vに、もう片方の足を抵抗の片側につなぎます。
  2. 抵抗のもう片側をGNDにつなぎ、NTCと抵抗の接続点からA0へジャンパーワイヤーを配線します。
  3. 下のコードを書き込み、シリアルモニタを9600ボーで開きます。
  4. 室温では20〜25 °C前後の値が表示されるはずです。NTCを2本の指でつまむと、数秒で値が30 °Cに向かって上がっていきます。
  5. 温まると値が下がる場合は、NTCと抵抗が逆になっています。配線を直すか、コードの式を「NTCが下側」の式に置き換えてください。
C++ (Arduino IDE)
1const int NTC_PIN = A0;            // NTC ile 10k direncin birleştiği nokta / junction of the NTC and the 10k resistor
2const float SERIES_R = 10000.0;    // sabit direnç, ölçtüğün değeri yaz / fixed resistor, write your measured value
3const float R_NOMINAL = 10000.0;   // NTC'nin 25 °C'deki direnci / NTC resistance at 25 °C
4const float T_NOMINAL_K = 298.15;  // 25 °C kelvin cinsinden / 25 °C in kelvin
5const float BETA_K = 3950.0;       // B25/50 değeri (veri sayfası) / B25/50 value (datasheet)
6const int SAMPLES = 16;            // ortalama için ölçüm sayısı / number of samples to average
7
8void setup() {
9  Serial.begin(9600);
10}
11
12void loop() {
13  long sum = 0;
14  for (int i = 0; i < SAMPLES; i++) {
15    sum += analogRead(NTC_PIN);
16    delay(2);
17  }
18  float adc = sum / (float)SAMPLES;                      // ortalama ham değer / average raw value
19
20  if (adc < 1.0 || adc > 1022.0) {                       // kablo kopuk ya da kısa devre / open or shorted wire
21    Serial.println(F("Sensor hatasi / Sensor error"));
22    delay(1000);
23    return;
24  }
25
26  float rNtc = SERIES_R * (1023.0 - adc) / adc;          // NTC üstte bağlantı / NTC on the high side
27  float tempK = 1.0 / (1.0 / T_NOMINAL_K + log(rNtc / R_NOMINAL) / BETA_K);   // Beta denklemi / Beta equation
28  float tempC = tempK - 273.15;                          // kelvin -> santigrat / kelvin -> Celsius
29
30  Serial.print(F("ADC: "));
31  Serial.print(adc, 1);
32  Serial.print(F("  R: "));
33  Serial.print(rNtc, 0);
34  Serial.print(F(" ohm  Sicaklik / Temp: "));
35  Serial.print(tempC, 2);
36  Serial.println(F(" C"));
37  delay(1000);
38}

このコードは測定のたびにA0を16回読み取って平均します。これでADCの1〜2ステップのふらつきがならされます。平均が1未満か1022を超える場合は、NTCの線が断線しているかショートしているので、意味のない温度ではなくエラーメッセージを表示します。続いて平均値からNTCの抵抗値を計算し、そこからB定数の式で温度を求めます。Arduinoのlog()関数は自然対数(ln)を返します。log10()は底が10の常用対数で、この2つを取り違えると、25 °Cから離れるほど結果がまったく違ってしまいます。シリアルモニタには「ADC: 512.3 R: 9969 ohm Sicaklik / Temp: 25.07 C」のような行が表示されます(Sicaklikはトルコ語で「温度」)。

Steinhart-Hartの式:より正確な結果

B定数の式は、Bを測定した範囲(通常は25〜50 °C)ではとても正確ですが、そこから離れるとずれていきます。実際のNTCのB定数は、温度によって少し変わるからです。0〜100 °Cのような広い範囲では、誤差が1 °Cを超えることもあります。より正確な結果を得るには、3つの係数を持つSteinhart-Hartの式を使います:1/T = A + B × ln(R) + C × (ln R)³。B定数の式は、実はこの式でC = 0とした特別な場合です。係数は、3つの異なる温度で測った3つの抵抗値から計算します。うまく選んだ3点を使えば、キャリブレーションした範囲内で通常0.1 °Cより高い精度が得られます。A、B、Cを手で解く代わりに、下のコードは測った3点からsetup()の中で係数を自動的に計算します。

C++ (Arduino IDE)
1const int NTC_PIN = A0;
2const float SERIES_R = 10000.0;    // ölçtüğün sabit direnç / your measured fixed resistor
3
4// Kalibrasyon noktaları: örnek değerler, kendi ölçümlerini yaz / calibration points: sample values, use your own
5const float CAL_T1 = 0.0,  CAL_R1 = 32900.0;   // buzlu su / ice water
6const float CAL_T2 = 25.0, CAL_R2 = 10000.0;   // oda, referans termometreyle / room, against a reference thermometer
7const float CAL_T3 = 98.5, CAL_R3 = 690.0;     // kaynayan su / boiling water
8
9float shA, shB, shC;               // Steinhart-Hart katsayıları / coefficients
10
11void computeCoefficients() {
12  float L1 = log(CAL_R1), L2 = log(CAL_R2), L3 = log(CAL_R3);
13  float Y1 = 1.0 / (CAL_T1 + 273.15);
14  float Y2 = 1.0 / (CAL_T2 + 273.15);
15  float Y3 = 1.0 / (CAL_T3 + 273.15);
16  float g2 = (Y2 - Y1) / (L2 - L1);
17  float g3 = (Y3 - Y1) / (L3 - L1);
18  shC = ((g3 - g2) / (L3 - L2)) / (L1 + L2 + L3);
19  shB = g2 - shC * (L1 * L1 + L1 * L2 + L2 * L2);
20  shA = Y1 - (shB + shC * L1 * L1) * L1;
21}
22
23float readResistance() {
24  long sum = 0;
25  for (int i = 0; i < 16; i++) {
26    sum += analogRead(NTC_PIN);
27    delay(2);
28  }
29  float adc = sum / 16.0;
30  if (adc < 1.0 || adc > 1022.0) return -1.0;            // sensör hatası / sensor error
31  return SERIES_R * (1023.0 - adc) / adc;                // NTC üstte / NTC on the high side
32}
33
34void setup() {
35  Serial.begin(9600);
36  computeCoefficients();           // katsayıları bir kez hesapla / compute the coefficients once
37}
38
39void loop() {
40  float r = readResistance();
41  if (r < 0) {
42    Serial.println(F("Sensor hatasi / Sensor error"));
43  } else {
44    float lnR = log(r);
45    float tempK = 1.0 / (shA + shB * lnR + shC * lnR * lnR * lnR);   // Steinhart-Hart
46    Serial.print(F("R: "));
47    Serial.print(r, 0);
48    Serial.print(F(" ohm  Sicaklik / Temp: "));
49    Serial.print(tempK - 273.15, 2);
50    Serial.println(F(" C"));
51  }
52  delay(1000);
53}

コードの3点は例です。自分のNTCを測って置き換えてください。このサンプル値では、Steinhart-Hartの式は0 °C、25 °C、98.5 °Cでぴったり正しい結果を出します。しかし同じ抵抗値をB定数の式(B = 3950)に入れると、0 °Cの点は0.4 °C、98.5 °Cの点は100.4 °Cと計算され、高温では約2 °Cの誤差になります。点は、測る範囲の両端と中央から選びましょう。キャリブレーションした範囲の外(たとえばこの係数での−20 °C)では、誤差がまた大きくなります。Unoのfloatは32ビットしかありませんが、この計算には十分です。結果は倍精度で計算した値と0.01 °C以内で一致します。

キャリブレーション:NTCを信頼できる温度計にする

  1. 固定抵抗を測る:10 kΩの抵抗の実際の値をテスターで測り、コードのSERIES_Rに入力します。1%のずれだけで約0.2 °Cの誤差になります。
  2. NTCを防水にする:むき出しのエポキシ型NTCを水に入れないでください。足を熱収縮チューブとシリコンで絶縁するか、ステンレス製プローブ入りの市販のNTCを使います。
  3. 0 °Cの点:コップの縁まで砕いた氷を入れ、冷たい水を少し加えてかき混ぜます。NTCをコップの中央に2〜3分入れておき、値が落ち着いたらシリアルモニタのRの値を記録します。
  4. 室温の点:風の当たらない場所で、NTCを信頼できるデジタル温度計の横に10分置きます。温度計の表示とNTCの抵抗値を記録します。
  5. 高温の点:水は海面の高さでは100 °Cで沸騰しますが、標高300 mごとに沸点が約1 °C下がります(1000 mで約96.7 °C)。鍋の底に触れないようにNTCを沸騰したお湯に入れ、抵抗値を記録します。
  6. 値をコードに入力する:3つの点をSteinhart-Hartのコードに入力します。室温付近しか測らない場合は、1点だけのオフセット補正(一定の差を引く)で十分なことも多いです。
誤差がどこから来るかを知れば、どこに手間をかけるべきかがわかります。10 kΩ、B3950のNTCの場合、R25の誤差±1%は約±0.2 °C、Bの誤差±1%は0 °Cで±0.2 °C、100 °Cで±0.9 °Cに相当します。5 V、10 kΩの分圧回路では、NTCが消費する電力は最大0.625 mWで、静止空気中では自己発熱によって約0.3〜0.4 °C温度が上がります。これを減らすには、分圧回路を5Vではなくデジタルピンから給電し、測定するときだけHIGHにするか、100 kΩのNTCと100 kΩの固定抵抗を使います。後者の場合は、A0とGNDの間に100 nFのコンデンサを追加してください。ATmega328PのADCは、信号源インピーダンスが約10 kΩ以下になるように設計されているからです。

LCDに表示するNTC温度計

パソコンなしで測定値を表示するために、16x2のI2C LCDを追加しましょう。ディスプレイのSDAピンをA4、SCLをA5、VCCを5V、GNDをGNDにつなぎます。NTCの回路はそのままです。コードでは、ライブラリマネージャからインストールできるLiquidCrystal I2Cライブラリを使います。ディスプレイのアドレスは通常0x27で、モジュールによっては0x3Fです。度の記号には、LCDの文字テーブルにある223番の文字を表示します。ディスプレイの下の行には、Arduinoの電源を入れてから測った最低温度と最高温度も表示されます。

I2C 2x16 LCDディスプレイ
16x2のI2C LCD:裏側のI2Cモジュールのおかげで、4本の線(GND、VCC、SDA、SCL)だけでつながります。青い半固定抵抗でコントラストを調整します。
C++ (Arduino IDE)
1#include <Wire.h>
2#include <LiquidCrystal_I2C.h>
3
4LiquidCrystal_I2C lcd(0x27, 16, 2);   // adres 0x27 ya da 0x3F / address 0x27 or 0x3F
5
6const int NTC_PIN = A0;
7const float SERIES_R = 10000.0;
8const float R_NOMINAL = 10000.0;
9const float T_NOMINAL_K = 298.15;
10const float BETA_K = 3950.0;
11
12float minC = 999.0;                   // en düşük değer / lowest value
13float maxC = -999.0;                  // en yüksek değer / highest value
14
15float readTempC() {
16  long sum = 0;
17  for (int i = 0; i < 16; i++) {
18    sum += analogRead(NTC_PIN);
19  }
20  float adc = sum / 16.0;
21  if (adc < 1.0 || adc > 1022.0) return NAN;             // sensör hatası / sensor error
22  float r = SERIES_R * (1023.0 - adc) / adc;
23  return 1.0 / (1.0 / T_NOMINAL_K + log(r / R_NOMINAL) / BETA_K) - 273.15;
24}
25
26void setup() {
27  lcd.init();
28  lcd.backlight();
29}
30
31void loop() {
32  float t = readTempC();
33  lcd.clear();
34  if (isnan(t)) {
35    lcd.print(F("Sensor hatasi"));
36  } else {
37    if (t < minC) minC = t;
38    if (t > maxC) maxC = t;
39    lcd.print(F("Sicaklik "));
40    lcd.print(t, 1);
41    lcd.print((char)223);             // derece işareti / degree symbol
42    lcd.print('C');
43    lcd.setCursor(0, 1);              // ikinci satır / second row
44    lcd.print(F("Min"));
45    lcd.print(minC, 1);
46    lcd.print(F(" Max"));
47    lcd.print(maxC, 1);
48  }
49  delay(1000);
50}

ESP32でNTCサーミスタを使う

ESP32のADCは12ビット(0〜4095)で、チップは3.3 Vで動作するので、分圧回路は3V3ピンから給電します。NTCは必ずADC1のピン(GPIO 32〜39)につないでください。ADC2のピンは、Wi-Fiがオンの間は読み取れません。ボードのピン配置は「ピン配置」ツールで確認できます。ここには重要な違いがあります。ESP32のADCは電源電圧を基準にせず、約1.1 Vの内部基準電圧と選択した減衰(アッテネーション)を使います。そのため、Unoで得られるレシオメトリック測定は自動的には成り立たず、3V3ラインの実際の値を知る必要があります。そこでコードでは、工場でチップに書き込まれたキャリブレーションデータを使うanalogReadMilliVolts()でミリボルト単位の値を読み取り、テスターで測った3V3の値をもとに抵抗値を計算します。Espressifのドキュメントによると、無印ESP32は標準の11 dBの減衰で150〜3100 mVを測れますが、推奨される最も直線的な範囲は150〜2450 mVです。これらの限界によって、測れる温度範囲は配線ごとに次のように決まります。

配線(3.3 V、10 kΩ)150〜2450 mV(最も正確)150〜3100 mV(全範囲)
NTCが上側:3V3 – NTC – GPIO 34 – 10 kΩ – GND約−30〜+50 °C約−30〜+100 °C
NTCが下側:3V3 – 10 kΩ – GPIO 34 – NTC – GND約+3〜+114 °C約−26〜+114 °C
C++ (Arduino IDE)
1const int NTC_PIN = 34;            // ADC1_CH6, Wi-Fi açıkken de çalışır / works while Wi-Fi is on
2const float VCC_MV = 3300.0;       // 3V3 pinini multimetreyle ölçüp yaz / measure the 3V3 pin and write it here
3const float SERIES_R = 10000.0;
4const float R_NOMINAL = 10000.0;
5const float T_NOMINAL_K = 298.15;
6const float BETA_K = 3950.0;
7const int SAMPLES = 64;            // ortalama için ölçüm sayısı / number of samples to average
8
9void setup() {
10  Serial.begin(115200);
11  analogReadResolution(12);                     // 0–4095
12  analogSetPinAttenuation(NTC_PIN, ADC_11db);   // varsayılan zayıflatma / default attenuation
13}
14
15void loop() {
16  uint32_t sum = 0;
17  for (int i = 0; i < SAMPLES; i++) {
18    sum += analogReadMilliVolts(NTC_PIN);       // kalibre edilmiş mV / calibrated millivolts
19    delay(1);
20  }
21  float mv = sum / (float)SAMPLES;
22
23  if (mv < 150.0 || mv > 3100.0) {              // ADC aralığı dışında / outside the ADC range
24    Serial.println("Aralik disi / Out of range");
25    delay(1000);
26    return;
27  }
28
29  float rNtc = SERIES_R * (VCC_MV - mv) / mv;   // NTC üstte / NTC on the high side
30  float tempC = 1.0 / (1.0 / T_NOMINAL_K + log(rNtc / R_NOMINAL) / BETA_K) - 273.15;
31  Serial.printf("Gerilim / Voltage: %.0f mV  R: %.0f ohm  Sicaklik / Temp: %.2f C\n", mv, rNtc, tempC);
32  delay(1000);
33}

室内や屋外の温度計には、NTCを上側に置く配線が最適です。電気ケトル、コーヒーメーカー、3Dプリンターのベッドなど、50 °Cを超える温度を測る場合は、NTCを下側に移し、式をRntc = Rs × mV / (Vcc − mV)に変えます。Wi-FiがオンだとESP32の電流の急増で3V3ラインに小さなリップルが生じます。64回の読み取りを平均し、GPIO 34とGNDの間に100 nFのコンデンサを入れると、結果がはっきり改善します。ESP32が初めての場合は、セットアップについて「ESP32とは?」の記事をご覧ください。

Raspberry Pi PicoとMicroPythonでNTCを使う

Picoの12ビットADCはGP26、GP27、GP28のピンにあり、MicroPythonのread_u16()は結果を0〜65535の範囲に拡大して返します。PicoのADCの基準電圧(ADC_VREF)は、ボード上で3.3 Vラインから小さなRCフィルタを通して作られています。分圧回路も3V3(OUT)ピンから給電すれば、Unoと同じようにほぼレシオメトリック測定になり、式も変わりません。1023の代わりに65535を使うだけです。PicoのADCは少しノイズが多く、特定のコードで値が小さく跳ぶことがあるので、ここでも平均は欠かせません。アナロググラウンドとしてAGND(ピン33)を使うと、ノイズが少し減ります。Picoを初めて使う場合は、MicroPythonのセットアップを「Raspberry Pi Picoとは?」の記事で紹介しています。

MicroPython
1from machine import ADC
2import math
3import time
4
5ntc = ADC(26)                # GP26 = ADC0, fiziksel pin 31 / physical pin 31
6SERIES_R = 10000             # sabit direnç / fixed resistor
7R_NOMINAL = 10000            # NTC'nin 25 °C'deki direnci / NTC resistance at 25 °C
8T_NOMINAL_K = 298.15         # 25 °C kelvin cinsinden / 25 °C in kelvin
9BETA_K = 3950                # B25/50 değeri / B25/50 value
10SAMPLES = 64                 # ortalama için ölçüm sayısı / number of samples to average
11
12
13def read_temp_c():
14    total = 0
15    for _ in range(SAMPLES):
16        total += ntc.read_u16()          # 0–65535
17    raw = total / SAMPLES
18    if raw < 100 or raw > 65435:
19        return None                      # kopuk ya da kısa devre / open or shorted
20    r_ntc = SERIES_R * (65535 - raw) / raw          # NTC üstte / NTC on the high side
21    temp_k = 1 / (1 / T_NOMINAL_K + math.log(r_ntc / R_NOMINAL) / BETA_K)
22    return temp_k - 273.15
23
24
25while True:
26    t = read_temp_c()
27    if t is None:
28        print("Sensor hatasi / Sensor error")
29    else:
30        print("Sicaklik / Temp: {:.2f} C".format(t))
31    time.sleep(1)

MicroPythonのmath.log()も自然対数なので、Arduinoのコードと同じ式を使います。Picoには内蔵の温度センサー(ADC(4))もありますが、周囲ではなくチップ自体の温度を測るので、動作中はたいてい数度高く表示されます。周囲の温度を測るなら、外付けのNTCのほうがずっと正確です。Steinhart-Hartの係数を使いたい場合は、ArduinoのコードのcomputeCoefficients()関数を数行でPythonに書き換えられます。

NTCとPTCの違いは?

PTC(Positive Temperature Coefficient、正の温度係数)サーミスタでは、温度が上がると抵抗値が上がります。最も一般的なPTCは、測定ではなく保護に使われます。チタン酸バリウムのセラミックでできたスイッチング型PTCは、ある温度(キュリー点)までは低い抵抗値を保ち、それを超えると抵抗値が急に数百倍から数千倍に跳ね上がります。モーター巻線の過熱保護や、自己温度制御型のPTCヒーターはこの原理で動きます。ポリマー製の復帰型ヒューズ(ポリスイッチ)も同じようにふるまい、Arduino UnoのUSBラインにある500 mAのヒューズもその1つです。一方、KTY81のようなシリコンPTCセンサーは、約0.7〜0.8%/°Cでほぼ直線的に変化します。PT100やPT1000のような白金測温抵抗体(RTD)も正の係数を持ちますが、サーミスタではなく金属のセンサーです。0 °Cで100 Ωまたは1000 Ωを示し、500 °Cを超える温度まで測れ、読み取りにはMAX31865のようなアンプが必要です。

特性NTCサーミスタスイッチング型PTCPT100 / PT1000(RTD)
温まったときの抵抗値下がる(25 °Cで約−4.4%/°C)あまり変わらず、スイッチング温度で急上昇上がる(約+0.385%/°C)
曲線指数関数的で、直線的ではない急な跳ね上がり(スイッチのよう)ほぼ直線的
一般的な範囲−40〜+125 °C(ガラス封止型は250〜300 °C)スイッチング温度はモデルごとに選ぶ(例:80 °C、120 °C)−200〜+500 °C以上
主な用途温度測定、突入電流の制限過熱保護と過電流保護産業用の精密測定
Arduinoでの読み取り分圧回路+アナログピン通常は測定に使わないMAX31865のようなアンプモジュールで読む
価格とても安い安いほかより高い

3Dプリンターとバッテリーでの応用

3Dプリンターでは、ホットエンドとベッドの温度のどちらも、ほとんどがNTCサーミスタで測られています。ここでは10 kΩではなく100 kΩのNTCが使われます。250 °Cでは10 kΩのNTCの抵抗値が35 Ω前後まで下がり、測定の分解能が失われるからです。人気のファームウェアMarlinの設定ファイルにも、汎用の10 kΩサーミスタについて「ホットエンドには使わないこと。高温では分解能が悪い」という警告が書かれています。RAMPSのような8ビットボードでは、サーミスタの入力は4.7 kΩの抵抗で5 Vにプルアップされており、MarlinはADCの値を用意された表で温度に変換します。100 kΩ B3950のサーミスタ向けに定義されたタイプの1つが11番です。サーミスタの線が切れるとADCは最大値を読み、ファームウェアはこれを極端な低温とみなしてErr: MINTEMPを表示します。ショートするとErr: MAXTEMPになります。サーミスタがソケットから抜けると、ヒーターは加熱を続けるのに測定値は上がりません。MarlinはこれをTHERMAL RUNAWAY(熱暴走)保護で検出し、ヒーターを切ります。この保護は絶対に無効にしないでください。

リチウムイオン電池は、0 °C未満や約45 °Cを超える温度で充電してはいけません。低温で充電するとセルの内部に金属リチウムが析出し、元に戻らない損傷を与えます。そのため、スマホ、ノートパソコン、電動自転車のバッテリーの多くにはセルにNTCが貼り付けてあり、バッテリーのコネクタの3つ目の端子(TまたはNTCと表示)はたいていこのサーミスタにつながっています。人気の充電ICTP4056の1番ピン(TEMP)は、この役目のためにあります。データシートによると、このピンの電圧が0.15秒を超えて入力電圧の45%未満または80%超のままだと、充電が一時停止されます。自分のバッテリープロジェクトでは、NTCをセルに貼り付けてArduinoで読み取り、温度が範囲外になったらMOSFETで充電回路を切ることができます。電源では、大きなディスク型NTCが、電源を入れたときにコンデンサに流れ込む突入電流を制限します。温まると抵抗値が数Ωから1 Ω未満に下がるので、通常の動作中の損失はごくわずかです。

TP4056 Li-ion充電モジュール
USB-C入力と保護回路付きのTP4056充電モジュール:ICのTEMPピンは、NTCでセルの温度を監視できます。市販のモジュールの多くはこのピンがGNDにつながれていて、この機能は無効になっています。

NTCサーミスタを使ったプロジェクトのアイデア

  • ヒステリシス付きのファン用サーモスタット:温度が30 °Cを超えたらリレーモジュールでファンをオンにし、28 °Cまで下がったらオフにします。2度の差があるので、リレーがカチカチと切り替わり続けることがありません。
  • 防水プローブ付きのアクアリウム用温度計:ステンレス製のNTCプローブで水温を測り、ヒーターが故障したらブザーで知らせます。
  • OLEDディスプレイ付きのポケット温度計:温度と直近1時間のグラフをOLEDディスプレイに表示します。
  • 3Dプリンターのエンクロージャー監視:閉じたエンクロージャー内の温度を測り、45 °Cを超えたら排気ファンを回します。
  • バッテリーの温度ガード:充電中のセルの温度を監視し、0〜45 °Cの範囲外では充電を止めてLEDで警告します。
  • Wi-Fi温度ロガー:ESP32で1分ごとに測定値をSDカードに記録するか、スマホで開くWebページに表示します。

よくある間違いと対処法

症状考えられる原因対処法
値がいつも1023か0固定抵抗がない、線の断線、またはNTCのショート分圧回路を確認する。25 °Cなら、テスターでA0に約2.5 Vが出ているはず
温まると温度が下がるNTCと固定抵抗が逆配線を直すか、もう一方の配線の式を使う
結果が−273.15 °C、inf、nanになるanalogReadが0を返し、ゼロ除算が起きている線を確認する。コードの範囲チェックは削除しない
25 °C付近は正しいが、離れるとかなりずれるlnの代わりにlog10()を使っている、またはB定数が違う(例:3435のNTCに3950を入力)log()を使い、NTCのデータシートのB定数を入力する
値がいつも1〜2 °C高い自己発熱、またはNTCがレギュレーターやESP32モジュールに近い測定するときだけ分圧回路に給電し、ケーブルでNTCをボードから離す
読み取り値がふらつくノイズ、長い配線、ブレッドボードの接触不良平均を取る、100 nFのコンデンサを追加する、線をより合わせる
ESP32で低温や高温のときにおかしな値になる電圧が、ADCの直線的な150〜2450 mVの範囲から外れている測る範囲に合わせて配線を選ぶ(ESP32の表を参照)
ESP32でWi-Fiが始まると読み取りに失敗するNTCがADC2のピンにつながっているGPIO 32〜39のADC1のピンのどれかを使う
反応がとても遅い太いプローブやケースの熱容量異常ではない。速く反応させたいなら、細いエポキシビーズ型かSMDのNTCを選ぶ
NTC、LM35、DS18B20のどれにするか迷ったら、こう考えましょう。NTCは最も安く、反応が最も速く、パッケージの選択肢も最も多いセンサーですが、精度はキャリブレーションしだいです。DS18B20は工場出荷時から±0.5 °Cの精度があり、デジタル出力なので長いケーブルでも信頼でき、1本のピンに複数のセンサーをつなげます。LM35は直線的なアナログ出力ですが、4 V以上の電源が必要です。詳しい比較は「温度センサーの比較」を、ADCの仕組みを深く知りたい場合は「ADCとアナログ-デジタル変換」の記事をご覧ください。

NTCサーミスタを使うと、1本の抵抗と数行の計算で、安価な部品を正確な温度計に変える方法が身につきます。分圧回路、ADC、対数、キャリブレーションがすべてそろっています。同じ考え方は、この先ほかのアナログセンサーでも使います。測定値をさらになめらかにするには、「センサーデータのフィルタリング」の手法も見てみましょう。BlueGraysアプリには、「NTCと2x16 LCDディスプレイで温度を測定」、「DHT11で温度と湿度を測定」、LCD付きのESP32温度ステーション、温度データロガーのプロジェクトがあり、それぞれステップごとの回路図とすぐに使えるコードがそろっています。

よくある質問

NTCサーミスタは何に使われますか?

NTCサーミスタは、温度が上がると抵抗値が下がる半導体の抵抗です。主に温度の測定に使われ、3Dプリンター、エアコン、冷蔵庫、バッテリーパック、デジタル温度計はたいていNTCで温度を測っています。大きなディスク型は、電源の突入電流を制限するために使われます。

NTCサーミスタをテスターで確認するには?

テスターを抵抗レンジにして、NTCの2本の足の間を測ります。10 kΩのNTCなら、25 °Cで約10 kΩ、20 °Cで約12.5 kΩを示すはずです。次にNTCを指でつまむと、数秒で抵抗値がはっきり下がるはずです。表示がOL(開放)やゼロに近い値なら、サーミスタは故障しています。

NTCとPTCの違いは何ですか?

NTCは温まると抵抗値が下がり、PTCは上がります。NTCは主に温度の測定と突入電流の制限に使われます。最も一般的なPTCは、ある温度で抵抗値が急に跳ね上がる保護用の部品で、モーターの過熱保護や自己温度制御型のヒーターがこの仕組みで動きます。

10kのNTCサーミスタにはどの抵抗を使えばいいですか?

室温付近を測るなら、25 °CでのNTCの値と同じ10 kΩの抵抗を使います。分圧回路は、その温度で感度が最も高くなります。特定の範囲を測る場合は、範囲の両端でのNTCの抵抗値の幾何平均が最適な値で、たとえば0〜100 °Cなら約4.7 kΩです。精度のために、誤差1%の金属皮膜抵抗を選びましょう。

サーミスタのB定数(3950)は何を意味しますか?

B定数は、NTCの抵抗値が温度によってどれだけ速く変わるかを表す材料定数で、単位はケルビンです。B25/50 = 3950は、25 °Cと50 °Cの抵抗値から計算したという意味です。コードでNTCの実際のB定数を使わないと、25 °Cから離れるほど誤差が大きくなります。

NTCサーミスタ、DS18B20、LM35のどれがよいですか?

速さ、安さ、小ささならNTCを選びましょう。キャリブレーションなしで±0.5 °Cの精度と長いケーブルが必要なら、DS18B20のほうが適しています。LM35は直線的なアナログ出力ですが、4 V以上の電源が必要なので、3.3 VのESP32やPicoでは扱いにくくなります。125 °Cを超える温度(たとえば3Dプリンターのホットエンド)には、ガラス封止型のNTC、PT100、または熱電対が必要です。

全プロジェクトを見る
NTCと2x16 LCDディスプレイで温度を測定
#44初級
プレミアム

NTCと2x16 LCDディスプレイで温度を測定

小さなビーズのようなセンサーで周囲の温度を測ります。NTCというこの部品は、温まるほど電気が流れやすくなります。Arduinoがその変化を読み取り、数式で摂氏温度に変換して、2行のLCDディスプレイに0.5秒ごとに表示します。手のひらでセンサーを温めて、数値が上がる様子を見るのも楽しみの1つです。

4.5(33)
44
DHT11で温度と湿度を測定
#55中級

DHT11で温度と湿度を測定

部屋の温度は何度で、空気は湿っているでしょうか、それとも乾燥しているでしょうか?DHT11センサーが温度と湿度を測定し、Arduinoが2行のLCDディスプレイに値を表示して、数秒ごとに更新します。センサーに異常があればエラーメッセージが表示されます。自分だけの小さな気象観測装置を作る第一歩です。

4.7(47)
73
LDRで光の強さを測定
#11初級

LDRで光の強さを測定

部屋の明るさを数値で見てみませんか?光に反応する小さな部品、LDRで周囲の光を測定し、Arduinoが0.5秒ごとにその値をコンピューターの画面に表示します。手で覆うと数値が変わる様子を確認できます。自動で点灯する常夜灯などのプロジェクトへの第一歩です。

4.6(81)
139
ESP32とLDRモジュールで光の強さを読み取る
#113初級

ESP32とLDRモジュールで光の強さを読み取る

LDRモジュールの生のADC値と、暗い状態・明るい状態の基準値から計算した相対的な明るさの割合を、シリアルモニタでリアルタイムに確認します。この割合はルクスの測定値ではありません。モジュールの校正の仕組みを学べます。しきい値の決定に使うため、プロジェクト10の前に取り組むのが適しています。

4.6(36)
55
ESP32 DHT22温湿度計(LCDディスプレイ付き)
#117中級

ESP32 DHT22温湿度計(LCDディスプレイ付き)

DHT22センサーで周囲の温度と湿度を測定し、16x2 I2C LCDにリアルタイムで表示するプロジェクトです。Adafruit DHTライブラリを使い、1本の信号線を使うプロトコルでセンサーからデータを読み取ります。IoT気象観測装置やスマートホームの自動化、温室の環境監視システムの基礎となります。ESP32のGPIO 4ピンを介してDHT22と通信します。

4.8(38)
56
ESP32温度データロガー(DHT22 + DS1307 RTC + microSD + OLED)
#144上級
プレミアム

ESP32温度データロガー(DHT22 + DS1307 RTC + microSD + OLED)

ESP32で日時付きの温度・湿度記録システムを作ります!DHT22で1分ごとに温度と湿度を読み取り、DS1307 RTCから取得した日時とともにmicroSDカードへCSV形式で記録します。OLEDには最新の温度を大きな文字で表示し、湿度のパーセント値、日時、総記録数も表示します。SDカードの/temp_log.csvファイルはExcel、Google Sheets、Pythonのpandasで開いて分析できます。温室の監視、家や部屋の温度管理、実験室のデータ収集、食品の保管環境や養蜂箱の監視に適しています。

4.7(7)
12
I2CでLCDディスプレイを使う
#32初級
プレミアム

I2CでLCDディスプレイを使う

Arduinoにディスプレイを接続し、最初のメッセージを表示します。2行のLCDディスプレイは数本の配線だけで接続できます。まず上の行にあいさつを表示し、次に下の行にもう1つのメッセージを表示します。その後、表示を消去して最初から繰り返します。温度や時刻、スコアを表示するプロジェクトは、すべてこのステップから始まります。

4.8(53)
70
LCDディスプレイ付きデジタル電圧計
#56中級
プレミアム

LCDディスプレイ付きデジタル電圧計

自作の測定器で、電池や電源アダプターが出力する電圧を調べます。2つの抵抗で作る分圧回路が、高い電圧をボードで読み取れるレベルまで下げます。Arduinoが元の電圧を計算し、2行のLCDディスプレイにボルト単位で表示します。この回路では約55ボルトまでの直流電圧を測定できます。コンセントの商用電源には絶対に接続しないでください。

4.5(27)
36