Embedded HandbookПриложения
Все разделы › XXI. Аналоговые узлы
STM32G474, STM32F103 · уровень средний · 20 мин чтения
Открыть в интерактивном справочнике

176б. Термометр сопротивления PT100/PT1000: ратиометрия и 2-, 3-, 4-проводное подключение

В 96 температуру мерил NTC-термистор, в 104 — термопара. Для точного измерения от −50 до +200 °C в промышленности берут платиновый термометр сопротивления: PT100 или PT1000, 100 или 1000 Ом при 0 °C. Его кривая известна заранее, датчики взаимозаменяемы, но полезный сигнал мал: десятые доли ома на градус у PT100. Здесь — как перевести сопротивление в градусы, как мерить его встроенным АЦП так, чтобы опора не входила в результат, что делают провода длиной 10 м и сколько градусов на код остаётся у F103 и G474.

Опоры: коэффициенты уравнения — стандарт IEC 60751 (общеизвестные константы; текст стандарта с разделом не сверялся). Другие наборы коэффициентов и регистры MAX31865 — из дерева Zephyr v4.4.2 (раздел 34а): драйвер drivers/sensor/maxim/max31865 и пример samples/shields/lmp90100_evb/rtd. Даташиты F103 (DocID13587) и G474 (DS12288) — из паков Keil. Все расчёты — модель на ПК _verify/rtd176c; код пересчёта собран armclang для обоих камней и прогнан на ПК по всему диапазону против модели. Коэффициент самонагрева 0,5 °C/мВт, кабель 10 м и разброс жил 5 % — примеры.

Как это называется в документации

Оригинал Перевод
resistance temperature detector (RTD) термометр сопротивления
Callendar–Van Dusen equation уравнение Каллендара — Ван Дюзена
ratiometric measurement ратиометрическое (логометрическое) измерение
reference resistor (RREF) опорный резистор
excitation current ток возбуждения, ток через датчик
2-, 3-, 4-wire connection двух-, трёх-, четырёхпроводное подключение
lead (wire) resistance сопротивление проводов
force / sense leads токовые и измерительные провода
self-heating самонагрев
RTD-to-digital converter преобразователь «термометр сопротивления — код»
fault detection обнаружение неисправности

176б.1 Платина и уравнение Каллендара — Ван Дюзена

Сопротивление платины растёт с температурой почти линейно. Точнее — по уравнению Каллендара — Ван Дюзена:

R(T) = R0 · (1 + A·T + B·T² + C·(T − 100)·T³),

где R0 — сопротивление при 0 °C, A = 3,9083·10⁻³, B = −5,775·10⁻⁷, а C = −4,183·10⁻¹² только ниже нуля; выше нуля C = 0. Одни и те же коэффициенты годятся и для PT100, и для PT1000: меняется только R0.

Температура PT100, Ом PT1000, Ом Крутизна PT100, Ом/°C
−50 °C 80,306 803,06 0,3971
0 °C 100,000 1000,00 0,3908
+100 °C 138,505 1385,05 —
+200 °C 175,856 1758,56 0,3677

Средний коэффициент между 0 и 100 °C — 0,003851 на градус (3850,5 ppm/°C); по нему датчики и различают. Но прямая через 0 и 100 °C — не кривая: при +200 °C она занижает на 3,00 °C, при −50 °C — на 1,15 °C, при +50 °C завышает на 0,37 °C. Крутизна падает с температурой: у PT1000 3,971 Ом/°C при −50 °C и 3,677 Ом/°C при +200 °C.

Наборов коэффициентов в ходу три, и они не совпадают:

Где A B Ошибка против IEC 60751
IEC 60751 3,9083·10⁻³ −5,775·10⁻⁷ —
Zephyr, драйвер max31865 («ITS-90») 3,9080·10⁻³ −5,870·10⁻⁷ +0,033 °C при 100 °C, +0,120 °C при 200 °C
Zephyr, пример lmp90100_evb/rtd 3,90802·10⁻³ −0,58020·10⁻⁶ +0,015 °C при 100 °C, +0,045 °C при 200 °C, −0,022 °C при −50 °C

