Asi_a が 2021年05月20日16時04分56秒 に編集
初版
タイトルの変更
秋月サーモパイルで非接触温度計を作った
タグの変更
PIC32
サーモパイル
メイン画像の変更
本文の変更
# はじめに elchika世間がObniz一色な中何も関係ない記事を投稿していくスタイル。 [2月に秋月が売り出したやっすいサーモパイル](https://akizukidenshi.com/catalog/g/gI-15815/)を使ってナウい感じな非接触温度計を作りたかった。 # サーモパイルとは **サーモパイルは変な使い方をしている熱電対**という理解をしてもらえればいいと思う。 まず、熱電対の片方の金属片に光を当てると温まってそれで電位差が生じる。光が強ければより温まってより大きな電位差が生じる。サーモパイルでは、入力光をフィルターで、室温付近での熱放射の主成分である赤外線付近に限定してしまうことで、熱放射のエネルギーがだいたい分かるというもの、らしい。 これによって彼我の温度**差**を得られるが、実温度は得られないので、サーミスタを同梱してサーモパイル自体の温度も得るタイプが一般ぽい。 # 全体的な方針 * 電源にはNi-MHx2を使用し、HT7733Aで**約**3.3Vに昇圧し、アナログ系統にはシャントレギュレーターで3.3Vを2.495Vに降圧したものを用いる。 * サーモパイルとサーミスタの出力はオペアンプを通してPICに送る。 * 温度表示は定番の8x2のI2CのLCD。 * 細かい調整などは回路側ではなく、マイコン側で頑張る。 # 使用した主要な部品リスト |部品|点数|備考| |---|---|---| |[サーモパイル ISB-TS45D](https://akizukidenshi.com/catalog/g/gI-15815/)|1|I-15815、本作の目玉、実際安い| |[PIC32MX120F032B-I/SP](https://akizukidenshi.com/catalog/g/gI-05850/)|1|I-05850、何故か大量に持ってた| |[AD8506](https://akizukidenshi.com/catalog/g/gI-04568/)|1|I-04568、面実装オペアンプ、変換基板に載ってるやつもある| |[HT7733A](https://akizukidenshi.com/catalog/g/gI-02799/)|1|I-02799、昇圧DCDC制御IC| |[TL431](https://akizukidenshi.com/catalog/g/gI-12018/)|1|I-12018、シャントレギュレータ| |[I2C接続小型LCDモジュール変換キット](https://akizukidenshi.com/catalog/g/gK-06795/)|1|K-06795、8x2のやつ| |[プラケース SK-5](https://akizukidenshi.com/catalog/g/gP-00076/)|1|P-00076、単3が横に入るもののうち最小(多分)| その他に基板、電池ボックス、コネクタ類、抵抗、コンデンサ、マイクロインダクタ、ショットキーバリアダイオードなどを使用。 # 回路図  典型的な非反転とボルテージフォロアなので特に難しくはない。C3の10uはどうしても50Hzのノイズが乗るのでつけた。バッテリー駆動なので出所がわからない。 PICと液晶周りの回路は割愛させて頂いた。あとに載せるピンアサイン画像を見てもらえればだいたい分かると思う。それにどうせみんなArduinoにつなげちゃうんでしょ。AD変換の正の基準電圧(Vref+)には2.495Vがつながっていることに注意。 # プログラム MPLAB X + XC32 + Microchip Harmony3で開発した。Microchip Harmony3は起動するのに何故かクッッッッッソ時間がかかるので困る(誰か解決策教えて下さい)。Microchip Harmonyでは以下のように設定した。      UART2を使うと、書き込み用に出した端子をそのままシリアル通信に使える(小技)。   プログラムは基本的にMicrochip Harmony3の自動生成コードから書き起こしている。 変更部分のみ掲載。 ```c:main.c #include <stddef.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include "definitions.h" volatile bool t1_int = false; double ADC2ThermistorTemp(int value) { const double a = -0.08758141505; const double b = 69.96186904; return a * (double) value + b; } double ADC2ThermopileTemp(int value) { const double a = 0.4987508246; const double b = -98.0; return a * (double) value + b; } void delay(int delay_time) { for (int i = 0; i < delay_time; i++) { while (!t1_int); t1_int = false; } } const uint16_t LCDaddr = 0x3e; //0x7c const uint8_t initCommands[] = {0x38, 0x39, 0x14, 0x70, 0x56, 0x6C, 0x38, 0x0C, 0x01}; void LCDSendData(bool isInst, uint8_t data) { uint8_t d[2] = {isInst ? 0x00 : 0x40, data}; I2C1_Write(LCDaddr, d, 2); while (I2C1_IsBusy()); delay(2); } void LCDSendData2(bool isInst, const uint8_t *data, int size) { for (int i = 0; i < size; i++)LCDSendData(isInst, data[i]); } void LCDSendMsg(const char *data, int size) { uint8_t msg[40] = {0x80, 0x80}; int msg_size = 2; for (int i = 0; (i < size) && (i < 16); i++) { if (i == 8) { msg[msg_size] = 0x80; msg[msg_size + 1] = 0xC0; msg_size += 2; } msg[msg_size] = 0xC0; msg[msg_size + 1] = data[i]; msg_size += 2; } I2C1_Write(LCDaddr, msg, msg_size); while (I2C1_IsBusy()); delay(2); } void LCDInit(void) { delay(40); LCDSendData2(true, initCommands, sizeof (initCommands)); } int main(void) { /* Initialize all modules */ SYS_Initialize(NULL); puts("start\n"); TMR1_Start(); TMR3_Start(); LCDInit(); while (true) { delay(100); char m[17]; double A1 = ADC2ThermopileTemp(ADC1BUF0); double A2 = ADC2ThermistorTemp(ADC1BUF1); snprintf(m, sizeof (m), "P:%4.1f%cCT:%4.1f%cC", A1 + A2, 0xdf, A2, 0xdf); LCDSendMsg(m, strlen(m)); //printf("%d,%d\n", ADC1BUF0, ADC1BUF1); } /* Execution should not come here during normal operation */ return (EXIT_FAILURE); } ``` ```c:interrupt.c #include "definitions.h" #include "test.h" //<-追加 void TIMER_1_InterruptHandler( void ); void I2C_1_InterruptHandler( void ); void __ISR(_TIMER_1_VECTOR, ipl1AUTO) TIMER_1_Handler (void) { TIMER_1_InterruptHandler(); t1_int = true; //<-追加 } void __ISR(_I2C_1_VECTOR, ipl1AUTO) I2C_1_Handler (void) { I2C_1_InterruptHandler(); } ``` ```c:test.h #pragma once extern volatile bool t1_int; ``` ビルドするときは`-std=c99`オプションをお忘れなく。 温度算出は`ADC2ThermistorTemp()`及び`ADC2ThermopileTemp()`の実装を見てもらえればわかるが、1次近似である。 データシートから計算した値をもとに、サーミスターは0℃から40℃、サーモパイルは温度**差**0℃から+20℃まででそれぞれ1次近似して、それから実機で校正した。 XC32はC\++も使えるが、リンクされるライブラリの最適化に問題があるらしく基本使えないと思っていい。 これは全く余談だがC\++とか最早いいからRustとか使わせてほしい、Microchipさんどうでしょう。明らかに組み込み系に必要なんですが。 # 完成品     # デモ 左がお湯入り、右が氷水入りの紙コップです。 @[youtube](https://www.youtube.com/watch?v=UUBlSbXCCRE) # 市販のサーモパイル式非接触体温計は? 最近額に向けてピピッとやるタイプの非接触温度計が流行っているが、今回のように素直な実装では明らかに体温は測れないのでどうしているのか気になって調べてみたところ、[タニタのページ](https://www.tanita.co.jp/page/noncontact_thermometer/)では > 本器は、人の額の表面から放射される赤外線量を測定し、舌下温度に換算してデジタル表示します(体温測定モード)。 > また、物体の表面から放射される赤外線量を測定し、温度に換算してデジタル表示します(温度測定モード)。 とあった。ナルホドナー。換算がうまく機能するために「使用上の注意」にあるように制約が多くなってしまうのは頷ける。でも消費者がこれすべて守れるのかどうか……? # 言い訳など * オペアンプ内蔵のPICでやればスマートにできたかもしれないけどPIC32とオペアンプの在庫があったから仕方がない * 今回使ったサーモパイルのメーカーのページには後継品?のISB-TS45Hしか掲載されていない。こちらの方が起電力も大きいしデータシートも見やすいのだが・・・。 * フルネルレンズなどは試していない。やったらどうなるかは気になるが、検知角度が狭くなるならともかく広くなっても仕方がない気もする。 * 校正、実はうまくやれてない。1度単位で変えれる熱源ください。恒温槽も。 * 逆に、同じ温度のものを図ったときの再現性はとても良いので、校正がうまくやれればだいぶ精度良く計れそうである。 # おわりに アナログ回路は難しいすね。 # 参考 * [浜松ホトニクス 熱型検出素子](https://www.hamamatsu.com/resources/pdf/ssd/07_handbook.pdf) * [サーモパイルの応用](http://www.ssc-inc.jp/products/images/ST-OUYOU.pdf) # 付録 https://gist.github.com/asi-msk/9b022297248a49684a1c8892089d7bad データシートから起電力引っ張ってくるのはめんどくさかろう?