Урок 1.8. Термистор. Делитель напряжения. Термометр со световой индикацией температуры

Базовый курс "Программирование микроконтроллеров"
Модуль 1. Введение в Arduino. Работа с цифровым и аналоговым сигналом

Терморезистор NTC 100K

Терморезистор (или термистор) — это такой резистор, который меняет свое электрическое сопротивление в зависимости от температуры.

Существует два вида термисторов: 

PTC (Positive Temperature Coefficient) — с положительным температурным коэффициентом: их сопротивление растёт при повышении температуры.

NTC (Negative Temperature Coefficient) — с отрицательным температурным коэффициентом: их сопротивление уменьшается при повышении температуры.

Также термисторы отличаются номинальным сопротивлением, которое соответствует комнатной температуре — 25 C°. Например, популярными являются термисторы с номиналом 100 кОм и 10 кОм. Такие термисторы часто используют в 3D-принтерах.

В этом уроке мы будет использовать термистор NTC 100K в стеклянном корпусе.

Делитель напряжения. Схема проекта

Соберем проект световой индикации температуры по схеме:

Как Вы можете заметить, последовательно термистору стоит резистор, наверняка многие из Вас спросят зачем он нужен?

Делитель напряжения — устройство, в котором входное U_{in} и выходное U_{out} напряжения связаны коэффициентом передачи.

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

Эта несложная схема делит (отсюда и название — делитель) напряжение, приложенное к контактам на его входе на части пропорционально отношению сопротивлений R_1 и R_2. Найдём это отношение.

Обратите внимание: важно знать, что сопротивление нагрузки на выходе делителя должно быть много больше сопротивлений R_1 и R_2. Соответственно, и ток, текущий через эту нагрузку должен быть много меньше тока на самом делителе. Именно по этой причине нерационально использовать делитель для питания устройств.

Вспомним, что:

Сила тока в последовательно соединенных участках цепи одинакова: I_1=I_2;
– Общее сопротивление последовательно соединенных резисторов равняется их сумме: R_{общ} = R_1 + R_2.

Согласно закону Ома:

R_{общ} = \frac{U_{вх}}{I_{общ}}

Таким образом ток протекающей в схеме будет равен:

I = \frac{U_{вх}}{R_{общ}}=\frac{U_{вх}}{R_1+R_2}

Напряжение на R_2, по закону Ома, равно:

U_2= I{R_2}=\frac{R_2}{R_1+R_2}U_{вх}

Таким образом мы по сути снижаем напряжение на термисторе, делая его более “чувствительным” к АЦП Ардуино.

Представим, что нам нужно питать ту же плату Arduino Uno с несколькими светодиодами от аккумулятора с напряжением 12 Вольт. Для работы подобной схемы потребуется ток около 150 мА. Сопротивление такой нагрузки можно грубо посчитать как R_Н = \frac{U}{I}=\frac{5B}{0.15A}=33,3  Ом.

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

Программа вычисления сопротивления термистора в Омах

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

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

Общее напряжение является суммой напряжений на двух участках цепи

U_{общ}=U_1+U_2

Согласно закону Ома: U = RI

Подставим  это в первое уравнение и получим:

U_{общ}=R_1I+R_2I

Обратите внимание на то, что сила тока протекающего через оба резистора одинакова.

Из закона Ома сила тока равна:

I = \frac{U_2}{R_2}

Подставим в предыдущее уравнение и получим:

U_{общ}= \frac{R_1U_2}{R_2} +\frac{R_2U_2}{R_2}=U_2(\frac{R_1}{R_2}+1)

Выразим отсюда R_1:

U_{общ}=U_2(\frac{R_1}{R_2}+1) \Rightarrow \frac{U_{общ}}{U_2}=\frac{R_1}{R_2}+1 \Rightarrow \frac{U_{общ}}{U_2}-1=\frac{R_1}{R_2} \Rightarrow R_2=\frac{R_1}{ \frac{U_{общ}}{U_2}-1}

Обратите внимание: в этой формуле U_2  - это показания АЦП, считанные командой analogRead, а {U_{общ}} - это максимальное значение АЦП, т.е. 1023.

Таким образом итоговая формула будет иметь вид: R_2=\frac{R_1}{\frac{1023}{АЦП}-1}

