Урок 25. Кремниевые термодатчики серии KTY81 в системе Ардино. Проект термометра-регистратора.

Диаграмма температуры

Урок рассказывает об использовании кремниевых датчиков температуры в системе Ардуино. Приводится рабочий проект термометра. Попутно рассматривается вопрос измерения сопротивления в системе Ардуино.

Предыдущий урок     Список уроков     Следующий урок

В предыдущем уроке для измерения температуры мы использовали интегральные датчики, у которых напряжение на выходе пропорционально зависит от температуры. Причем эта зависимость линейная с известным масштабным коэффициентом. Для вычисления температуры достаточно измерить напряжение и разделить его на масштабный коэффициент.

 

Кремниевые термодатчики в зависимости от температуры меняют свое сопротивление. Т.е. это не активные элементы, требующие питания, не интегральные микросхемы, а просто терморезисторы.

Типичными представителями кремниевых датчиков являются термодатчики серии KTY81. Я написал о них большую статью. Там есть параметры, характеристики, схемы включения. Частично я повторю эту информацию.

Достоинства и недостатки термодатчиков серии KTY81.

Датчики такого типа большинство разработчиков просто не замечают. Я, напротив, считаю, что в некоторых приложениях они незаменимы.

На мой взгляд, эти устройства имеют  только один существенный недостаток – нелинейная характеристика и невысокая точность измерения. У лучших вариантов датчиков серии KTY81  нелинейность:

± 3,5 °C в диапазоне температуры до + 100 °C;

± 8,5 °C в диапазоне температуры до + 150 °C.

Но, нелинейность характеристики исправляется программой микроконтроллера. В принципе, можно и откалибровать каждый датчик индивидуально.

Но если такая точность измерения  приемлема, то по остальным характеристикам и эксплуатационным возможностям KTY81 значительно превосходят интегральные термодатчики. А именно:

  • У кремниевых термодатчиков широкий диапазон измеряемых температур  -55 … +150 °C. Интегральные устройства, как правило, работают в диапазоне  -40 … +125 °C, многие до +100 °C. Часто этих лишних 25-50 °C и не хватает, например, при контроле температуры радиаторов мощных полупроводниковых приборов.
  • Для подключения к микроконтроллеру требуется всего два провода, что особенно важно, когда датчики расположены на большом расстоянии от контроллера.
  • Обеспечивается высокая помехоустойчивость за счет двух проводной линии связи, симметричной для помех. Для подключения датчика KTY81 на расстоянии десятков и даже сотен метров достаточно простой витой пары.
  • Высокое сопротивление KTY81 (1000 Ом и 2000 Ом) позволяет пренебречь активным сопротивлением проводов связи.
  • Нет ограничений на работу с емкостной нагрузкой. Это качество позволяет использовать линии связи с большой емкостью и шунтировать термодатчик конденсатором значительной емкости для фильтрации помех. Интегральные термодатчики не работают на емкостную нагрузку более 10 нФ.
  • Устройства не имеют полярности. Сколько полупроводниковых приборов было выведено из строя из-за попутки полярности!
  • Низкая цена. Это одни из самых дешевых датчиков температуры.

Решайте сами, в каких проектах использовать эти датчики. В моих разработках – мощных станциях катодной защиты на каждом радиаторе установлено по термодатчику KTY81/120.

 

Кремниевые термодатчики серии KTY81.

Подробно об этих устройствах можно почитать по ссылке. Сейчас коротко скажу, что:

  • серия включает 10 типов датчиков, отличающихся погрешностью измерения и сопротивлением;
  • у всех устройств рабочий диапазон температуры – 55 … + 150 °C;
  • характеристика (зависимость сопротивления от температуры) задана табличным способом;
  • устройства выполнены в корпусе SOD70 (как TO-92, только два вывода).

KTY81

Для вычисления реальной температуры необходимо выполнить следующие действия:

  • измерить сопротивление термодатчика;
  • используя табличную характеристику вычислить температуру (линеаризовать характеристику).

Измерение активного сопротивления в системе Ардуино.