Десятая доля градуса на 200 °C — мелочь для бытового термометра и заметная величина для поверки. Коэффициенты берут из паспорта своего датчика, а не из первого попавшегося драйвера.


176б.2 Из сопротивления в градусы

Выше нуля уравнение квадратное, и решается формулой:

T = (−A + √(A² − 4B·(1 − R/R0))) / (2B).

Модель на ПК сверила её с прямой кривой: расхождение 7,7·10⁻¹³ °C — точное решение. Ниже нуля член с C делает уравнение четвёртой степени. Варианты:

Без плавающей точки проще таблица и прямая между точками, как у NTC в 96.3. Таблицу хранят в долях R/R0 — тогда она общая для PT100 и PT1000:

Шаг таблицы Точек на −60…+210 °C Наибольшая ошибка интерполяции
5 °C 55 0,0011 °C
10 °C 28 0,0043 °C
30 °C 10 0,0389 °C

Шаг 10 °C: 28 чисел по 4 байта и ошибка в тысячные доли градуса — меньше шага любого АЦП ниже. Запас −60 и +210 °C за краями рабочего диапазона нужен, чтобы шум у края не выбрасывал показание из таблицы.

А вот линейную формулу T = (R − R0) / (R0·A), которую драйвер max31865 использует, если собран без newlib, брать нельзя: −1,47 °C при 100 °C и −5,90 °C при 200 °C.


176б.3 Ратиометрия: опора сокращается

Прямой путь — источник тока 1 мА и АЦП, который меряет напряжение на датчике относительно своей опоры. Тогда ошибка опоры и ошибка тока входят в результат один к одному: опора на 1 % ниже номинала — это +2,59 °C при 0 °C и +4,83 °C при 200 °C.

Ратиометрическая схема убирает и то и другое. Датчик стоит в делителе с опорным резистором Rref, делитель питается от того же напряжения, что служит опорой АЦП. Код в точке A — отношение напряжений:

a = FS · (R + Rпров) / (Rref + R + Rпров),

и напряжение питания из него ушло. Отсюда R = Rref · a / (FS − a): код на Rref показывает ток, код на датчике — напряжение, их отношение — сопротивление. Модель перебрала 2501 температуру от −50 до +200 °C через 0,1 °C при VDDA 3,0, 3,3 и 3,6 В: коды совпали во всех 2501 случаях (при 0 °C — 5958 из 65536). Тот же приём у NTC назван логометрическим измерением (96.2).

PT1000 на встроенном АЦП STM32: VDDA через опорный резистор 10 кОм питает датчик по токовым жилам L1 и L2 десятиметрового кабеля 0,5 мм², точка A над токовой жилой и два измерительных провода C и D от выводов датчика идут на три несимметричных входа АЦП с опорой VDDA; внизу формулы сопротивления для двух, трёх и четырёх проводов

Теперь эталон — сам Rref, и его ошибка переходит в R один к одному:

Ошибка Rref При 0 °C При 200 °C
допуск 0,1 % 0,256 °C 0,478 °C
ТКС 25 ppm/K при нагреве платы на 60 K — 0,15 % 0,384 °C 0,717 °C

Допуск снимает калибровка (202.3): в прошивку пишут измеренное значение Rref, а не номинал (202.5). Дрейф остаётся — резистор с малым ТКС дешевле, чем источник опоры того же класса (177).

Условие ратиометрии — делитель питается от опоры АЦП. У F103 в корпусах LQFP48 (BluePill) и LQFP64 вход VREF+ соединён с VDDA внутри, в LQFP100 он выведен отдельно (вывод 21) и его подключают к VDDA на плате. У G474 вывод VREF+ в части корпусов сдвоен с VDDA, и тогда VREFBUF недоступен (DS12288); в остальных VREF+ соединяют с VDDA и VREFBUF не включают. Опора АЦП 2,5 В от VREFBUF при делителе от 3,3 В — это снова абсолютное измерение с ошибкой питания в результате.


176б.4 Два, три, четыре провода

