PT100の抵抗値から温度への変換は一般的に浮動小数点と平方根が使われているようだ。非力なMPUでは約1ms程度の計算時間がかかるらしいので、より高速な変換テーブル方式のライブラリを考えてみた。
まず、事前にPC上で公式演算を実行した結果を元に抵抗値から温度へ変換するテーブルを作成する。変換テーブルは4Ω毎(温度は約10℃単位)に作成し、抵抗の中間値は前後の温度の増分から比率計算して求める。
16ビット整数演算のみとし、かつ、精度を確保するため抵抗値(入力値)と温度(戻り値)はそれぞれ16倍した値とする仕様としたが、公式演算との比較では0.07℃以内の誤差に収めることができた。まぁ、必要十分すぎる精度だろう...
【概要】
| 1 | static int16_t temperature(uint16_t r) | 
対応する温度範囲は約-30℃~300℃。rはRTDの抵抗値(小数部含む)を16倍した値を指定する。
戻り値は16倍された摂氏温度(小数部含む)を返す。整数部だけなら4ビット右シフトすれば良いし、小数部も必要なら16で割る浮動小数点演算を行えば良い。
| 1 | static uint16_t resistor(int16_t c) | 
cは16倍された温度(小数部含む)を指定する。戻り値は16倍された抵抗値(小数部含む)を返す。
【サンプル・スケッチ】
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include "pt100.h" void setup() { } void loop() {   uint16_t rtd = ...                 // RTDの抵抗値(小数部含む)を16倍した値   uint16_t temp = PT100::temperature(rtd);   Serial.println(temp >> 4);         // 整数部のみ表示   Serial.println((double)temp / 16); // 整数部と小数部を表示   delay(1000); } | 
【ライブラリ】
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | /*   pt100.h - RTD Temperature Conversion Library for PT100   Copyright (c) 2020 Sasapea's Lab. All right reserved.   This library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   version 2.1 of the License, or (at your option) any later version.   This library is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Lesser General Public License for more details.   You should have received a copy of the GNU Lesser General   Public License along with this library; if not, write to the   Free Software Foundation, Inc., 59 Temple Place, Suite 330,   Boston, MA  02111-1307  USA */ #ifndef __PT100_H #define __PT100_H #include <stdint.h> #ifdef __AVR__ #include <avr/pgmspace.h> #else #define PROGMEM #define pgm_read_word(p) *(p) #endif #define PT100_DATA_SHIFT   4 #define PT100_RRTD_SHIFT   (2 + PT100_DATA_SHIFT) #define PT100_RRTD_MASK    ((1 << PT100_RRTD_SHIFT) - 1) #define PT100_RRTD_BASE    (88 << PT100_DATA_SHIFT) #define PT100_TEMP_DATA(c) (int16_t)((c) * (1 << PT100_DATA_SHIFT)) class PT100 {   private:       static const PROGMEM int16_t TEMP[32];   public:     static int16_t temperature(uint16_t r)     {       if (r <= PT100_RRTD_BASE)         return TEMP[0];       if (r >= PT100_RRTD_BASE + ((sizeof(TEMP) / sizeof(TEMP[0]) - 1) << PT100_RRTD_SHIFT))         return TEMP[sizeof(TEMP) / sizeof(TEMP[0]) - 1];       uint8_t i = (r - PT100_RRTD_BASE) >> PT100_RRTD_SHIFT;       int16_t t = pgm_read_word(TEMP + i);       int16_t n = pgm_read_word(TEMP + i + 1);       return t + (((n - t) * (r & PT100_RRTD_MASK) + ((1 << PT100_RRTD_SHIFT) >> 1)) >> PT100_RRTD_SHIFT);     }     static uint16_t resistor(int16_t c)     {       if (c < TEMP[0])         return PT100_RRTD_BASE;       if (c >= TEMP[sizeof(TEMP) / sizeof(TEMP[0]) - 1])         return PT100_RRTD_BASE + ((sizeof(TEMP) / sizeof(TEMP[0]) - 1) << PT100_RRTD_SHIFT);       uint8_t i;       for (i = 0; (i < sizeof(TEMP) / sizeof(TEMP[0]) - 1) && (c >= TEMP[i + 1]); ++i)         continue;       int16_t t = pgm_read_word(TEMP + i);       int16_t n = pgm_read_word(TEMP + i + 1);       return PT100_RRTD_BASE + ((uint16_t)i << PT100_RRTD_SHIFT) + ((c - t) << PT100_RRTD_SHIFT) / (n - t);     } }; #define PT100_TEMP_LOW  PT100_TEMP_DATA(-30.563) #define PT100_TEMP_HIGH PT100_TEMP_DATA(299.855) const PROGMEM int16_t PT100::TEMP[] = {   PT100_TEMP_DATA(-30.563), //  88 ohm   PT100_TEMP_DATA(-20.408), //  92   PT100_TEMP_DATA(-10.220), //  96   PT100_TEMP_DATA(  0.000), // 100   PT100_TEMP_DATA( 10.250), // 104   PT100_TEMP_DATA( 20.532), // 108   PT100_TEMP_DATA( 30.844), // 112   PT100_TEMP_DATA( 41.189), // 116   PT100_TEMP_DATA( 51.566), // 120   PT100_TEMP_DATA( 61.975), // 124   PT100_TEMP_DATA( 72.417), // 128   PT100_TEMP_DATA( 82.892), // 132   PT100_TEMP_DATA( 93.401), // 136   PT100_TEMP_DATA(103.943), // 140   PT100_TEMP_DATA(114.519), // 144   PT100_TEMP_DATA(125.129), // 148   PT100_TEMP_DATA(135.774), // 152   PT100_TEMP_DATA(146.454), // 156   PT100_TEMP_DATA(157.169), // 160   PT100_TEMP_DATA(167.921), // 164   PT100_TEMP_DATA(178.708), // 168   PT100_TEMP_DATA(189.531), // 172   PT100_TEMP_DATA(200.392), // 176   PT100_TEMP_DATA(211.289), // 180   PT100_TEMP_DATA(222.224), // 184   PT100_TEMP_DATA(233.197), // 188   PT100_TEMP_DATA(244.209), // 192   PT100_TEMP_DATA(255.259), // 196   PT100_TEMP_DATA(266.348), // 200   PT100_TEMP_DATA(277.477), // 204   PT100_TEMP_DATA(288.646), // 208   PT100_TEMP_DATA(299.855), // 212 }; #endif | 
