ATtiny202のような超小型マイコンでも、工夫次第で高精度な温度測定が可能です。
今回はアナログ温度センサー「MCP9700」を使い、内部1.1V基準+ADC+自作SerialUPDIライブラリを組み合わせた軽量温度モニターを作成します。
フラッシュ使用量はわずか962バイト。
ノイズ対策や精度向上のテクニックも含めて、実用レベルの温度計を構築していきます。
この記事でできること
- ATtiny202で温度測定 (秋月電子 80円)
- MCP9700の使い方 (秋月電子 40円で購入)
- 内部基準電圧を使った高精度ADC測定
- 超軽量UART出力(SerialUPDI活用)
リポジトリURL:https://github.com/asa-lab-bit/SimpleUART
使いかたは私のこちらのブログで確認してください。 - ノイズ対策(平均化)
使用部品
- ATtiny202 (SSOP-8)
- MCP9700(アナログ温度センサー)
- 書き込み用:SerialUPDI
- USBシリアル変換モジュール(CH340など)シリアル通信用です
接続図

接続ポイント
- MCP9700 OUT → PA3(ADC入力)
- MCP9700 VDD → VCC(5V or 3.3V)
- MCP9700 GND → GND
- UART TX → USBシリアルRX
👉 ポイント
- ADC入力ピンはアナログ専用にするためデジタル入力を無効化
- ノイズ対策として配線は短く
動作確認

表示:

完成プログラム
#include <SimpleUART.h>
#include <string.h>
// Initialize with 16 bytes buffer
SimpleUART<16> myUART;
// Interrupt handler 今回使用しない
//ISR(USART0_RXC_vect) {
// myUART.handle_interrupt();
//}
void setup() {
// 1. 基準電圧(VREF)を1.1Vに設定
VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc;
// 2. ADCの基準として「内部VREF」を使用するように設定
// ※VREF.CTRLA だけでなく、このADC0.CTRLCが「心臓部」です
ADC0.CTRLC = ADC_PRESC_DIV16_gc // ADCクロックを適切に設定しないとだめです(16分周)
| ADC_REFSEL_INTREF_gc; // ★内部基準(VREF)を選択★
// 3. 10ビットモードに設定
ADC0.CTRLB = ADC_RESSEL_10BIT_gc;
// 4. ADCを有効化
ADC0.CTRLA = ADC_ENABLE_bm;
// 5. 基準電圧が安定するまで少し待つ(おまじないですが重要です)
delay(15);
// 6. ピンの設定 (7番ピン/PA3)
PORTA.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc;
myUART.init(9600);
myUART.send_string("--- ATtiny202 Calibration Start ---\r\n");
//myUART.println("--- ATtiny202 Calibration Start ---"); こちらでもok少しプログラムサイズ増えるかも
}
void loop() {
uint16_t sum = 0; // 1023 * 8 = 8184 なので 16bit(uint16_t)で十分収まります
for (uint8_t i = 0; i < 8; i++) {
ADC0.MUXPOS = ADC_MUXPOS_AIN3_gc;
ADC0.COMMAND = ADC_STCONV_bm;
while (!(ADC0.INTFLAGS & ADC_RESRDY_bm));
sum += ADC0.RES;
delay(20); // 1/50秒待つ(ノイズ対策)
}
// 8で割る (3ビット右シフト)
int avgAdc = sum >> 3;
//myUART.print(avgAdc);
// --- ここから先はこれまでの計算式 ---
long voltageMV = (avgAdc * 1095L) >> 10;
// ...続く
// 3. 温度計算 (MCP9700: 500mV = 0度, 10mV = 1度)
int tempX10 = (int)(voltageMV - 528);
// 4. 表示 (SimpleUARTを使用)
myUART.send_string("Temp: ");
//myUART.print("Temp: "); こちらでもok 少しプログラムサイズ増えるかも
myUART.print(tempX10 / 10); // 整数部
myUART.send_string(".");
myUART.print(abs(tempX10 % 10)); // 小数第1位
myUART.send_string(" C\r\n");
//myUART.println(" C"); こちらでもok
delay(2000); // 2秒おきに更新
}プログラム解説
① 内部基準電圧1.1Vを使用
VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc;外部電源の変動に影響されないため、測定精度が安定します。
AVRマイコンのATtiny202(tinyAVR 0シリーズ)において、内蔵の基準電圧(VREF)は非常に柔軟に設定可能です。
内部リファレンス(Internal Reference)として、以下の電圧を選択できます
0.55v 1.1v 1.5v 2.5v 4.3v
ATtiny202は「8ビット」か「10ビット」の2択ですが、上位モデルの ATtiny1614(tinyAVR 1シリーズ)になると「12ビット」という超精密モードが選べるようになります。
202 と 1614 の「解像度」の違い
もし基準電圧を 1.1V に設定して比較すると、1目盛り(最小単位)の細かさはこれだけ変わります。
| マイコン | 設定 (RESSEL) | 段階数 | 1目盛りの電圧 | 温度に換算(MCP9700) |
| ATtiny202 | 10BIT | 1,024 | 1.07 mV | 約 0.10 ℃ |
| ATtiny1614 | 12BIT | 4,096 | 0.27 mV | 約 0.02 ℃ |
② ADC設定(10ビット)
ADC0.CTRLB = ADC_RESSEL_10BIT_gc;1024段階で電圧を測定。
③ ノイズ対策(8回平均)
sum += ADC0.RES;さらに:
int avgAdc = sum >> 3;👉 割り算をビットシフトで高速化
👉 50Hzノイズ対策として20ms間隔
④ 電圧計算(軽量化テクニック)
long voltageMV = (avgAdc * 1095L) >> 10;👉 浮動小数点を使わず整数演算で処理
👉 メモリ削減&高速化
⑤ 温度変換(MCP9700)
int tempX10 = (int)(voltageMV - 528);MCP9700の特性:
- 0℃ = 約500mV
- 10mV/℃
👉 微調整済み(528mVオフセット)
⑥ シリアル出力(軽量UART)
myUART.print(tempX10 / 10);👉 自作UARTでメモリ削減
👉 Serialより圧倒的に軽量
精度をさらに上げるポイント
- 電源を安定化(LDO使用)
- GNDをしっかり取る
- センサー周辺にコンデンサ追加(0.1uF)
- 温度補正値を実測で微調整
まとめ
ATtiny202のような小さなマイコンでも、
- 内部基準電圧
- 平均化処理
- 整数演算
- 軽量UART
といった工夫を組み合わせることで、実用レベルの高精度温度計を作ることができます。
特に今回の構成は1KB未満で動作するため、
ATtinyシリーズや小容量マイコンを使った開発のベースとして非常におすすめです。
ぜひ、自分なりに改良して温度ログや表示機能にも挑戦してみてください。