Прежде всего, необходимо измерить сопротивление термодатчика. АЦП платы Ардуино измеряет напряжение. Значит необходимо преобразовать сопротивление в напряжение. Существует большое количество схем с такой функцией. В нашем случае лучшим вариантом будет простой делитель напряжения.

Схема делителя

Между сигналом питание 5 В и землей подключен делитель напряжения из двух резисторов:

  • Ro – образцовый резистор;
  • Rx – измеряемый резистор.

Напряжение на выходе делителя будет:

Uвых = Uвх * Rx  /  ( Ro + Rx )

Отсюда:

Rx = Ro  /  (Uвх / Uвых   - 1)

Из этой формулы видно основное преимущество такого способа измерения. Нам не важно значение напряжение питания делителя (Uвх), не важна его стабильность, т.к. в формулу входит соотношение Uвх / Uвых. А так как источником опорного напряжение для АЦП служит питание 5 В, то АЦП измеряет именно соотношение Uвх / Uвых. Совершенно не важно, какое там напряжение. Мы даже не будем задавать разрешающую способность АЦП в вольтах. Мы зададим Uвх / Uвых как 1023 / N, где 1023 – максимальное значение кода АЦП, N – код АЦП.

В результате формула вычисления сопротивления будет выглядеть так:

Rx = Ro  /  (1023 / N   - 1),

N – код АЦП.

Точность измерения сопротивления по схеме делителя не зависит от погрешности напряжения питания схемы, а определяется только точностью сопротивления образцового резистора Ro.

Правда, у этой схемы явно нелинейная характеристика и разрешающая способность. Определим ее на конкретном примере.

Если использовать датчик KTY81/120, то надо ориентироваться на следующие параметры:

Минимальное сопротивление при – 55 °C 490 Ом
Максимальное сопротивление при + 150 °C 2211 Ом
Предельно допустимый ток при + 150 °C 2 мА

Выберем образцовый резистор сопротивлением 3300 Ом. Тогда ток при + 150 °C будет равным

5 В / (3300 + 2211) = 0,9 мА.

Для наглядности я построил два графика в Excel. Первый это зависимость сопротивления от кода АЦП.

Характеристика измерителя сопротивления

Видна нелинейность преобразования. Если мы используем датчик KTY81/120, то требуется измерять сопротивление в диапазоне 490 … 2211 Ом. По графику видно, что этот диапазон соответствует коду АЦП примерно 130 … 410. Можно посчитать точнее, но сейчас в этом необходимости нет. У нас примерно 280 единиц дискретности АЦП, что вполне достаточно.

Второй график показывает зависимость сопротивления соответствующего единице дискретности АЦП от кода АЦП. Т.е. он показывает насколько меняется разрешающая способность измерителя сопротивления в рабочем диапазоне.

Характеристика измерителя сопротивления

Видно, что худшее значение разрешения измерителя сопротивления при коде 410, и равно 9 Ом. Это соответствует примерно 1 °C и нас вполне устраивает.

В итоге схема подключения термодатчика KTY81/20 к микроконтроллеру выглядит так.

Схема подключения KTY81
Для дальнейших расчетов определим точные границы рабочего диапазона измерителя сопротивления.

N    =  Rx * 1023 /  ( Ro + Rx )

Граница Сопротивление датчика,
Rx
Код АЦП,
N
Минимальная температура,  – 55 °C 490 Ом 132
Максимальная температура,  + 150 °C 2211 Ом 410

 

Проект Ардуино термометра на датчике температуры KTY81/120.

Разработаем термометр – полный функциональный аналог устройства из предыдущего урока, только с использованием термодатчика KTY81/120. Применение кремневого датчика:

  • расширило диапазон измерения температуры до  – 55 … + 150 °C;
  • позволило размещать датчик на большом расстоянии (до сотен метров) и использовать в качестве линии связи витую пару;
  • снизило точность измерения до :
    • ± 5 °C в диапазоне  – 55 … + 100 °C
    • ± 10 °C в диапазоне  + 100 … + 150 °C.