Напишем следующую программу:

#define SERIAL_R 100000          // сопротивление последовательного резистора, 100 кОм

const byte tempPin = A0;

void setup() {
    Serial.begin(9600);
    pinMode(tempPin, INPUT);
}

void loop() {
    int t = analogRead( tempPin );
    float term_r = 1023.0 / t - 1;
    term_r = SERIAL_R / term_r;
    Serial.println(term_r);
    delay(100);
}

Откроем монитор порта и посмотрим на измеренное значения сопротивления:

Программа вычисления сопротивления термистора в градусах Цельсия

Наш следующий шаг — вычисление температуры в градусах Цельсия. Чтобы вычислить значение температуры используют формулу Стейнхарта — Харта:

\frac{1}{T} =A+B\cdot ln(R) +C(ln(R))^3

Уравнение имеет параметры A, B и C, которые нужно брать из спецификации к датчику. Так как нам не требуется большой точности, можно воспользоваться модифицированным уравнением (B-уравнением):

\frac{1}{T} =\frac{1}{T_0}+\frac{1}{B}ln(\frac{R}{R_0})

В этом уравнении неизвестным остается только параметр B, который для NTC-термистора равен 3950. Остальные параметры нам уже известны:

T_0 — комнатная температура в Кельвинах, для которой указывается номинал термистора, T_0 = 25 + 273.15;

T — искомая температура, в Кельвинах;

R — измеренное сопротивление термистора в Омах;

R_0 — номинальное сопротивление термистора в Омах.

Модифицируем программу для Ардуино, добавив расчет температуры:

#define B 3950                              // B-коэффициент
#define SERIAL_R 100000                     // сопротивление последовательного резистора, 100 кОм
#define THERMISTOR_R 100000                 // номинальное сопротивления термистора, 100 кОм
#define NOMINAL_T 25                        // номинальная температура (при которой TR = 100 кОм)

const byte tempPin = A0;

void setup() {
  Serial.begin(9600);
  pinMode(tempPin, INPUT);
}

void loop() {
  int t = analogRead(tempPin);
  float term_r = 1023.0 / t - 1;
  term_r = SERIAL_R / term_r;
  Serial.print("R=");
  Serial.print(term_r);
  Serial.print(", t=");

  float steinhart;
  steinhart = term_r / THERMISTOR_R;        // (R/Ro)
  steinhart = log(steinhart);               // ln(R/Ro)
  steinhart /= B;                           // 1/B * ln(R/Ro)
  steinhart += 1.0 / (NOMINAL_T + 273.15);  // + (1/To)
  steinhart = 1.0 / steinhart;              // Invert
  steinhart -= 273.15;
  Serial.println(steinhart);

  delay(100);
}

Остаётся добавить световую индикацию:

#define B 3950                              // B-коэффициент
#define SERIAL_R 100000                     // сопротивление последовательного резистора, 100 кОм
#define THERMISTOR_R 100000                 // номинальное сопротивления термистора, 100 кОм
#define NOMINAL_T 25                        // номинальная температура (при которой TR = 100 кОм)

const byte tempPin = A0;
const byte red_led = 5;
const byte blue_led = 6;

void setup() {
  Serial.begin(9600);
  pinMode(tempPin, INPUT);
  pinMode(red_led, OUTPUT);
  pinMode(blue_led, OUTPUT);
}

void loop() {
  int t = analogRead(tempPin);
  float term_r = 1023.0 / t - 1;
  term_r = SERIAL_R / term_r;
  Serial.print("R=");
  Serial.print(term_r);
  Serial.print(", t=");

  float steinhart;
  steinhart = term_r / THERMISTOR_R;        // (R/Ro)
  steinhart = log(steinhart);               // ln(R/Ro)
  steinhart /= B;                           // 1/B * ln(R/Ro)
  steinhart += 1.0 / (NOMINAL_T + 273.15);  // + (1/To)
  steinhart = 1.0 / steinhart;              // Invert
  steinhart -= 273.15;
  Serial.println(steinhart);
  int x;
  steinhart = constrain(steinhart, 20, 40);
  x = map(steinhart, 20, 40, 0, 255);
  analogWrite(red_led, 255 - x);
  analogWrite(blue_led, x);
}