Жила 0,5 мм² длиной 10 м — 0,35 Ом. При двух проводах датчик меряется вместе с обеими жилами, 0,70 Ом:

Датчик Ошибка при 0 °C При 200 °C Кабель 0,5 мм² на 0,1 °C
PT100 +1,792 °C +1,904 °C 0,56 м
PT1000 +0,179 °C +0,190 °C 5,6 м

У PT100 два провода годятся только на плате; у PT1000 ошибка в десять раз меньше при том же кабеле — это одна из причин выбрать PT1000.

Три провода. Третья жила идёт от верхнего вывода датчика, и ток по ней не течёт: АЦП видит в точке B напряжение самого вывода. Разность a − b — падение на верхней токовой жиле L1, и если нижняя L2 такая же, её падение равно ему. Отсюда числитель 2b − a: из напряжения на датчике с нижней жилой вычтено падение одной жилы. Компенсация точна, пока жилы равны; если одна на 5 % больше другой, остаётся 0,0448 °C у PT100 и 0,0045 °C у PT1000.

Четыре провода. Две жилы несут ток, две другие — C и D — только снимают напряжение прямо с выводов датчика. Числитель c − d — напряжение на самом датчике, знаменатель FS − a — ток через Rref. Провода в формулу не входят вообще: сопротивление жил и их разброс — ноль.

Схема Числитель Каналов АЦП
2 провода a 1
3 провода 2b − a 2
4 провода c − d 3

У G474 разность c − d можно снять одним дифференциальным каналом (15а.4). Но это не выигрыш: единица кода вдвое крупнее, а синфазное напряжение по DS12288 должно лежать в пределах VREF+/2 ± 0,18 В — 1,47…1,83 В при 3,3 В. В нашем делителе датчик сидит у земли, синфазное — 0,15 В; пришлось бы поднимать датчик резистором снизу. Три несимметричных канала проще.


176б.5 Шаг в градусах, самонагрев и когда нужен внешний АЦП

Сигнал датчика — ток на крутизну. Больше ток — крупнее сигнал, но датчик греется своей мощностью I²·R, и показывает температуру выше среды. Ниже — идеальный источник тока, 0 °C, опора 3,3 В; единица кода несимметричного входа — 0,806 мВ при 12 битах и 0,0504 мВ при 16 битах (передискретизация 256 со сдвигом 4, 15а.5), дифференциального — 1,611 и 0,1007 мВ. Самонагрев — при 0,5 °C/мВт (пример: настоящее число в паспорте датчика, оно зависит от корпуса и среды).

Датчик и ток Сигнал, мВ/°C Мощность Самонагрев 12 бит 16 бит Дифф. 12 бит Дифф. 16 бит
PT100, 1 мА 0,391 0,100 мВт 0,0500 °C 2,061 °C 0,1288 °C 4,123 °C 0,2577 °C
PT100, 0,1 мА 0,039 0,001 мВт 0,0005 °C 20,614 °C 1,2884 °C 41,228 °C 2,5768 °C
PT1000, 1 мА 3,908 1,000 мВт 0,5000 °C 0,206 °C 0,0129 °C 0,412 °C 0,0258 °C
PT1000, 0,1 мА 0,391 0,010 мВт 0,0050 °C 2,061 °C 0,1288 °C 4,123 °C 0,2577 °C
PT100, 1 мА, усилитель ×10 3,908 0,100 мВт 0,0500 °C 0,206 °C 0,0129 °C 0,412 °C 0,0258 °C

Вывод простой. PT100 прямо на 12-битный АЦП — два градуса на код; ему нужен усилитель (инструментальный, раздел 176) или внешний АЦП. PT1000 при 0,1 мА даёт тот же сигнал, что PT100 при 1 мА, а греется вдесятеро меньше. При 1 мА PT1000 даёт крупный сигнал, но полградуса самонагрева. Ошибка усиления, если стоит усилитель, входит в R один к одному, как допуск Rref.

В делителе от VDDA ток задаёт Rref. Для PT1000 при 3,3 В и 0 °C:

Rref Ток Мощность Самонагрев F103, 12 бит G474, 16 бит
2,2 кОм 1,031 мА 1,063 мВт 0,532 °C 0,29 °C 0,018 °C
4,7 кОм 0,579 мА 0,335 мВт 0,168 °C 0,43 °C 0,027 °C
10 кОм 0,300 мА 0,090 мВт 0,045 °C 0,76 °C 0,047 °C
33 кОм 0,097 мА 0,009 мВт 0,005 °C 2,19 °C 0,137 °C
PT100 и 3,3 кОм 0,971 мА 0,094 мВт 0,047 °C 2,19 °C 0,137 °C

Rref 10 кОм уравнивает самонагрев и шаг G474 — около 0,05 °C каждый; его и берёт код ниже. Шестнадцать бит — не точность: лишние четыре бита настоящие, только если шум АЦП их раскачивает (15а.5, раздел 165), а ошибки нелинейности и смещения АЦП никуда не деваются (202).

Специальная микросхема. Когда нужны сотые доли, ставят преобразователь для термометров сопротивления. MAX31865 из дерева Zephyr: код сопротивления — 15 бит в регистрах 0x01–0x02, младший бит D0 — флаг неисправности; R = код / 32768 · Rref. Привязка Zephyr советует Rref 400 Ом для PT100 и 4000 Ом для PT1000 (со ссылкой на даташит): шаг 0,01221 и 0,1221 Ом, в обоих случаях 0,0312 °C при 0 °C. Регистр настройки 0x00: бит 7 включает смещение датчика (VBIAS), бит 6 — непрерывное преобразование, бит 5 — одиночное, бит 4 — трёхпроводную схему, биты 3:2 — цикл поиска неисправности, бит 1 сбрасывает её флаги, бит 0 выбирает фильтр 50 Гц вместо 60 Гц. Регистр 0x07 — причина неисправности, 0x03–0x06 — пороги; при записи к адресу добавляют 0x80. Драйвер после включения смещения ждёт 66 мс до чтения. Формула драйвера R = код / 32768 · Rref — та же ратиометрия: код — доля от Rref.


176б.6 Код: из кодов АЦП в сотые доли градуса

Переносимая часть rtd.c не трогает регистров: на вход — 16-битные коды точек A, B, C, D, на выход — температура в сотых долях градуса и состояние. 16 бит на G474 даёт сама передискретизация (15а.5), на F103 — сумма 16 измерений в программе (усреднение — 165.8). Параметры:

#define RTD_R0_OHM      1000u       /* PT1000: 1000 Ом при 0 °C */
#define RTD_RREF_MOHM   10000000u   /* опорный резистор 10 кОм, в миллиомах: сюда — измеренное значение */
#define RTD_FS          65536       /* полная шкала: код, соответствующий напряжению опоры */
#define RTD_VDDA_MV     3600u       /* худшее питание делителя — только для проверки тока */
#define RTD_I_MAX_UA    500u        /* больше — самонагрев: 0,5 мА через PT1000 — 0,25 мВт */
#define RTD_DEN_MIN     4096        /* на Rref меньше 1/16 опоры — ток не течёт */
#define RTD_W_SHORT     700000      /* R/R0 ниже 0,70 (около −76 °C) — замыкание */
#define RTD_W_OPEN      2000000     /* R/R0 выше 2,00 (около +266 °C) — обрыв */
#define RTD_W_LEAD      10000       /* провода: не больше 1 % R0 (10 Ом у PT1000) */
/* числитель отношения R/Rref для трёх схем; знаменатель — всегда RTD_FS - a */
#define RTD_NUM_2W(a)        (a)                        /* датчик + оба провода */
#define RTD_NUM_3W(a, b)     (2 * (b) - (a))            /* b — верх датчика по третьему проводу */
#define RTD_NUM_4W(c, d)     ((c) - (d))                /* c, d — измерительные провода */

Проверки на этапе сборки:

_Static_assert((uint64_t)RTD_VDDA_MV * 1000000u / (RTD_RREF_MOHM + RTD_R0_OHM * 1000u) <= RTD_I_MAX_UA,
               "ток через датчик больше RTD_I_MAX_UA: самонагрев");
_Static_assert((uint64_t)RTD_FS * RTD_RREF_MOHM / (RTD_RREF_MOHM + RTD_R0_OHM * (RTD_W_OPEN / 1000u)) > RTD_DEN_MIN,
               "на пороге обрыва ток должен ещё отличаться от нуля");
_Static_assert(RTD_W_SHORT < 763278 && RTD_W_OPEN > 1795275, "пороги аварии - за краями таблицы");

Первая считает ток при худшем питании 3,6 В: 327,3 мкА (при 3,3 В — 300,0 мкА, 0,090 мВт). Ошибись в Rref на порядок — 1 кОм вместо 10 — и сборка остановится с сообщением про самонагрев. Вторая: даже на пороге обрыва на Rref остаётся 54613 единиц кода — больше порога 4096.

Сопротивление — отношением в 64-битных целых, температура — по таблице R/R0 через 10 °C:

/* R/R0 = (Rref / R0) * num / den, в миллионных, с округлением к ближайшему */
int32_t rtd_w_ppm(int32_t num, int32_t den)
{
    int64_t n = (int64_t)num * RTD_RREF_MOHM * 1000;
    int64_t d = (int64_t)den * RTD_R0_OHM;
    n += (n >= 0 ? d : -d) / 2;
    return (int32_t)(n / d);
}

/* R/R0 -> сотые доли градуса: таблица через 10 °C и прямая между точками */
rtd_status_t rtd_temp(int32_t w, int32_t *t_centi)
{
    if (w < rtd_tab[0] || w > rtd_tab[RTD_N - 1])
        return RTD_RANGE;
    unsigned i = 0;
    while (i < RTD_N - 2 && w >= rtd_tab[i + 1])
        i++;
    int32_t span = rtd_tab[i + 1] - rtd_tab[i];
    *t_centi = (RTD_T0 + RTD_STEP * (int32_t)i) * 100 + (RTD_STEP * 100 * (w - rtd_tab[i]) + span / 2) / span;
    return RTD_OK;
}

Диагностика идёт до пересчёта, и порядок проверок важен:

rtd_status_t rtd_read(int32_t a, int32_t num, int32_t *t_centi)
{
    int32_t den = RTD_FS - a;                   /* напряжение на Rref — это ток */
    if (den < RTD_DEN_MIN)
        return RTD_OPEN;                        /* тока нет: оборван токовый провод или датчик */
    int32_t w2 = rtd_w_ppm(a, den);             /* датчик вместе с проводами */
    int32_t w = rtd_w_ppm(num, den);
    if (w2 < RTD_W_SHORT)
        return RTD_SHORT;
    if (w2 - w > RTD_W_LEAD || w - w2 > RTD_W_LEAD)
        return RTD_SENSE;                       /* провода «стали» больше 1 % R0: висит измерительный провод */
    if (w > RTD_W_OPEN)
        return RTD_OPEN;
    return rtd_temp(w, t_centi);
}

Сначала ток. При обрыве токовой жилы в четырёхпроводной схеме ток пропадает, c и d равны, числитель — ноль, и без этой проверки обрыв прочитался бы как замыкание. Потом двухпроводная оценка w2 — датчик вместе с жилами: если и она ниже 0,70 R0 (около −75,8 °C), замкнут сам датчик или кабель. Потом сравнение двух оценок: их разность — это сопротивление жил, и больше 10 Ом у PT1000 оно не бывает. Оборванная измерительная жила оставляет вход АЦП висеть, и разность выходит за предел. Выше 2,00 R0 (+266,3 °C) — обрыв или датчик вне рабочей области.

Прогон на ПК (rtd_host.c + тот же rtd.c, gcc):


176б.7 Грабли

Коэффициенты «как в драйвере». Драйвер max31865 в Zephyr берёт A = 3,9080·10⁻³ и B = −5,870·10⁻⁷ — на 200 °C это +0,120 °C против IEC 60751. Без newlib он вовсе считает прямую: −5,90 °C при 200 °C.