Точность измерения можно улучшить использованием термодатчиков типа KTY81/110 до:

  • ± 3,5 °C в диапазоне  – 55 … + 100 °C;
  • ± 8,5 °C в диапазоне  + 100 … + 150 °C.

Устройство:

  • отображает значение температуры на LED индикаторе (в автономном режиме);
  • передает значение температуры на компьютер;
  • при использовании программы верхнего уровня из предыдущего урока:
    • отображает текущую температуру на дисплее компьютера;
    • регистрирует изменение температуры с дискретностью по времени 1 сек;
    • отображает изменение температуры в графическом виде.

 

Схема термометра.

К плате Ардуино подключим:

  • 4х разрядный LED индикатор;
  • Датчик температуры KTY81/120.

Все как в предыдущем уроке.

Схема Ардуино термометра с датчиком KTY81/120.

Схема Ардуино термометра

R1 – образцовый резистор. C1 – фильтрует высокочастотные помехи, можно его увеличить до 1 мкФ. Применение электролитических конденсаторов нежелательно. У них большой ток утечки. Датчик лучше подключить к контроллеру витой парой.

На макетной плате устройство выглядит так.

Ардуино термометр

Резидентная программа Ардуино термометра.

Программа должна:

  • считывать значение АЦП;
  • усреднять коды АЦП для повышения помехозащищенности;
  • вычислять температуру, используя табличную характеристику датчика KTY81/120;
  • отображать значение температуры на LED индикаторе  в формате:
    • знак;
    • сотни;
    • десятки;
    • единицы °C;
  • передавать значение температуры раз в секунду на компьютер.

Программа большей частью аналогична программе из предыдущего урока. Изменения коснулись только принципа вычисления температуры.

Скетч программы термометра.

// термометр, датчик KTY81/120
#include <MsTimer2.h>
#include <Led4Digits.h>

#define MEASURE_PERIOD 500  // время измерения, * 2 мс
#define RO  3300  // сопротивление образцового резистора, Ом
#define MIN_ADC 132 // минимальное значение рабочего диапазона АЦП
#define MAX_ADC 410 // максимальное значение рабочего диапазона АЦП
#define POL_NUM 24  // число полюсов характеристики

int sensTable[POL_NUM][2] = {  // таблица характеристики датчика
  {-55, 490}, {-50, 515}, {-40, 567}, {-30, 624}, {-20, 684}, {-10, 747},
  {0, 815}, {10, 886}, {20, 961}, {25, 1000}, {30,1040}, {40, 1122},
  {50, 1209}, {60, 1299}, {70, 1392}, {80, 1490}, {90, 1591}, {100, 1696},
  {110, 1805}, {120, 1915}, {125, 1970}, {130, 2023}, {140, 2124}, {150, 2211}
};

int codToTempTable[MAX_ADC - MIN_ADC +1];  // таблица преобразования код в температуру

int timeCount;     // счетчик времени измерения
long  sumA0;       // переменная суммирования кодов АЦП
long  avarageTemp; // среднее значение температуры (сумма кодов АЦП, среднее значение * 500)
boolean flagTempReady;  // признак готовности измерения температуры
int temperature;  // рассчитанная температура, °C

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

void setup() {
  MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
  MsTimer2::start();               // разрешаем прерывание по таймеру
  Serial.begin(9600); // инициализируем порт, скорость 9600 

  //--------- предварительный расчет значений температуры -------------
  // вычисление массива codToTempTable[]
  int codBeginPol=0;  // код полюса начала отрезка
  int codEndPol;  // код полюса конца отрезка
  float koeff;  // коэффициент для отрезка между полюсами

  // цикл перебора полюсов
  for ( int p= 0; p < (POL_NUM-1); p++ ) {

    // вычисление кода для следующего полюса N= Rx * 1023 / (Ro + Rx)
    codEndPol = (int)(((float)sensTable[p+1][1] * 1023.) / (RO + (float)sensTable[p+1][1]) + 0.5) - MIN_ADC ;               
    codToTempTable[codEndPol] = sensTable[p+1][0];  // температура для следующего полюса

    // вычисление коэффициента для отрезка
    koeff = (float)(sensTable[p+1][0] - sensTable[p][0]) / (float)(codEndPol - codBeginPol);

    // интерполяция температуры
    for ( int n = codBeginPol; n < codEndPol; n++ ) {
      codToTempTable[n]= sensTable[p][0] + (int)((float)(n - codBeginPol) * koeff +0.5 );
    }
    codBeginPol=codEndPol;   
  }   
}

