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サーミスタとは?その仕組みは?
サーミスタ(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 °C | 105.4 kΩ | 0.433 V | 89 | 0.20 °C |
| 0 °C | 33.6 kΩ | 1.146 V | 235 | 0.10 °C |
| 10 °C | 20.2 kΩ | 1.657 V | 339 | 0.09 °C |
| 20 °C | 12.5 kΩ | 2.219 V | 454 | 0.09 °C |
| 25 °C | 10.0 kΩ | 2.500 V | 512 | 0.09 °C |
| 30 °C | 8.04 kΩ | 2.772 V | 567 | 0.09 °C |
| 40 °C | 5.30 kΩ | 3.268 V | 669 | 0.11 °C |
| 50 °C | 3.59 kΩ | 3.680 V | 753 | 0.13 °C |
| 60 °C | 2.49 kΩ | 4.004 V | 819 | 0.17 °C |
| 80 °C | 1.27 kΩ | 4.436 V | 908 | 0.31 °C |
| 100 °C | 698 Ω | 4.674 V | 956 | 0.57 °C |
| 125 °C | 359 Ω | 4.827 V | 988 | 1.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 Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| NTCの足1 | 5V | 3V3 | 3V3(OUT)、ピン36 |
| NTCの足2+10 kΩの抵抗の片側 | A0 | GPIO 34(ADC1) | GP26 / ADC0、ピン31 |
| 10 kΩの抵抗のもう片側 | GND | GND | AGND、ピン33 |
| 100 nFのコンデンサ(任意) | A0とGNDの間 | GPIO 34とGNDの間 | GP26とAGNDの間 |
| 配線 | A0の電圧 | NTCの抵抗値(10ビット) | 温まったときのanalogRead |
|---|---|---|---|
| NTCが上側:5V – NTC – A0 – 10 kΩ – GND | Vcc × Rs / (Rs + Rntc)(Rs=固定抵抗) | Rntc = Rs × (1023 − adc) / adc(adc=読み取り値) | 上がる |
| NTCが下側:5V – 10 kΩ – A0 – NTC – GND | Vcc × Rntc / (Rs + Rntc)(Rs=固定抵抗) | Rntc = Rs × adc / (1023 − adc)(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で最初の測定をする手順
- NTCと10 kΩの抵抗をブレッドボードに挿します。NTCの片方の足を5Vに、もう片方の足を抵抗の片側につなぎます。
- 抵抗のもう片側をGNDにつなぎ、NTCと抵抗の接続点からA0へジャンパーワイヤーを配線します。
- 下のコードを書き込み、シリアルモニタを9600ボーで開きます。
- 室温では20〜25 °C前後の値が表示されるはずです。NTCを2本の指でつまむと、数秒で値が30 °Cに向かって上がっていきます。
- 温まると値が下がる場合は、NTCと抵抗が逆になっています。配線を直すか、コードの式を「NTCが下側」の式に置き換えてください。
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()の中で係数を自動的に計算します。
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を信頼できる温度計にする
- 固定抵抗を測る:10 kΩの抵抗の実際の値をテスターで測り、コードのSERIES_Rに入力します。1%のずれだけで約0.2 °Cの誤差になります。
- NTCを防水にする:むき出しのエポキシ型NTCを水に入れないでください。足を熱収縮チューブとシリコンで絶縁するか、ステンレス製プローブ入りの市販のNTCを使います。
- 0 °Cの点:コップの縁まで砕いた氷を入れ、冷たい水を少し加えてかき混ぜます。NTCをコップの中央に2〜3分入れておき、値が落ち着いたらシリアルモニタのRの値を記録します。
- 室温の点:風の当たらない場所で、NTCを信頼できるデジタル温度計の横に10分置きます。温度計の表示とNTCの抵抗値を記録します。
- 高温の点:水は海面の高さでは100 °Cで沸騰しますが、標高300 mごとに沸点が約1 °C下がります(1000 mで約96.7 °C)。鍋の底に触れないようにNTCを沸騰したお湯に入れ、抵抗値を記録します。
- 値をコードに入力する:3つの点をSteinhart-Hartのコードに入力します。室温付近しか測らない場合は、1点だけのオフセット補正(一定の差を引く)で十分なことも多いです。
LCDに表示するNTC温度計
パソコンなしで測定値を表示するために、16x2のI2C LCDを追加しましょう。ディスプレイのSDAピンをA4、SCLをA5、VCCを5V、GNDをGNDにつなぎます。NTCの回路はそのままです。コードでは、ライブラリマネージャからインストールできるLiquidCrystal I2Cライブラリを使います。ディスプレイのアドレスは通常0x27で、モジュールによっては0x3Fです。度の記号には、LCDの文字テーブルにある223番の文字を表示します。ディスプレイの下の行には、Arduinoの電源を入れてから測った最低温度と最高温度も表示されます。

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 |
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とは?」の記事で紹介しています。
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サーミスタ | スイッチング型PTC | PT100 / 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 Ω未満に下がるので、通常の動作中の損失はごくわずかです。

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

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

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

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

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

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

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

LCDディスプレイ付きデジタル電圧計
自作の測定器で、電池や電源アダプターが出力する電圧を調べます。2つの抵抗で作る分圧回路が、高い電圧をボードで読み取れるレベルまで下げます。Arduinoが元の電圧を計算し、2行のLCDディスプレイにボルト単位で表示します。この回路では約55ボルトまでの直流電圧を測定できます。コンセントの商用電源には絶対に接続しないでください。
ほかの記事
BlueGraysアプリ
この回路をスマホでステップごとに作る
回路図、コード、部品リストを1つの画面で確認できます。Arduino、ESP32、Picoのプロジェクトを200件以上用意しています。