PT100 на двух проводах. Десять метров жилы 0,5 мм² — +1,79 °C. PT1000 на тех же проводах ошибётся на 0,18 °C; дальше — три или четыре провода.

Трёхпроводная схема с разными жилами. Компенсация держится на равенстве L1 и L2. Клемма с плохим контактом или жилы разного сечения — и разность идёт прямо в результат.

Опора АЦП не та, что питает делитель. VREFBUF 2,5 В при делителе от VDDA 3,3 В — ратиометрии нет, 1 % питания — 2,59 °C при 0 °C.

Ток «для крупного сигнала». PT1000 с Rref 2,2 кОм греется на 0,532 °C (при 0,5 °C/мВт) — в 30 раз больше шага G474 с тем же Rref (0,018 °C). _Static_assert на ток ловит ошибку номинала при сборке.

Обрыв похож на замыкание. В четырёхпроводной схеме без тока c = d, числитель ноль. Проверяй ток (знаменатель) раньше сопротивления.

Висящий измерительный провод. Оборванная жила C или D оставляет вход АЦП без привязки, и он может показать правдоподобное число. Ловит это сравнение с двухпроводной оценкой: провода не могут «весить» 10 Ом.

Шестнадцать бит без шума. Сумма одинаковых кодов не добавляет разрядов: F103 без шума остаётся с шагом 0,76 °C.

Дифференциальный канал у земли. Синфазное 0,15 В против нужных 1,47…1,83 В — канал G474 работает вне условий даташита.


176б.8 Итоги


Полные исходники

rtd.h — настройки делителя и интерфейс пересчёта.

/* 176б: термометр сопротивления PT1000 — коды АЦП в сотые доли градуса, в целых числах.
 * Делитель VDDA -> Rref -> точка A -> провод -> датчик -> провод -> земля; опора АЦП — тот же VDDA.
 * Коды — 16 бит: G474 с передискретизацией 256 и сдвигом 4 или сумма 16 измерений F103. */
#ifndef RTD_H
#define RTD_H

#include <stdint.h>

#define RTD_R0_OHM      1000u       /* PT1000: 1000 Ом при 0 °C */
#define RTD_RREF_MOHM   10000000u   /* опорный резистор 10 кОм, в миллиомах: сюда — измеренное значение */
#define RTD_FS          65536       /* полная шкала: код, соответствующий напряжению опоры */
#define RTD_VDDA_MV     3600u       /* худшее питание делителя — только для проверки тока */
#define RTD_I_MAX_UA    500u        /* больше — самонагрев: 0,5 мА через PT1000 — 0,25 мВт */
#define RTD_DEN_MIN     4096        /* на Rref меньше 1/16 опоры — ток не течёт */
#define RTD_W_SHORT     700000      /* R/R0 ниже 0,70 (около −76 °C) — замыкание */
#define RTD_W_OPEN      2000000     /* R/R0 выше 2,00 (около +266 °C) — обрыв */
#define RTD_W_LEAD      10000       /* провода: не больше 1 % R0 (10 Ом у PT1000) */
#define RTD_T0          (-60)       /* таблица: от −60 °C — запас за −50 */
#define RTD_STEP        10          /* через 10 °C */
#define RTD_N           28          /* до +210 °C — запас за +200 */

/* числитель отношения R/Rref для трёх схем; знаменатель — всегда RTD_FS - a */
#define RTD_NUM_2W(a)        (a)                        /* датчик + оба провода */
#define RTD_NUM_3W(a, b)     (2 * (b) - (a))            /* b — верх датчика по третьему проводу */
#define RTD_NUM_4W(c, d)     ((c) - (d))                /* c, d — измерительные провода */

typedef enum { RTD_OK, RTD_OPEN, RTD_SHORT, RTD_SENSE, RTD_RANGE } rtd_status_t;

int32_t rtd_w_ppm(int32_t num, int32_t den);
rtd_status_t rtd_temp(int32_t w, int32_t *t_centi);
rtd_status_t rtd_read(int32_t a, int32_t num, int32_t *t_centi);