void loop() { 

  if ( flagTempReady == true ) {
    flagTempReady= false;
    // данные готовы

    // вычисление температуры
    temperature = (int)((float)avarageTemp / 500. + 0.5);

    // проверка диапазона
    if (temperature < MIN_ADC) temperature= MIN_ADC;
    if (temperature > MAX_ADC) temperature= MAX_ADC;

    // выборка готового значения из массива
    temperature= codToTempTable[temperature - MIN_ADC];
   
    // вывод температуры на индикатор
    if (temperature >= 0) {
      // температура положительная
      disp.digit[3]= 0; // минус не светится
      disp.print((int)(temperature), 3, 1);  
    }
    else {
      // температура отрицательная
      disp.digit[3]= 0x40;  // отображается минус
      disp.print((int)(temperature * -1), 3, 1);        
    }
           
    // передача температуры на компьютер
    Serial.println(temperature);   
    }       
}

//-------------------------------------- обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора

  // измерение среднего значения темпрературы
  timeCount++;  // +1 счетчик выборок усреднения
  sumA0+= analogRead(A0);  // суммирование кодов канала A0 АЦП

  // проверка числа выборок усреднения
  if ( timeCount >= MEASURE_PERIOD ) {
    timeCount= 0;
    avarageTemp= sumA0; // перегрузка среднего значения
    sumA0= 0;
    flagTempReady= true;  // признак готовности результата
    } 
}

Загрузить скетч программы Ардуино термометр можно по ссылке:

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!

Должны быть подключены библиотеки Led4Digits.h  и MsTimer2.h. Загрузить библиотеки можно из урока 20 и урока 10.

Вычисление температуры по характеристике датчика , заданной таблицей.

Итак, у нас есть таблица зависимости сопротивления датчика от температуры. Она взята из материалов по этой ссылке.

Температура, °C Сопротивление, Ом
-55 490
-50 515
-40 567
-30 624
-20 684
-10 747
0 815
10 886
20 961
25 1000
30 1040
40 1122
50 1209
60 1299
70 1392
80 1490
90 1591
100 1696
110 1805
120 1915
125 1970
130 2023
140 2124
150 2211

Зависимость задана в виде 24 точек (полюсов) с разным шагом 5 или 10 °C.  Нам надо из кода АЦП вычислить температуру. Для вычисления значений между полюсами характеристики следует использовать линейную интерполяцию, т.е. соединить точки отрезками прямой.

В графическом виде интерполированная характеристика датчика KTY81/120 выглядит так.

Характеристика KTY81/120

Для вычисления температуры можно сделать следующую последовательность действий:

  • считать код АЦП;
  • вычислить сопротивление;
  • перебрать полюса характеристики и определить, в какой отрезок попадает измеренное сопротивление;
  • по линейной зависимости между полюсами более точно вычислить температуру.

Но такой способ очень сложный и медленный. Сделаем другим способом – заранее рассчитаем значения температуры для каждого значения АЦП.

В разделе об измерении сопротивления мы вычислили, что рабочий диапазон датчика в кодах АЦП 132 … 410, т.е. 279 значений. Нам надо рассчитать соответствие температуры каждому коду в этом диапазоне (132 … 410).

Предварительный расчет значений температуры происходит один раз, при запуске программы в функции setup(). В результате формируется массив

int codToTempTable[MAX_ADC - MIN_ADC +1];  // таблица преобразования код в температуру

Теперь для вычисления измеренной температуры достаточно считать значение температуры из этого массива по адресу – коду АЦП.

// выборка готового значения из массива    
temperature= codToTempTable[temperature - MIN_ADC];

Простая, быстрая операция.

Лучший вариант рассчитать массив codToTempTable[] заранее программой верхнего уровня и использовать его, как инициализированный массив с модификатором const. Тогда в программе Ардуино предварительных расчетов для температуры вообще не будет. Но я предпочел рассчитать его в программе микроконтроллера для наглядности.

Несколько слов об отладке программы. Вычисления довольно сложные, легко совершить ошибку. Поэтому я сделал две проверки:

  • При формировании массива codToTempTable[] через последовательный порт я вывел на компьютер таблицу со значениями код, полюс, коэффициент, температура. Значение температуры в полюсах сравнил с табличными и убедился, что между полюсами значения монотонные и примерно равномерные.
  • В программе временно отключил АЦП и задал имитацию изменения кода на единицу раз в секунду. С помощью регистратора программы Thermometer убедился, что изменение значения температуры монотонное.

 

Работа Ардуино термометра-регистратора в составе с компьютером.

В автономном режиме термометр отображает значение температуры на LED индикаторах. При подключении к устройству компьютера можно наблюдать измеренную температуру  с помощью монитора последовательного порта Arduino IDE или программы верхнего уровня Thermometer.

Окно программы верхнего уровня

Это программа из предыдущего урока. Загрузить ее можно по этой ссылке:

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!

В уроке подробно рассказано об установке и работе с программой Thermometer.

Напомню, что программа, кроме индикации температуры, выполняет функцию регистратора температуры с временной дискретностью 1 секунда.

Диаграмма температуры

Диаграмма температуры

Описанный принцип измерения температуры с помощью кремниевых датчиков KTY81/120 вполне применим для других типов датчиков с нелинейным сопротивлением.

 

В следующем уроке научимся работать с датчиком температуры DS18B20, разработаем термометр с этим датчиком.

Предыдущий урок     Список уроков     Следующий урок

3

Автор публикации

не в сети 10 часов

Эдуард

285
Комментарии: 1946Публикации: 199Регистрация: 13-12-2015