#endif

rtd.c — пересчёт кодов АЦП в сотые доли градуса и диагностика, без плавающей точки.

/* 176б: пересчёт кодов АЦП в температуру PT100/PT1000 и диагностика. Без плавающей точки, без регистров. */
#include "rtd.h"

_Static_assert((uint64_t)RTD_VDDA_MV * 1000000u / (RTD_RREF_MOHM + RTD_R0_OHM * 1000u) <= RTD_I_MAX_UA,
               "ток через датчик больше RTD_I_MAX_UA: самонагрев");
_Static_assert((uint64_t)RTD_FS * RTD_RREF_MOHM / (RTD_RREF_MOHM + RTD_R0_OHM * (RTD_W_OPEN / 1000u)) > RTD_DEN_MIN,
               "на пороге обрыва ток должен ещё отличаться от нуля");
_Static_assert(RTD_W_SHORT < 763278 && RTD_W_OPEN > 1795275, "пороги аварии - за краями таблицы");

/* R/R0 в миллионных долях: W(T) по IEC 60751, A = 3,9083e-3, B = -5,775e-7, C = -4,183e-12 */
static const int32_t rtd_tab[RTD_N] = {
     763278,  803063,  842707,  882217,  921599,  960859, 1000000, 1039025, 1077935, 1116729,
    1155408, 1193971, 1232419, 1270751, 1308968, 1347069, 1385055, 1422925, 1460680, 1498319,
    1535843, 1573251, 1610544, 1647721, 1684783, 1721729, 1758560, 1795275,
};
_Static_assert(sizeof rtd_tab / sizeof rtd_tab[0] == RTD_N, "таблица: -60...+210 °C через 10 °C");

/* R/R0 = (Rref / R0) * num / den, в миллионных, с округлением к ближайшему */
int32_t rtd_w_ppm(int32_t num, int32_t den)
{
    int64_t n = (int64_t)num * RTD_RREF_MOHM * 1000;
    int64_t d = (int64_t)den * RTD_R0_OHM;
    n += (n >= 0 ? d : -d) / 2;
    return (int32_t)(n / d);
}

/* R/R0 -> сотые доли градуса: таблица через 10 °C и прямая между точками */
rtd_status_t rtd_temp(int32_t w, int32_t *t_centi)
{
    if (w < rtd_tab[0] || w > rtd_tab[RTD_N - 1])
        return RTD_RANGE;
    unsigned i = 0;
    while (i < RTD_N - 2 && w >= rtd_tab[i + 1])
        i++;
    int32_t span = rtd_tab[i + 1] - rtd_tab[i];
    *t_centi = (RTD_T0 + RTD_STEP * (int32_t)i) * 100 + (RTD_STEP * 100 * (w - rtd_tab[i]) + span / 2) / span;
    return RTD_OK;
}

/* a — код точки A над токовым проводом; num — RTD_NUM_2W, RTD_NUM_3W или RTD_NUM_4W */
rtd_status_t rtd_read(int32_t a, int32_t num, int32_t *t_centi)
{
    int32_t den = RTD_FS - a;                   /* напряжение на Rref — это ток */
    if (den < RTD_DEN_MIN)
        return RTD_OPEN;                        /* тока нет: оборван токовый провод или датчик */
    int32_t w2 = rtd_w_ppm(a, den);             /* датчик вместе с проводами */
    int32_t w = rtd_w_ppm(num, den);
    if (w2 < RTD_W_SHORT)
        return RTD_SHORT;
    if (w2 - w > RTD_W_LEAD || w - w2 > RTD_W_LEAD)
        return RTD_SENSE;                       /* провода «стали» больше 1 % R0: висит измерительный провод */
    if (w > RTD_W_OPEN)
        return RTD_OPEN;
    return rtd_temp(w, t_centi);
}

Дальше: раздел 177 «Источники опорного напряжения» — чем заменить VDDA и VREFBUF, когда их дрейф съедает бюджет.

Открыть в интерактивном справочнике