23 комментария на «Урок 25. Кремниевые термодатчики серии KTY81 в системе Ардино. Проект термометра-регистратора.»

  1. Спасибо Вам за уроки, очень познавательно.
    Я использую 3х разрядный 7 сегментный led индикатор. Интересует как зажечь точку и указать десятые доли температуры?

    0
    • Спасибо.
      Принцип вывода дробных значений на индикатор описывается в уроке 20. И есть примеры в уроках 24 и 26.

      0
      • Точку я зажег, но теперь в десятых всегда горит 0, как понимаю округление до целых?

        0
        • А откуда дробная часть появится, если программа для этого датчика вычисляет в целых. В уроках 24 и 26 температура вычисляется в формате с дробной частью. Там дробная часть и отображается.

          0
          • Значит дробную часть не вывести с этим датчиком?

            0
          • Можно вывести. Но нужны другие вычисления и для этого датчика практически не имеет смысла. У него невысокая точность и дробная часть практической информации иметь не будет. Посмотрите урок 26. Там датчик точный и термометр показывает дробную часть.
            Павел, если Вас какой-нибудь вопрос интересует подробно, открывайте тему на форуме сайта. Это просто.

            0
  2. (повторный комент, кратко)
    Очень хорсшо изложены уроки, много для себя нашел полезного, спасибо
    Проще, по моему, таррировку датчика поместить в Эксель, построить график, на нем добавить линию тренда, а формулу тренда прямо в ЛООП.
    Это как альтернатива при практической реализации, так как выше точность, значительно меньше код, что важно для больших программ

    0
  3. Добрый день, спасибо за уроки.
    Необходимо упомянуть ещё об одном существенном недостатке терморезисторов — внесение погрешности измерительным током (происходит доп. нагрев терморезистора от рассеиваемой им мощности). При выбранных вами номиналах это ощутимо. Обычно выход — выбор номиналов в сотни кОм, но это ухудшает помехозащищённость, особенно актуально при длинных шлейфах.

    0
  4. Спасибо за урок! Очень помог в моём проекте, но я пошёл другим путём в пересчёте сопротивления в температуру, сэкономив в 5 раз больше оперативной памяти (всего 9%).

    0
  5. Эдуард, здравствуйте! При компиляции скетча_25 появляется ошибка: error: size of array ‘codToTempTable’ has non-integral type ‘double’ на строке: int codToTempTable[MAX_ADC — MIN_ADC + 1]; Не получается справиться … Не подскажете, в чём может быть ошибка? Написание программы проверял несколько раз.

    0
  6. Извините, Эдуард, я только начинаю осваивать программирование, не подскажете точнее где поставить число 279? Я по разному подставлял в эту строку — int codToTempTable[MAX_ADC — MIN_ADC + 1]; , но никак… Странно, что у всех программа работает, судя по комментариям???…

    0
  7. Здравствуйте Эдуард!

    Можно использовать датчик Рт 100 вместо датчика КТУ81?
    Спасибо Вам за Ваши уроки.

    0
    • Здравствуйте!
      Насколько я помню, у PT100 линейная характеристика. Нет необходимости табличного способа линеаризации. Проще сделать делитель из датчика и резистора, и вычислять температуру по формуле линейной зависимости.

      0
  8. Здравствуйте Эдуард!

    У меня к Вам пару вопросов.
    Я изменил Ваш код и подключил ЖК-экран вместо LED индикаторов. Температуру показывает
    к примеру 24.45 гр. Вопрос №1. Как избавиться от двух последних символов после запятой?
    С помощью энкодера регулирую яркость СИДа с выводом показании (строка disp.print(LED); //регулируем яркость СИДа) на ЖК-экран.
    С максимальной яркости вращаю энкодер к минимуму переходя значения со 100 на 99 и соответственно с 10 на 9 остаются нули. Вопрос № 2. Как от этих нулей избавиться? Это надо обновлять экран, но как это делать (строка disp.clear();)?! В таком случае экран мецает

    {…..
    LED=encoder.position; //перегружаем «щелчки» энкодера в СИД
    disp.setCursor(6,1); //устанавливаем курсор на 6й символ второй строки
    disp.print(LED); //регулируем яркость СИДа
    disp.clear(); // очищаем экран ????????

    Подскажите пожалуйста.
    Спасибо.

    0
    • Здравствуйте!
      disp.print(temp, 0); — второй аргумент это число цифр после запятой. По умолчанию 2 цифры. Используется только с числами типа с плавающей запятой.
      Установите курсор в начальную позицию и перепишите всю строку. Пустые знакоместа заполните пробелами.
      disp.print(LED); //регулируем яркость СИДа
      disp.print(» «);
      Если что-то упустил — переспросите.

      0
      • Ваша подсказка на первый мой вопрос помогла.

        А вот со вторым я не понял disp.print(» «); ?
        таких кавычек на клавиатуре не обнаружил.
        Повторите, объясните только более развернуто.
        Спасибо.

        0
        • Здравствуйте!
          У вас печатается, например, 3х разрядное число, а затем поверх него 2х разрядное. А третий разряд остается от предыдущего числа. Надо его стереть пробелом. Т.е. напечатать пробел.
          Как вариант, можете стирать пробелами все поле, предназначенное для числа, а затем его выводить.
          А кавычки в функции обычные. В поле комментариев WordPress заменяет кавычки на другие.

          0
  9. Здравствуйте! Подскажите, будет ли работать по описанной здесь схеме работать датчик 0-90 Ом? Какой величины лучше взять Ro для такой схемы?

    0
    • Здравствуйте!
      Возможно, работать будет, но надо сделать доработки. Такой низкоомный датчик лучше записать от более низкого напряжения 1 В. Иначе через него будет протекать слишком большой ток. Соответственно необходимо переключить АЦП на входное напряжение 1.1 В.
      В идеале напряжение на датчике надо сформировать из ИОН микроконтроллера. Сделать повторитель на ОУ.
      Если у вас датчик линейный, то нет необходимости в табличной линеаризации его характеристики.

      0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".